@datagrok/helm 2.2.1 → 2.3.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/package-test.js +1 -1
  3. package/dist/package-test.js.map +1 -1
  4. package/dist/package.js +1 -1
  5. package/dist/package.js.map +1 -1
  6. package/files/tests/helm2-bracket.csv +2 -0
  7. package/package.json +13 -10
  8. package/src/cell-renderer.ts +8 -33
  9. package/src/helm-helper.ts +67 -17
  10. package/src/helm-monomer-placer.ts +7 -9
  11. package/src/helm-web-editor.ts +33 -3
  12. package/src/package-test.ts +8 -3
  13. package/src/package-utils.ts +69 -42
  14. package/src/package.ts +121 -141
  15. package/src/tests/findMonomers-tests.ts +2 -0
  16. package/src/tests/get-all-parts-tests.ts +5 -0
  17. package/src/tests/get-molfiles-tests.ts +3 -1
  18. package/src/tests/get-monomer-tests.ts +88 -19
  19. package/src/tests/helm-service-tests.ts +4 -0
  20. package/src/tests/helm-tests.ts +7 -1
  21. package/src/tests/helm-web-editor-tests.ts +55 -0
  22. package/src/tests/parse-helm-tests.ts +98 -0
  23. package/src/tests/properties-widget-tests.ts +33 -4
  24. package/src/tests/renderers-tests.ts +3 -1
  25. package/src/tests/utils.ts +6 -0
  26. package/src/types/index.ts +5 -0
  27. package/src/utils/get-hovered.ts +3 -4
  28. package/src/utils/{dummy-monomer.ts → get-monomer-dummy.ts} +10 -45
  29. package/src/utils/get-monomer-of-library.ts +90 -0
  30. package/src/utils/get-monomer.ts +23 -21
  31. package/src/utils/helm-grid-cell-renderer.ts +19 -3
  32. package/src/utils/helm-service.ts +6 -5
  33. package/src/utils/index.ts +11 -17
  34. package/src/widgets/properties-widget.ts +29 -9
  35. package/tsconfig.json +1 -1
  36. package/vendor/helm-web-editor.development.js +39640 -0
  37. package/vendor/helm-web-editor.production.js +2 -0
  38. package/vendor/helm-web-editor.production.js.map +1 -0
  39. package/webpack.config.js +15 -12
  40. package/helm/JSDraw/Pistoia.HELM.js +0 -27
  41. package/helm/JSDraw/Scilligence.JSDraw2.Lite.js +0 -12
  42. package/helm/JSDraw/Scilligence.JSDraw2.Resources.js +0 -762
  43. package/helm/JSDraw/dojo.js +0 -250
  44. package/helm/JSDraw/test.html +0 -24
