@datagrok/helm 2.1.24 → 2.1.26
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/CHANGELOG.md +13 -2
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +6 -5
- package/src/helm-helper.ts +62 -0
- package/src/helm-web-editor.ts +1 -34
- package/src/package-test.ts +1 -0
- package/src/package.ts +12 -26
- package/src/tests/properties-widget-tests.ts +81 -0
- package/src/utils/index.ts +47 -13
- package/src/widgets/properties-widget.ts +43 -0
- package/tsconfig.json +6 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/helm",
|
|
3
3
|
"friendlyName": "Helm",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.26",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleksandra Serhiienko",
|
|
7
7
|
"email": "oserhiienko@datagrok.ai"
|
|
@@ -15,22 +15,23 @@
|
|
|
15
15
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@datagrok-libraries/bio": "^5.39.
|
|
18
|
+
"@datagrok-libraries/bio": "^5.39.24",
|
|
19
19
|
"@datagrok-libraries/chem-meta": "^1.2.1",
|
|
20
|
-
"@datagrok-libraries/utils": "^4.
|
|
20
|
+
"@datagrok-libraries/utils": "^4.1.42",
|
|
21
21
|
"cash-dom": "^8.1.1",
|
|
22
|
-
"datagrok-api": "^1.
|
|
22
|
+
"datagrok-api": "^1.17.0",
|
|
23
23
|
"dayjs": "^1.10.6",
|
|
24
24
|
"rxjs": "^6.5.5",
|
|
25
25
|
"wu": "latest"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
+
"@types/node": "17.0.45",
|
|
28
29
|
"@types/wu": "latest",
|
|
29
30
|
"path": "^0.12.7",
|
|
30
31
|
"source-map-loader": "^4.0.1",
|
|
31
32
|
"ts-loader": "^9.2.6",
|
|
32
33
|
"typescript": "^4.8.4",
|
|
33
|
-
"webpack": "^5.
|
|
34
|
+
"webpack": "^5.76.3",
|
|
34
35
|
"webpack-cli": "^4.9.1",
|
|
35
36
|
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
|
36
37
|
"@typescript-eslint/parser": "^5.11.0",
|
|
@@ -0,0 +1,62 @@
|
|
|
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 {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
6
|
+
import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
|
|
7
|
+
import {HelmWebEditor} from './helm-web-editor';
|
|
8
|
+
|
|
9
|
+
type HelmHelperWindowType = Window & {
|
|
10
|
+
$helmHelper?: HelmHelper,
|
|
11
|
+
}
|
|
12
|
+
declare const window: HelmHelperWindowType;
|
|
13
|
+
|
|
14
|
+
export class HelmHelper implements IHelmHelper {
|
|
15
|
+
createHelmWebEditor(): IHelmWebEditor {
|
|
16
|
+
return new HelmWebEditor();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
createWebEditorApp(host: HTMLDivElement, helm: string): IWebEditorApp {
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
const webEditorApp = new scil.helm.App(host, {
|
|
24
|
+
showabout: false,
|
|
25
|
+
mexfontsize: '90%',
|
|
26
|
+
mexrnapinontab: true,
|
|
27
|
+
topmargin: 20,
|
|
28
|
+
mexmonomerstab: true,
|
|
29
|
+
sequenceviewonly: false,
|
|
30
|
+
mexfavoritefirst: true,
|
|
31
|
+
mexfilter: true
|
|
32
|
+
}) as IWebEditorApp;
|
|
33
|
+
const sizes = webEditorApp.calculateSizes();
|
|
34
|
+
webEditorApp.canvas.resize(sizes.rightwidth - 100, sizes.topheight - 210);
|
|
35
|
+
let s = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
36
|
+
//@ts-ignore
|
|
37
|
+
scil.apply(webEditorApp.sequence.style, s);
|
|
38
|
+
//@ts-ignore
|
|
39
|
+
scil.apply(webEditorApp.notation.style, s);
|
|
40
|
+
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + webEditorApp.toolbarheight) + 'px'};
|
|
41
|
+
//@ts-ignore
|
|
42
|
+
scil.apply(webEditorApp.properties.parent.style, s);
|
|
43
|
+
webEditorApp.structureview.resize(sizes.rightwidth, sizes.bottomheight + webEditorApp.toolbarheight);
|
|
44
|
+
webEditorApp.mex.resize(sizes.topheight - 80);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
webEditorApp.canvas.helm.setSequence(helm, 'HELM');
|
|
47
|
+
}, 200);
|
|
48
|
+
return webEditorApp;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// -- Instance singleton --
|
|
52
|
+
|
|
53
|
+
public static async getInstance(): Promise<IHelmHelper> {
|
|
54
|
+
let res: HelmHelper = window.$helmHelper!;
|
|
55
|
+
if (!res) {
|
|
56
|
+
// create & init singleton
|
|
57
|
+
window.$helmHelper = res = new HelmHelper();
|
|
58
|
+
// await res.init();
|
|
59
|
+
}
|
|
60
|
+
return res;
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/helm-web-editor.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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 {IHelmWebEditor} from '@datagrok-libraries/bio/src/types
|
|
5
|
+
import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
|
|
6
6
|
|
|
7
7
|
export class HelmWebEditor implements IHelmWebEditor {
|
|
8
8
|
host: any;
|
|
@@ -18,38 +18,5 @@ export class HelmWebEditor implements IHelmWebEditor {
|
|
|
18
18
|
resizeEditor(w: number, h: number) {
|
|
19
19
|
this.editor.setSize(w, h);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
createWebEditor(value: string) {
|
|
23
|
-
const editorView = ui.div();
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
const webEditor = new scil.helm.App(editorView, {
|
|
28
|
-
showabout: false,
|
|
29
|
-
mexfontsize: '90%',
|
|
30
|
-
mexrnapinontab: true,
|
|
31
|
-
topmargin: 20,
|
|
32
|
-
mexmonomerstab: true,
|
|
33
|
-
sequenceviewonly: false,
|
|
34
|
-
mexfavoritefirst: true,
|
|
35
|
-
mexfilter: true
|
|
36
|
-
});
|
|
37
|
-
const sizes = webEditor.calculateSizes();
|
|
38
|
-
webEditor.canvas.resize(sizes.rightwidth - 100, sizes.topheight - 210);
|
|
39
|
-
let s = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
40
|
-
//@ts-ignore
|
|
41
|
-
scil.apply(webEditor.sequence.style, s);
|
|
42
|
-
//@ts-ignore
|
|
43
|
-
scil.apply(webEditor.notation.style, s);
|
|
44
|
-
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + webEditor.toolbarheight) + 'px'};
|
|
45
|
-
//@ts-ignore
|
|
46
|
-
scil.apply(webEditor.properties.parent.style, s);
|
|
47
|
-
webEditor.structureview.resize(sizes.rightwidth, sizes.bottomheight + webEditor.toolbarheight);
|
|
48
|
-
webEditor.mex.resize(sizes.topheight - 80);
|
|
49
|
-
setTimeout(() => {
|
|
50
|
-
webEditor.canvas.helm.setSequence(value, 'HELM');
|
|
51
|
-
}, 200);
|
|
52
|
-
return {editorDiv: editorView, webEditor: webEditor};
|
|
53
|
-
}
|
|
54
21
|
}
|
|
55
22
|
|
package/src/package-test.ts
CHANGED
package/src/package.ts
CHANGED
|
@@ -7,10 +7,12 @@ import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
|
7
7
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
8
|
import {GapSymbols, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
9
9
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
10
|
+
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
10
11
|
|
|
11
12
|
import {findMonomers, parseHelm} from './utils';
|
|
12
|
-
import {HelmWebEditor} from './helm-web-editor';
|
|
13
13
|
import {HelmCellRenderer} from './cell-renderer';
|
|
14
|
+
import {HelmHelper} from './helm-helper';
|
|
15
|
+
import {getPropertiesWidget} from './widgets/properties-widget';
|
|
14
16
|
|
|
15
17
|
let monomerLib: IMonomerLib | null = null;
|
|
16
18
|
|
|
@@ -159,29 +161,11 @@ export function openEditor(mol: string): void {
|
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
//name: Properties
|
|
162
|
-
//tags: panel, widgets
|
|
163
|
-
//input:
|
|
164
|
+
//tags: panel, bio, helm, widgets
|
|
165
|
+
//input: semantic_value sequence {semType: Macromolecule}
|
|
164
166
|
//output: widget result
|
|
165
|
-
export
|
|
166
|
-
|
|
167
|
-
const parent = grid.root.parentElement!;
|
|
168
|
-
const host = ui.div([]);
|
|
169
|
-
parent.appendChild(host);
|
|
170
|
-
const editor = new JSDraw2.Editor(host, {viewonly: true});
|
|
171
|
-
host.style.width = '0px';
|
|
172
|
-
host.style.height = '0px';
|
|
173
|
-
editor.setHelm(helmString);
|
|
174
|
-
const formula = editor.getFormula(true);
|
|
175
|
-
const molWeight = Math.round(editor.getMolWeight() * 100) / 100;
|
|
176
|
-
const coef = Math.round(editor.getExtinctionCoefficient(true) * 100) / 100;
|
|
177
|
-
parent.lastChild!.remove();
|
|
178
|
-
return new DG.Widget(
|
|
179
|
-
ui.tableFromMap({
|
|
180
|
-
'formula': formula.replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
|
|
181
|
-
'molecular weight': molWeight,
|
|
182
|
-
'extinction coefficient': coef,
|
|
183
|
-
})
|
|
184
|
-
);
|
|
167
|
+
export function propertiesWidget(sequence: DG.SemanticValue): DG.Widget {
|
|
168
|
+
return getPropertiesWidget(sequence);
|
|
185
169
|
}
|
|
186
170
|
|
|
187
171
|
function webEditor(cell?: DG.Cell, value?: string, units?: string) {
|
|
@@ -282,8 +266,10 @@ export function getMolfiles(col: DG.Column): DG.Column {
|
|
|
282
266
|
return res;
|
|
283
267
|
}
|
|
284
268
|
|
|
285
|
-
//
|
|
269
|
+
// -- Utils --
|
|
270
|
+
|
|
271
|
+
//name: getHelmHelper
|
|
286
272
|
//output: object result
|
|
287
|
-
export function
|
|
288
|
-
return
|
|
273
|
+
export async function getHelmHelper(): Promise<IHelmHelper> {
|
|
274
|
+
return HelmHelper.getInstance();
|
|
289
275
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import * as grok from 'datagrok-api/grok';
|
|
4
|
+
|
|
5
|
+
import {category, expect, expectObject, test} from '@datagrok-libraries/utils/src/test';
|
|
6
|
+
import {ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
8
|
+
|
|
9
|
+
import {getPropertiesDict} from '../widgets/properties-widget';
|
|
10
|
+
|
|
11
|
+
const enum MolProps {
|
|
12
|
+
formula = 'formula',
|
|
13
|
+
mw = 'molecular weight',
|
|
14
|
+
extinctCoef = 'extinction coefficient',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const enum Tests {
|
|
18
|
+
helm = 'Helm',
|
|
19
|
+
separator = 'separator',
|
|
20
|
+
separator2 = 'separator2', // with a few gaps in a row
|
|
21
|
+
separatorGaps = 'separator-gaps',
|
|
22
|
+
fastaPt = 'fasta-PT',
|
|
23
|
+
fastaPtMsa = 'fasta-PT-MSA',
|
|
24
|
+
fastaDna = 'fasta-DNA',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const TestsData: {
|
|
28
|
+
[testName: string]: { seq: string, units: NOTATION, separator?: string, alphabet?: ALPHABET, res: {} }
|
|
29
|
+
} = {
|
|
30
|
+
[Tests.helm]: {
|
|
31
|
+
seq: 'PEPTIDE1{I.H.A.C.T.[Thr_PO3H2].[Aca].[D-Tyr_Et]}|PEPTIDE2{E.A.[meG]}$PEPTIDE1,PEPTIDE2,4:R3-1:R1$$$V2.0',
|
|
32
|
+
units: NOTATION.HELM,
|
|
33
|
+
res: {[MolProps.formula]: 'C58H94N13O21SP', [MolProps.mw]: 1372.48, [MolProps.extinctCoef]: 1.55}
|
|
34
|
+
},
|
|
35
|
+
[Tests.separator]: {
|
|
36
|
+
seq: 'I/H/A/C/T/Thr_PO3H2/Aca/D-Tyr_Et',
|
|
37
|
+
units: NOTATION.SEPARATOR, separator: '/', alphabet: ALPHABET.UN,
|
|
38
|
+
res: {[MolProps.formula]: 'C47H77N10O15SP', [MolProps.mw]: 1085.21, [MolProps.extinctCoef]: 1.55}
|
|
39
|
+
},
|
|
40
|
+
[Tests.separator2]: {
|
|
41
|
+
seq: 'meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca/D-Tyr_Et/Aze/dV/E/N////Phe_4Me',
|
|
42
|
+
units: NOTATION.SEPARATOR, separator: '/', alphabet: ALPHABET.UN,
|
|
43
|
+
res: {[MolProps.formula]: 'C91H146N19O25P', [MolProps.mw]: 1937.21, [MolProps.extinctCoef]: 1.49},
|
|
44
|
+
},
|
|
45
|
+
[Tests.separatorGaps]: {
|
|
46
|
+
seq: 'I/H/A//T/Thr_PO3H2/Aca/D-Tyr_Et',
|
|
47
|
+
units: NOTATION.SEPARATOR, separator: '/', alphabet: ALPHABET.UN,
|
|
48
|
+
res: {[MolProps.formula]: 'C44H72N9O14P', [MolProps.mw]: 982.07, [MolProps.extinctCoef]: 1.49},
|
|
49
|
+
},
|
|
50
|
+
[Tests.fastaPt]: {
|
|
51
|
+
seq: 'IHACTTAY',
|
|
52
|
+
units: NOTATION.FASTA, alphabet: ALPHABET.PT,
|
|
53
|
+
res: {[MolProps.formula]: 'C38H58N10O12S', [MolProps.mw]: 878.99, [MolProps.extinctCoef]: 1.55}
|
|
54
|
+
},
|
|
55
|
+
[Tests.fastaDna]: {
|
|
56
|
+
seq: 'ACGTATTCC',
|
|
57
|
+
units: NOTATION.FASTA, alphabet: ALPHABET.DNA,
|
|
58
|
+
res: {[MolProps.formula]: 'C87H113N30O56P9', [MolProps.mw]: 2753.76, [MolProps.extinctCoef]: 91.74}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
category('properties-widget', () => {
|
|
63
|
+
for (const [testName, testData] of Object.entries(TestsData)) {
|
|
64
|
+
test(testName, async () => {
|
|
65
|
+
testPropertiesDict(testData.seq, testData.units, testData.separator, testData.alphabet, testData.res);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
function testPropertiesDict(
|
|
71
|
+
seq: string, units: NOTATION, separator: string | undefined, alphabet: ALPHABET | undefined, expPropDict: {}
|
|
72
|
+
) {
|
|
73
|
+
const col = DG.Column.fromList(DG.COLUMN_TYPE.STRING, 'seq', [seq]);
|
|
74
|
+
col.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
75
|
+
col.setTag(DG.TAGS.UNITS, units);
|
|
76
|
+
if (separator) col.setTag(bioTAGS.separator, separator);
|
|
77
|
+
if (alphabet) col.setTag(bioTAGS.alphabet, alphabet);
|
|
78
|
+
const uh = UnitsHandler.getOrCreate(col);
|
|
79
|
+
const actPropDict = getPropertiesDict(seq, uh);
|
|
80
|
+
expectObject(actPropDict, expPropDict);
|
|
81
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -46,14 +46,16 @@ export function parseHelm(s: string): string[] {
|
|
|
46
46
|
for (const monomer of ss) {
|
|
47
47
|
if (!monomer || monomer === '') continue;
|
|
48
48
|
if (monomer.startsWith('[') && monomer.includes(']')) {
|
|
49
|
-
const
|
|
49
|
+
const closingIndex = findClosing(monomer, 1, '[', ']');
|
|
50
|
+
const element = monomer.substring(1, closingIndex);
|
|
50
51
|
monomers.push(element);
|
|
51
|
-
const residue = monomer.substring(
|
|
52
|
+
const residue = monomer.substring(closingIndex + 1);
|
|
52
53
|
ss.push(residue);
|
|
53
54
|
} else if (monomer.includes('[') && monomer.endsWith(']')) {
|
|
54
|
-
const
|
|
55
|
+
const openingIndex = findOpening(monomer, monomer.length - 2, '[', ']');
|
|
56
|
+
const element = monomer.substring(openingIndex + 1, monomer.length - 1);
|
|
55
57
|
monomers.push(element);
|
|
56
|
-
const residue = monomer.substring(0,
|
|
58
|
+
const residue = monomer.substring(0, openingIndex);
|
|
57
59
|
ss.push(residue);
|
|
58
60
|
} else if (monomer.includes('(') && monomer.includes(')')) {
|
|
59
61
|
// here we only want to split the string at first '(' and last ')'
|
|
@@ -64,9 +66,8 @@ export function parseHelm(s: string): string[] {
|
|
|
64
66
|
const elements = [firstPiece, secondPiece, thirdPiece];
|
|
65
67
|
for (const el of elements)
|
|
66
68
|
ss.push(el);
|
|
67
|
-
} else
|
|
69
|
+
} else
|
|
68
70
|
monomers.push(monomer);
|
|
69
|
-
}
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
}
|
|
@@ -111,6 +112,40 @@ export function findMonomers(monomerSymbolList: string[]): Set<string> {
|
|
|
111
112
|
return new Set(monomerSymbolList.filter((val) => !monomerNames.includes(val)));
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
function findClosing(s: string, start: number, open: string, close: string) {
|
|
116
|
+
let i = start;
|
|
117
|
+
let count = 0;
|
|
118
|
+
while (i < s.length) {
|
|
119
|
+
if (s[i] === open)
|
|
120
|
+
count++;
|
|
121
|
+
|
|
122
|
+
if (s[i] === close) {
|
|
123
|
+
if (count === 0)
|
|
124
|
+
return i;
|
|
125
|
+
count--;
|
|
126
|
+
}
|
|
127
|
+
i++;
|
|
128
|
+
}
|
|
129
|
+
return -1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function findOpening(s: string, start: number, open: string, close: string) {
|
|
133
|
+
let i = start;
|
|
134
|
+
let count = 0;
|
|
135
|
+
while (i >= 0) {
|
|
136
|
+
if (s[i] === close)
|
|
137
|
+
count++;
|
|
138
|
+
|
|
139
|
+
if (s[i] === open) {
|
|
140
|
+
if (count === 0)
|
|
141
|
+
return i;
|
|
142
|
+
count--;
|
|
143
|
+
}
|
|
144
|
+
i--;
|
|
145
|
+
}
|
|
146
|
+
return -1;
|
|
147
|
+
}
|
|
148
|
+
|
|
114
149
|
function split(s: string, sep: string) {
|
|
115
150
|
const ret = [];
|
|
116
151
|
let frag = '';
|
|
@@ -136,19 +171,18 @@ function split(s: string, sep: string) {
|
|
|
136
171
|
if (c == '\"') {
|
|
137
172
|
if (!(i > 0 && s.substring(i - 1, i) == '\\'))
|
|
138
173
|
quote = quote == 0 ? 1 : 0;
|
|
139
|
-
} else if (c == '[')
|
|
174
|
+
} else if (c == '[')
|
|
140
175
|
++bracket;
|
|
141
|
-
|
|
176
|
+
else if (c == ']')
|
|
142
177
|
--bracket;
|
|
143
|
-
|
|
178
|
+
else if (c == '(')
|
|
144
179
|
++parentheses;
|
|
145
|
-
|
|
180
|
+
else if (c == ')')
|
|
146
181
|
--parentheses;
|
|
147
|
-
|
|
182
|
+
else if (c == '{')
|
|
148
183
|
++braces;
|
|
149
|
-
|
|
184
|
+
else if (c == '}')
|
|
150
185
|
--braces;
|
|
151
|
-
}
|
|
152
186
|
}
|
|
153
187
|
}
|
|
154
188
|
ret.push(frag);
|
|
@@ -0,0 +1,43 @@
|
|
|
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 $ from 'cash-dom';
|
|
6
|
+
|
|
7
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
8
|
+
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
9
|
+
|
|
10
|
+
export function getPropertiesDict(seq: string, uh: UnitsHandler): {} {
|
|
11
|
+
const helmString = uh.isHelm() ? seq : uh.getConverter(NOTATION.HELM)(seq);
|
|
12
|
+
// Remove gap symbols for compatibility with WebEditor
|
|
13
|
+
const helmString2 = helmString.replaceAll(/\.(\*\.)+/g, '.')
|
|
14
|
+
.replaceAll(/\{(\*\.)+/g, '{').replaceAll(/(\.\*)+}/g, '}');
|
|
15
|
+
|
|
16
|
+
const host = ui.div([], {style: {width: '0', height: '0'}});
|
|
17
|
+
try {
|
|
18
|
+
document.documentElement.appendChild(host);
|
|
19
|
+
const editor = new JSDraw2.Editor(host, {viewonly: true});
|
|
20
|
+
editor.setHelm(helmString2);
|
|
21
|
+
|
|
22
|
+
const formula = editor.getFormula(true);
|
|
23
|
+
const molWeight = Math.round(editor.getMolWeight() * 100) / 100;
|
|
24
|
+
const coef = Math.round(editor.getExtinctionCoefficient(true) * 100) / 100;
|
|
25
|
+
return {
|
|
26
|
+
'formula': formula.replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
|
|
27
|
+
'molecular weight': molWeight,
|
|
28
|
+
'extinction coefficient': coef,
|
|
29
|
+
};
|
|
30
|
+
} finally {
|
|
31
|
+
$(host).empty();
|
|
32
|
+
host.remove();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export function getPropertiesWidget(value: DG.SemanticValue): DG.Widget {
|
|
38
|
+
const uh = UnitsHandler.getOrCreate(value.cell.column);
|
|
39
|
+
const propDict = getPropertiesDict(value.value, uh);
|
|
40
|
+
return new DG.Widget(
|
|
41
|
+
ui.tableFromMap(propDict)
|
|
42
|
+
);
|
|
43
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
/* Basic Options */
|
|
6
6
|
// "incremental": true, /* Enable incremental compilation */
|
|
7
|
-
"target": "
|
|
7
|
+
"target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
|
8
8
|
"module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
|
9
|
-
"lib": ["ES2022", "dom"], /* Specify library files to be included in the compilation. */
|
|
9
|
+
"lib": ["ES2022", "ES2022.String", "dom"], /* Specify library files to be included in the compilation. */
|
|
10
10
|
"allowJs": true, /* Allow javascript files to be compiled. */
|
|
11
11
|
// "checkJs": true, /* Report errors in .js files. */
|
|
12
12
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
|
@@ -61,11 +61,12 @@
|
|
|
61
61
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
62
62
|
|
|
63
63
|
/* Experimental Options */
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
65
|
+
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
66
66
|
|
|
67
67
|
/* Advanced Options */
|
|
68
68
|
"skipLibCheck": false, /* Skip type checking of declaration files. */
|
|
69
|
-
"forceConsistentCasingInFileNames": true
|
|
69
|
+
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
|
70
|
+
//"jsx": "react"
|
|
70
71
|
}
|
|
71
72
|
}
|