@datagrok/helm 2.1.25 → 2.1.27
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 +15 -1
- 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/cell-renderer.ts +0 -30
- 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 +64 -41
- package/src/tests/properties-widget-tests.ts +81 -0
- 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.27",
|
|
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",
|
package/src/cell-renderer.ts
CHANGED
|
@@ -144,36 +144,6 @@ function getHoveredMonomerFallback(
|
|
|
144
144
|
return hoveredSeqMonomer;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
// patch window.dojox.gfx.svg.Text.prototype.getTextWidth hangs
|
|
148
|
-
/** get the text width in pixels */
|
|
149
|
-
// @ts-ignore
|
|
150
|
-
window.dojox.gfx.svg.Text.prototype.getTextWidth = function() {
|
|
151
|
-
const rawNode = this.rawNode;
|
|
152
|
-
const oldParent = rawNode.parentNode;
|
|
153
|
-
const _measurementNode = rawNode.cloneNode(true);
|
|
154
|
-
_measurementNode.style.visibility = 'hidden';
|
|
155
|
-
|
|
156
|
-
// solution to the "orphan issue" in FF
|
|
157
|
-
let _width = 0;
|
|
158
|
-
const _text = _measurementNode.firstChild.nodeValue;
|
|
159
|
-
oldParent.appendChild(_measurementNode);
|
|
160
|
-
|
|
161
|
-
// solution to the "orphan issue" in Opera
|
|
162
|
-
// (nodeValue == "" hangs firefox)
|
|
163
|
-
if (_text != '') {
|
|
164
|
-
let watchdogCounter = 100;
|
|
165
|
-
while (!_width && --watchdogCounter > 0) { // <-- hangs
|
|
166
|
-
//Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
|
|
167
|
-
if (_measurementNode.getBBox)
|
|
168
|
-
_width = parseInt(_measurementNode.getBBox().width);
|
|
169
|
-
else
|
|
170
|
-
_width = 68;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
oldParent.removeChild(_measurementNode);
|
|
174
|
-
return _width;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
147
|
/** Helm cell renderer in case of no missed monomer draws with JSDraw2.Editor (webeditor),
|
|
178
148
|
* in case of missed monomers presented, draws linear sequences aligned in width per monomer.
|
|
179
149
|
*/
|
|
@@ -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
|
@@ -3,14 +3,18 @@ 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
5
|
|
|
6
|
+
import $ from 'cash-dom';
|
|
7
|
+
|
|
6
8
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
7
9
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
10
|
import {GapSymbols, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
9
11
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
12
|
+
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
10
13
|
|
|
11
14
|
import {findMonomers, parseHelm} from './utils';
|
|
12
|
-
import {HelmWebEditor} from './helm-web-editor';
|
|
13
15
|
import {HelmCellRenderer} from './cell-renderer';
|
|
16
|
+
import {HelmHelper} from './helm-helper';
|
|
17
|
+
import {getPropertiesWidget} from './widgets/properties-widget';
|
|
14
18
|
|
|
15
19
|
let monomerLib: IMonomerLib | null = null;
|
|
16
20
|
|
|
@@ -18,6 +22,38 @@ import {WebEditorMonomer, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './c
|
|
|
18
22
|
|
|
19
23
|
export const _package = new DG.Package();
|
|
20
24
|
|
|
25
|
+
function initHelmPatchDojo(): void {
|
|
26
|
+
// patch window.dojox.gfx.svg.Text.prototype.getTextWidth hangs
|
|
27
|
+
/** get the text width in pixels */
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
window.dojox.gfx.svg.Text.prototype.getTextWidth = function() {
|
|
30
|
+
const rawNode = this.rawNode;
|
|
31
|
+
const oldParent = rawNode.parentNode;
|
|
32
|
+
const _measurementNode = rawNode.cloneNode(true);
|
|
33
|
+
_measurementNode.style.visibility = 'hidden';
|
|
34
|
+
|
|
35
|
+
// solution to the "orphan issue" in FF
|
|
36
|
+
let _width = 0;
|
|
37
|
+
const _text = _measurementNode.firstChild.nodeValue;
|
|
38
|
+
oldParent.appendChild(_measurementNode);
|
|
39
|
+
|
|
40
|
+
// solution to the "orphan issue" in Opera
|
|
41
|
+
// (nodeValue == "" hangs firefox)
|
|
42
|
+
if (_text != '') {
|
|
43
|
+
let watchdogCounter = 100;
|
|
44
|
+
while (!_width && --watchdogCounter > 0) { // <-- hangs
|
|
45
|
+
//Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
|
|
46
|
+
if (_measurementNode.getBBox)
|
|
47
|
+
_width = parseInt(_measurementNode.getBBox().width);
|
|
48
|
+
else
|
|
49
|
+
_width = 68;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
oldParent.removeChild(_measurementNode);
|
|
53
|
+
return _width;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
21
57
|
//tags: init
|
|
22
58
|
export async function initHelm(): Promise<void> {
|
|
23
59
|
//@ts-ignore
|
|
@@ -27,6 +63,8 @@ export async function initHelm(): Promise<void> {
|
|
|
27
63
|
new Promise((resolve, reject) => {
|
|
28
64
|
// @ts-ignore
|
|
29
65
|
dojo.ready(function() { resolve(null); });
|
|
66
|
+
}).then(() => {
|
|
67
|
+
initHelmPatchDojo();
|
|
30
68
|
}),
|
|
31
69
|
grok.functions.call('Bio:getBioLib'),
|
|
32
70
|
])
|
|
@@ -105,7 +143,7 @@ function rewriteLibraries() {
|
|
|
105
143
|
});
|
|
106
144
|
|
|
107
145
|
// Obsolete
|
|
108
|
-
const grid: DG.Grid = grok.shell.tv
|
|
146
|
+
const grid: DG.Grid = grok.shell.tv?.grid;
|
|
109
147
|
if (grid) grid.invalidate();
|
|
110
148
|
}
|
|
111
149
|
|
|
@@ -159,29 +197,11 @@ export function openEditor(mol: string): void {
|
|
|
159
197
|
}
|
|
160
198
|
|
|
161
199
|
//name: Properties
|
|
162
|
-
//tags: panel, widgets
|
|
163
|
-
//input:
|
|
200
|
+
//tags: panel, bio, helm, widgets
|
|
201
|
+
//input: semantic_value sequence {semType: Macromolecule}
|
|
164
202
|
//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
|
-
);
|
|
203
|
+
export function propertiesWidget(sequence: DG.SemanticValue): DG.Widget {
|
|
204
|
+
return getPropertiesWidget(sequence);
|
|
185
205
|
}
|
|
186
206
|
|
|
187
207
|
function webEditor(cell?: DG.Cell, value?: string, units?: string) {
|
|
@@ -265,25 +285,28 @@ function getRS(smiles: string) {
|
|
|
265
285
|
//input: column col {semType: Macromolecule}
|
|
266
286
|
//output: column res
|
|
267
287
|
export function getMolfiles(col: DG.Column): DG.Column {
|
|
268
|
-
const grid = grok.shell.tv.grid;
|
|
269
|
-
const parent = grid.root.parentElement!;
|
|
270
288
|
const res = DG.Column.string('mols', col.length);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
289
|
+
|
|
290
|
+
const host = ui.div([], {style: {width: '0', height: '0'}});
|
|
291
|
+
document.documentElement.appendChild(host);
|
|
292
|
+
try {
|
|
293
|
+
const editor = new JSDraw2.Editor(host, {viewonly: true});
|
|
294
|
+
res.init((i) => {
|
|
295
|
+
editor.setHelm(col.get(i));
|
|
296
|
+
const mol = editor.getMolfile();
|
|
297
|
+
return mol;
|
|
298
|
+
});
|
|
299
|
+
return res;
|
|
300
|
+
} finally {
|
|
301
|
+
$(host).empty();
|
|
302
|
+
host.remove();
|
|
303
|
+
}
|
|
283
304
|
}
|
|
284
305
|
|
|
285
|
-
//
|
|
306
|
+
// -- Utils --
|
|
307
|
+
|
|
308
|
+
//name: getHelmHelper
|
|
286
309
|
//output: object result
|
|
287
|
-
export function
|
|
288
|
-
return
|
|
310
|
+
export async function getHelmHelper(): Promise<IHelmHelper> {
|
|
311
|
+
return HelmHelper.getInstance();
|
|
289
312
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
document.documentElement.appendChild(host);
|
|
18
|
+
try {
|
|
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
|
}
|