@@ -0,0 +1,55 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {after, before, category, delay, expect, test, expectArray} from '@datagrok-libraries/utils/src/test';
6
+ import {IHelmHelper, getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
7
+ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
+ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
9
+ import {
10
+ getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
11
+ } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
12
+
13
+ import {initHelmMainPackage} from './utils';
14
+
15
+ category('helm-web-editor', async () => {
16
+ let monomerLibHelper: IMonomerLibHelper;
17
+ let userLibSettings: UserLibSettings;
18
+
19
+ let hh: IHelmHelper;
20
+
21
+ before(async () => {
22
+ await initHelmMainPackage();
23
+ monomerLibHelper = await getMonomerLibHelper();
24
+ userLibSettings = await getUserLibSettings();
25
+ await setUserLibSettingsForTests();
26
+ await monomerLibHelper.awaitLoaded();
27
+ await monomerLibHelper.loadLibraries(true);
28
+
29
+ hh = await getHelmHelper();
30
+ });
31
+
32
+ after(async () => {
33
+ await setUserLibSettings(userLibSettings);
34
+ await monomerLibHelper.loadLibraries(true);
35
+ });
36
+
37
+ test('helm-web-editor', async () => {
38
+ const editor = hh.createHelmWebEditor();
39
+ });
40
+
41
+ test('web-editor-app', async () => {
42
+ const helmStr: string = 'PEPTIDE1{I.H.A.N.T.Thr_PO3H2.Aca.D-Tyr_Et}$$$$';
43
+
44
+ const appHost = ui.div([],
45
+ {style: {width: '700px', height: '432px'}});
46
+ const app = hh.createWebEditorApp(appHost, helmStr);
47
+
48
+ const dlg = ui.dialog().add(appHost).show();
49
+ try {
50
+
51
+ } finally {
52
+ dlg.close();
53
+ }
54
+ });
55
+ });
@@ -0,0 +1,98 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+
6
+ import {after, before, category, delay, expect, test, expectArray, timeout} from '@datagrok-libraries/utils/src/test';
7
+ import {HelmType, Mol, OrgType} from '@datagrok-libraries/bio/src/helm/types';
8
+ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
9
+ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
10
+ import {
11
+ getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
12
+ } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
13
+
14
+ import {JSDraw2HelmModule} from '../types';
15
+ import {initHelmMainPackage} from './utils';
16
+
17
+ declare const org: OrgType;
18
+ declare const JSDraw2: JSDraw2HelmModule;
19
+
20
+ type TestTgtType = { atomCount: number, bondCount: number };
21
+
22
+ category('parseHelm', () => {
23
+ const testData: { [testName: string]: { src: string, tgt: TestTgtType } } = {
24
+ 'PT': {
25
+ src: 'PEPTIDE1{[L-hArg(Et,Et)].E.F.G}|PEPTIDE2{C.E}$PEPTIDE1,PEPTIDE2,2:R3-1:R1$$$V2.0',
26
+ tgt: {atomCount: 6, bondCount: 5}
27
+ },
28
+ 'RNA': {
29
+ src: 'RNA1{[dhp]([m1A])p.r(T)p.r(T)p.r(G)p}$$$$V2.0',
30
+ tgt: {atomCount: 12, bondCount: 11}
31
+ }
32
+ };
33
+
34
+ let libHelper: IMonomerLibHelper;
35
+ /** Backup actual user's monomer libraries settings */
36
+ let userLibSettings: UserLibSettings;
37
+
38
+ before(async () => {
39
+ await initHelmMainPackage();
40
+
41
+ libHelper = await getMonomerLibHelper();
42
+
43
+ await timeout(async () => { userLibSettings = await getUserLibSettings(); }, 5000,
44
+ 'get user lib settings for backup');
45
+
46
+ // parseHelm is dependent on monomers RGroups available, test requires default monomer library
47
+ await setUserLibSettingsForTests();
48
+ await timeout(async () => { await libHelper.awaitLoaded(); }, 5000,
49
+ 'await monomerLib to be loaded');
50
+ await libHelper.loadLibraries(true);
51
+ });
52
+
53
+ after(async () => {
54
+ await setUserLibSettings(userLibSettings);
55
+ await libHelper.loadLibraries(true);
56
+ });
57
+
58
+ for (const [testName, {src, tgt}] of Object.entries(testData)) {
59
+ test(`Editor-${testName}`, async () => {
60
+ _testParseHelmWithEditor(src, tgt);
61
+ });
62
+ }
63
+
64
+ for (const [testName, {src, tgt}] of Object.entries(testData)) {
65
+ test(`woDOM-${testName}`, async () => {
66
+ _testParseHelmWithoutDOM(src, tgt);
67
+ });
68
+ }
69
+ });
70
+
71
+ function _testParseHelmWithEditor(src: string, tgt: TestTgtType): void {
72
+ const io = org.helm.webeditor.IO;
73
+
74
+ const editorHost = ui.div();
75
+ const editor = new JSDraw2.Editor(editorHost, {viewonly: true});
76
+
77
+ const plugin = new org.helm.webeditor.Plugin(editor);
78
+ const origin = new JSDraw2.Point(0, 0);
79
+ io.parseHelm(plugin, src, origin, null);
80
+
81
+ const m: Mol<HelmType> = plugin.jsd.m;
82
+ expect(m.atoms.length, tgt.atomCount);
83
+ expect(m.bonds.length, tgt.bondCount);
84
+ }
85
+
86
+ function _testParseHelmWithoutDOM(src: string, tgt: TestTgtType): void {
87
+ const io = org.helm.webeditor.IO;
88
+
89
+ const molHandler = new JSDraw2.MolHandler();
90
+
91
+ const plugin = new org.helm.webeditor.Plugin(molHandler);
92
+ const origin = new JSDraw2.Point(0, 0);
93
+ io.parseHelm(plugin, src, origin, null);
94
+
95
+ const m: Mol<HelmType> = plugin.jsd.m;
96
+ expect(m.atoms.length, tgt.atomCount);
97
+ expect(m.bonds.length, tgt.bondCount);
98
+ }
@@ -2,15 +2,17 @@ import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import * as grok from 'datagrok-api/grok';
4
4
 
5
- import {after, before, category, expect, expectObject, test} from '@datagrok-libraries/utils/src/test';
5
+ import {after, before, category, expect, expectObject, test, timeout} from '@datagrok-libraries/utils/src/test';
6
6
  import {ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
7
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
8
8
  import {
9
9
  getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
10
10
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
11
11
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
12
+ import {generateLongSequence} from '@datagrok-libraries/bio/src/utils/generator';
12
13
 
13
- import {getPropertiesDict} from '../widgets/properties-widget';
14
+ import {initHelmMainPackage} from './utils';
15
+ import {getPropertiesDict, SeqPropertiesError} from '../widgets/properties-widget';
14
16
 
15
17
  const enum MolProps {
16
18
  formula = 'formula',
@@ -25,6 +27,7 @@ const enum Tests {
25
27
  separatorGaps = 'separator-gaps',
26
28
  fastaPt = 'fasta-PT',
27
29
  fastaPtMsa = 'fasta-PT-MSA',
30
+ fastaRna = 'fasta-RNA',
28
31
  fastaDna = 'fasta-DNA',
29
32
  }
30
33
 
@@ -56,6 +59,11 @@ const TestsData: {
56
59
  units: NOTATION.FASTA, alphabet: ALPHABET.PT,
57
60
  res: {[MolProps.formula]: 'C38H58N10O12S', [MolProps.mw]: 878.99, [MolProps.extinctCoef]: 1.55}
58
61
  },
62
+ [Tests.fastaRna]: {
63
+ seq: 'ACGUAUUCC',
64
+ units: NOTATION.FASTA, alphabet: ALPHABET.RNA,
65
+ res: {[MolProps.formula]: 'C84H107N30O65P9', [MolProps.mw]: 2855.67, [MolProps.extinctCoef]: 96.27}
66
+ },
59
67
  [Tests.fastaDna]: {
60
68
  seq: 'ACGTATTCC',
61
69
  units: NOTATION.FASTA, alphabet: ALPHABET.DNA,
@@ -69,9 +77,14 @@ category('properties-widget', () => {
69
77
  let userLibSettings: any = null;
70
78
 
71
79
  before(async () => {
80
+ await initHelmMainPackage();
81
+
72
82
  monomerLibHelper = await getMonomerLibHelper();
73
83
  userLibSettings = getUserLibSettings();
84
+
74
85
  await setUserLibSettingsForTests();
86
+ await timeout(async () => { await monomerLibHelper.awaitLoaded(); },
87
+ 5000, 'MonomerLibHelper.awaitLoaded() timeout');
75
88
  await monomerLibHelper.loadLibraries(true); // load default libraries
76
89
  });
77
90
 
@@ -85,6 +98,22 @@ category('properties-widget', () => {
85
98
  testPropertiesDict(testData.seq, testData.units, testData.separator, testData.alphabet, testData.res);
86
99
  });
87
100
  }
101
+
102
+ test('too-long', async () => {
103
+ const colList = generateLongSequence();
104
+ const df = DG.DataFrame.fromColumns(colList);
105
+ const col = df.getCol('MSA');
106
+
107
+ const sh = SeqHandler.forColumn(col);
108
+ let errCatched = true;
109
+ try {
110
+ const _actPropDict = getPropertiesDict(col.get(0), sh);
111
+ const k = 11;
112
+ } catch (err: any) {
113
+ if (err instanceof SeqPropertiesError) errCatched = true;
114
+ }
115
+ expect(errCatched, true);
116
+ });
88
117
  });
89
118
 
90
119
  function testPropertiesDict(
@@ -95,7 +124,7 @@ function testPropertiesDict(
95
124
  col.setTag(DG.TAGS.UNITS, units);
96
125
  if (separator) col.setTag(bioTAGS.separator, separator);
97
126
  if (alphabet) col.setTag(bioTAGS.alphabet, alphabet);
98
- const uh = SeqHandler.forColumn(col);
99
- const actPropDict = getPropertiesDict(seq, uh);
127
+ const sh = SeqHandler.forColumn(col);
128
+ const actPropDict = getPropertiesDict(seq, sh);
100
129
  expectObject(actPropDict, expPropDict);
101
130
  }
@@ -15,7 +15,7 @@ import {
15
15
  getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
16
16
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
17
17
 
18
- import {awaitGrid} from './utils';
18
+ import {awaitGrid, initHelmMainPackage} from './utils';
19
19
  import {TAGS as helmTAGS} from '../constants';
20
20
 
21
21
  import {_package} from '../package-test';
@@ -26,6 +26,8 @@ category('renderers', () => {
26
26
  let userLibSettings: UserLibSettings;
27
27
 
28
28
  before(async () => {
29
+ await initHelmMainPackage();
30
+
29
31
  monomerLibHelper = await getMonomerLibHelper();
30
32
  userLibSettings = await getUserLibSettings();
31
33
 
@@ -3,6 +3,12 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
6
+ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
7
+
8
+
9
+ export async function initHelmMainPackage(): Promise<void> {
10
+ await getHelmHelper();
11
+ }
6
12
 
7
13
  export async function awaitGrid(grid: DG.Grid, timeout: number = 5000): Promise<void> {
8
14
  await delay(100);
@@ -0,0 +1,5 @@
1
+ import {HelmType, JSDraw2ModuleType, OrgType, ScilModuleType} from '@datagrok-libraries/bio/src/helm/types';
2
+
3
+ export type ScilModule = ScilModuleType;
4
+ export type JSDraw2HelmModule = JSDraw2ModuleType<HelmType>;
5
+ export type OrgHelmModule = OrgType;
@@ -2,15 +2,14 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
 
5
- import * as JSDraw2 from 'JSDraw2';
5
+ import {HelmType, PolymerType, Atom, Mol} from '@datagrok-libraries/bio/src/helm/types';
6
6
 
7
7
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
8
- import {PolymerType} from '@datagrok-libraries/bio/src/types';
9
8
 
10
9
  import {HelmMonomerPlacer, ISeqMonomer} from '../helm-monomer-placer';
11
10
 
12
11
  export function getHoveredMonomerFromEditorMol(
13
- argsX: number, argsY: number, gridCell: DG.GridCell, mol: JSDraw2.IEditorMol
12
+ argsX: number, argsY: number, gridCell: DG.GridCell, mol: Mol<HelmType>
14
13
  ): ISeqMonomer | null {
15
14
  let hoveredSeqMonomer: ISeqMonomer | null = null;
16
15
 
@@ -84,7 +83,7 @@ export function getHoveredMonomerFallback(
84
83
  return hoveredSeqMonomer;
85
84
  }
86
85
 
87
- function getSeqMonomerFromHelmAtom(atom: JSDraw2.IEditorMolAtom): ISeqMonomer {
86
+ function getSeqMonomerFromHelmAtom(atom: Atom<HelmType>): ISeqMonomer {
88
87
  const polymerType = helmTypeToPolymerType(atom.bio.type);
89
88
  return {symbol: atom.elem, polymerType: polymerType};
90
89
  }
@@ -2,7 +2,9 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import * as org from 'org';
5
+ import {
6
+ HelmType, IWebEditorMonomer, MonomerType, PolymerType, WebEditorRGroups
7
+ } from '@datagrok-libraries/bio/src/helm/types';
6
8
 
7
9
  import {Monomer} from '@datagrok-libraries/bio/src/types/index';
8
10
  import {
@@ -33,56 +35,18 @@ export function getRS(smiles: string) {
33
35
  return res;
34
36
  }
35
37
 
36
- export class LibraryWebEditorMonomer implements org.helm.WebEditorMonomer {
37
- public get rs(): number { return Object.keys(this.at).length; }
38
-
39
- /* eslint-disable max-params */
40
- protected constructor(
41
- public readonly id: string,
42
- public readonly m: string,
43
- public readonly n: string,
44
- public readonly na: string | undefined,
45
- public readonly type: org.helm.PolymerType,
46
- public readonly mt: org.helm.MonomerType,
47
- public readonly at: org.helm.WebEditorRGroups,
48
- ) /* eslint-enable max-params */ {}
49
-
50
- static fromMonomer(biotype: org.helm.HelmType, monomer: Monomer): org.helm.WebEditorMonomer {
51
- let at: org.helm.WebEditorRGroups = {};
52
- const smiles = monomer[REQ.SMILES];
53
- if (monomer.rgroups.length > 0) {
54
- monomer.rgroups.forEach((it) => {
55
- at[it[RGP.LABEL]] = it[RGP.CAP_GROUP_NAME];
56
- });
57
- } else if (smiles) {
58
- // Generate R-Groups from SMILES
59
- at = getRS(smiles);
60
- } else {
61
- // broken
62
- return new BrokenWebEditorMonomer(biotype, monomer[REQ.SYMBOL]);
63
- }
64
-
65
- return new LibraryWebEditorMonomer(
66
- monomer[REQ.SYMBOL],
67
- monomer[REQ.MOLFILE],
68
- monomer[REQ.NAME],
69
- monomer[OPT.NATURAL_ANALOG],
70
- monomer[REQ.POLYMER_TYPE],
71
- monomer[REQ.MONOMER_TYPE],
72
- at);
73
- }
74
- }
75
-
76
38
  /* eslint-disable camelcase */
77
- export abstract class DummyWebEditorMonomer implements org.helm.WebEditorMonomer {
39
+ export abstract class DummyWebEditorMonomer implements IWebEditorMonomer {
78
40
  //@formatter:off
79
41
  public abstract get backgroundcolor(): string | undefined;
80
42
  public abstract get linecolor(): string | undefined;
81
43
  public abstract get textcolor(): string | undefined;
82
44
  //@formatter:on
83
45
 
46
+ get issmiles(): boolean { return !!this.smiles; }
47
+
84
48
  /** R-Group index os single digit only is allowed in Pistoia code */
85
- public readonly at: org.helm.WebEditorRGroups = {
49
+ public readonly at: WebEditorRGroups = {
86
50
  R1: 'H', R2: 'H', R3: 'H', R4: 'H', R5: 'H', R6: 'H', R7: 'H', R8: 'H', R9: 'H'
87
51
  };
88
52
 
@@ -94,8 +58,9 @@ export abstract class DummyWebEditorMonomer implements org.helm.WebEditorMonomer
94
58
  /** name */ public readonly n: string | undefined = 'missing',
95
59
  /** molfile */ public readonly m: string | undefined = undefined,
96
60
  /* Pistoia.HELM deletes .type and .mt in Monomers.addOneMonomer() */
97
- /** polymer type */ public readonly type: org.helm.PolymerType | undefined = undefined,
98
- /** monomer type */ public readonly mt: org.helm.MonomerType | undefined = undefined,
61
+ /** polymer type */ public readonly type: PolymerType | undefined = undefined,
62
+ /** monomer type */ public readonly mt: MonomerType | undefined = undefined,
63
+ public readonly smiles?: string,
99
64
  ) {
100
65
  if (!this.id)
101
66
  throw new Error('Invalid arg undefined [id].');
@@ -0,0 +1,90 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import {
6
+ HelmType, IWebEditorMonomer, IMonomerColors, MonomerType, PolymerType, WebEditorRGroups
7
+ } from '@datagrok-libraries/bio/src/helm/types';
8
+ import {Monomer} from '@datagrok-libraries/bio/src/types';
9
+ import {
10
+ HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP
11
+ } from '@datagrok-libraries/bio/src/utils/const';
12
+ import {BrokenWebEditorMonomer, getRS, MissingWebEditorMonomer} from './get-monomer-dummy';
13
+
14
+ function getMonomerColors(monomer: Monomer): IMonomerColors | null {
15
+ const currentMonomerSchema = 'default';
16
+ let monomerSchema: string = currentMonomerSchema;
17
+ if (!monomer.meta || !monomer.meta.colors) return null;
18
+
19
+ const monomerColors: { [colorSchemaName: string]: any } = monomer.meta.colors;
20
+
21
+ if (!(currentMonomerSchema in monomerColors)) monomerSchema = 'default';
22
+
23
+ const res = monomerColors[monomerSchema];
24
+
25
+ return !res ? null : {
26
+ textcolor: res.text ?? res.textColor,
27
+ linecolor: res.line ?? res.lineColor,
28
+ backgroundcolor: res.background ?? res.backgroundColor
29
+ } as IMonomerColors;
30
+ }
31
+
32
+ export class LibraryWebEditorMonomer implements IWebEditorMonomer {
33
+ public get rs(): number { return Object.keys(this.at).length; }
34
+
35
+ public get issmiles(): boolean { return !!this.smiles; }
36
+
37
+ public linecolor?: string;
38
+ public backgroundcolor?: string;
39
+ public textcolor?: string;
40
+
41
+ /* eslint-disable max-params */
42
+ protected constructor(
43
+ public readonly id: string,
44
+ public readonly m: string,
45
+ public readonly n: string,
46
+ public readonly na: string | undefined,
47
+ public readonly type: PolymerType,
48
+ public readonly mt: MonomerType,
49
+ public readonly at: WebEditorRGroups,
50
+ public readonly smiles?: string,
51
+ ) /* eslint-enable max-params */ {}
52
+
53
+ static fromMonomer(biotype: HelmType, monomer: Monomer): IWebEditorMonomer {
54
+ let at: WebEditorRGroups = {};
55
+ const symbol = monomer[REQ.SYMBOL];
56
+ const smiles = monomer[REQ.SMILES];
57
+ if (monomer.rgroups.length > 0) {
58
+ monomer.rgroups.forEach((it) => {
59
+ at[it[RGP.LABEL]] = it[RGP.CAP_GROUP_NAME];
60
+ });
61
+ } else if (smiles) {
62
+ // Generate R-Groups from SMILES
63
+ at = getRS(smiles);
64
+ } else if (!monomer.lib) {
65
+ // missing
66
+ return new MissingWebEditorMonomer(biotype, symbol);
67
+ } else {
68
+ // broken
69
+ return new BrokenWebEditorMonomer(biotype, symbol);
70
+ }
71
+
72
+ const res = new LibraryWebEditorMonomer(
73
+ monomer[REQ.SYMBOL],
74
+ monomer[REQ.MOLFILE],
75
+ monomer[REQ.NAME],
76
+ monomer[OPT.NATURAL_ANALOG],
77
+ monomer[REQ.POLYMER_TYPE],
78
+ monomer[REQ.MONOMER_TYPE],
79
+ at);
80
+
81
+ const colors = getMonomerColors(monomer);
82
+ if (colors) {
83
+ res.textcolor = colors?.textcolor;
84
+ res.linecolor = colors?.linecolor;
85
+ res.backgroundcolor = colors?.backgroundcolor;
86
+ }
87
+
88
+ return res;
89
+ }
90
+ }
@@ -2,30 +2,30 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import * as org from 'org';
6
- import * as scil from 'scil';
7
- import * as JSDraw2 from 'JSDraw2';
8
- import Atom = JSDraw2.Atom;
9
-
10
5
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
11
- import {HelmType, IMonomerLib, Monomer, WebEditorMonomer} from '@datagrok-libraries/bio/src/types';
6
+ import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
7
+ import {Atom, HelmType, IWebEditorMonomer, GetMonomerResType} from '@datagrok-libraries/bio/src/helm/types';
12
8
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
13
- import {PolymerTypes, HelmTypes} from '@datagrok-libraries/bio/src/utils/const';
14
9
  import {
15
10
  HELM_REQUIRED_FIELD as REQ
16
11
  } from '@datagrok-libraries/bio/src/utils/const';
12
+ import {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
13
+
14
+ import {AmbiguousWebEditorMonomer, GapWebEditorMonomer, MissingWebEditorMonomer} from './get-monomer-dummy';
15
+ import {LibraryWebEditorMonomer} from './get-monomer-of-library';
16
+ import {OrgHelmModule, ScilModule} from '../types';
17
+
18
+ import {_package} from '../package';
17
19
 
18
- import {AmbiguousWebEditorMonomer, GapWebEditorMonomer, LibraryWebEditorMonomer} from './dummy-monomer';
20
+ declare const org: OrgHelmModule;
21
+ declare const scil: ScilModule;
19
22
 
20
23
  const monomerRe = /[\w()]+/;
21
24
  //** Do not mess with monomer symbol with parenthesis enclosed in square brackets */
22
25
  const ambMonomerRe = RegExp(String.raw`\(${monomerRe}(,${monomerRe})+\)`);
23
26
 
24
- export type GetMonomerResType = WebEditorMonomer | null;
25
-
26
- export type GetMonomerFunc = (a: Atom<HelmType> | HelmType, name: string | undefined) => GetMonomerResType;
27
27
  type GetMonomerOverridingFunc = (
28
- a: Atom<HelmType> | HelmType, name: string, monomerLib: IMonomerLib,
28
+ a: Atom<HelmType> | HelmType, name: string | undefined, monomerLib: IMonomerLib,
29
29
  originalGetMonomer: (a: Atom<HelmType> | HelmType, name: string) => GetMonomerResType) => GetMonomerResType;
30
30
 
31
31
  export function getMonomerOverrideAndLogAlert(
@@ -36,11 +36,10 @@ export function getMonomerOverrideAndLogAlert(
36
36
  const getMonomerOriginal = monomers.getMonomer.bind(monomers);
37
37
  const alertOriginal = scil.Utils.alert;
38
38
  try {
39
- org.helm.webeditor.Monomers.getMonomer = (
40
- a: Atom<HelmType> | HelmType, name: string
41
- ): GetMonomerResType => {
42
- return getMonomerOverriding(a, name, monomerLib, getMonomerOriginal);
43
- };
39
+ org.helm.webeditor.Monomers.getMonomer =
40
+ (a: Atom<HelmType> | HelmType, name?: string): GetMonomerResType => {
41
+ return getMonomerOverriding(a, name, monomerLib, getMonomerOriginal);
42
+ };
44
43
  // Preventing alert message box for missing monomers with compressed Scilligence.JSDraw2.Lite.js
45
44
  scil.Utils.alert = (s: string): void => {
46
45
  logger.warning(`${logPrefix}, scil.Utils.alert() s = 's'.`);
@@ -59,7 +58,7 @@ export function getMonomerHandleArgs(
59
58
  let biotype: HelmType;
60
59
  let elem: string;
61
60
  if ((a as Atom<HelmType>).T === 'ATOM') {
62
- biotype = (a as Atom<HelmType>).biotype();
61
+ biotype = (a as Atom<HelmType>).biotype()!;
63
62
  elem = (a as Atom<HelmType>).elem;
64
63
  } else {
65
64
  biotype = a as HelmType;
@@ -72,8 +71,8 @@ export function getMonomerHandleArgs(
72
71
  /** Substitutes {@link org.helm.webeditor.Monomers.getMonomer()} */
73
72
  export function getWebEditorMonomer(
74
73
  monomerLib: IMonomerLib,
75
- a: Atom<HelmType> | HelmType, argName: string,
76
- ): WebEditorMonomer | null {
74
+ a: Atom<HelmType> | HelmType, argName?: string,
75
+ ): IWebEditorMonomer | null {
77
76
  const [biotype, elem] = getMonomerHandleArgs(a, argName);
78
77
  const pt = helmTypeToPolymerType(biotype);
79
78
 
@@ -91,7 +90,7 @@ export function getWebEditorMonomer(
91
90
  m = monomerLib.addMissingMonomer(pt, elem);
92
91
 
93
92
  /** Get or create {@link org,helm.WebEditorMonomer} */
94
- let resWem: WebEditorMonomer | undefined = m.wem;
93
+ let resWem: IWebEditorMonomer | null = m.wem ?? null;
95
94
  if (!resWem) {
96
95
  if (elem === '*')
97
96
  resWem = m.wem = new GapWebEditorMonomer(biotype, elem);
@@ -102,6 +101,9 @@ export function getWebEditorMonomer(
102
101
  ambMonomerRe.test(elem) // e.g. (A,R,_)
103
102
  )
104
103
  resWem = m.wem = new AmbiguousWebEditorMonomer(biotype, elem);
104
+ else if (!m.lib)
105
+ resWem = m.wem = new MissingWebEditorMonomer(biotype, elem);
106
+
105
107
 
106
108
  if (!resWem)
107
109
  resWem = m.wem = LibraryWebEditorMonomer.fromMonomer(biotype, m);
@@ -2,9 +2,9 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
 
5
- import * as JSDraw2 from 'JSDraw2';
6
5
  import wu from 'wu';
7
6
 
7
+ import {HelmType, Mol} from '@datagrok-libraries/bio/src/helm/types';
8
8
  import {
9
9
  CellRendererBackAsyncBase, RenderServiceBase
10
10
  } from '@datagrok-libraries/bio/src/utils/cell-renderer-async-base';
@@ -18,6 +18,8 @@ import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
18
18
  import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
19
19
 
20
20
  import {_package, getMonomerLib} from '../package';
21
+ import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
22
+ import {GridCell, GridCellStyle, x} from 'datagrok-api/dg';
21
23
 
22
24
  class WrapLogger implements ILogger {
23
25
  constructor(
@@ -44,6 +46,8 @@ class WrapLogger implements ILogger {
44
46
  export class HelmGridCellRendererBack extends CellRendererBackAsyncBase<HelmProps, HelmAux> {
45
47
  private _auxList: (HelmAux | null)[];
46
48
 
49
+ private monomerLib: IMonomerLib | null = null;
50
+
47
51
  constructor(
48
52
  gridCol: DG.GridColumn | null,
49
53
  tableCol: DG.Column<string>,
@@ -134,7 +138,7 @@ export class HelmGridCellRendererBack extends CellRendererBackAsyncBase<HelmProp
134
138
  const argsX = (e.offsetX - gcb.x) * dpr;
135
139
  const argsY = (e.offsetY - gcb.y) * dpr;
136
140
 
137
- const editorMol: JSDraw2.IEditorMol | null = aux.mol;
141
+ const editorMol: Mol<HelmType> | null = aux.mol;
138
142
  if (!editorMol) {
139
143
  this.logger.warning(`${logPrefix}, editorMol of the cell not found.`);
140
144
  return; // The gridCell is not rendered yet
@@ -152,10 +156,22 @@ export class HelmGridCellRendererBack extends CellRendererBackAsyncBase<HelmProp
152
156
  }
153
157
  }
154
158
 
159
+ public override render(g: CanvasRenderingContext2D,
160
+ x: number, y: number, w: number, h: number,
161
+ gridCell: GridCell, cellStyle: GridCellStyle) {
162
+ if (!this.monomerLib) {
163
+ this.monomerLib = getMonomerLib();
164
+ if (this.monomerLib) {
165
+ this.subs.push(this.monomerLib.onChanged.subscribe(this.monomerLibOnChanged.bind(this)));
166
+ }
167
+ }
168
+ super.render(g, x, y, w, h, gridCell, cellStyle);
169
+ }
170
+
155
171
  // -- Handle events --
172
+
156
173
  private monomerLibOnChanged(_value: any): void {
157
174
  this.reset();
158
- this.invalidateGrid();
159
175
  }
160
176
 
161
177
  static getOrCreate(gridCell: DG.GridCell): HelmGridCellRendererBack {
@@ -2,25 +2,26 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import * as org from 'org';
6
- import * as scil from 'scil';
7
- import * as JSDraw2 from 'JSDraw2';
8
-
9
5
  import $ from 'cash-dom';
10
6
  import {Subject, Unsubscribable} from 'rxjs';
11
7
 
12
8
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
13
9
  import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
10
+ import {Editor, HelmType} from '@datagrok-libraries/bio/src/helm/types';
14
11
  import {RenderTask} from '@datagrok-libraries/bio/src/utils/cell-renderer-async-base';
15
12
  import {HelmAux, HelmProps, HelmServiceBase} from '@datagrok-libraries/bio/src/viewers/helm-service';
16
13
  import {svgToImage} from '@datagrok-libraries/utils/src/svg';
17
14
 
15
+ import {JSDraw2HelmModule} from '../types';
16
+
18
17
  import {_package} from '../package';
19
18
 
19
+ declare const JSDraw2: JSDraw2HelmModule;
20
+
20
21
  export class HelmService extends HelmServiceBase {
21
22
  private readonly hostDiv: HTMLDivElement;
22
23
 
23
- private editor!: JSDraw2.Editor;
24
+ private editor!: Editor<HelmType>;
24
25
  private image: HTMLImageElement | null = null;
25
26
 
26
27
  constructor() {