@datagrok/helm 2.0.0 → 2.0.3
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/README.md +1 -1
- package/dist/package-test.js +2827 -92
- package/dist/package.js +666 -217
- package/helm/JSDraw/test.html +3 -0
- package/package.json +25 -20
- package/src/__jest__/remote.test.ts +4 -4
- package/src/__jest__/test-node.ts +3 -2
- package/src/package-test.ts +0 -1
- package/src/package.ts +300 -82
- package/src/tests/helm-tests.ts +46 -16
- package/{test-Helm-4f0c8bae6479-529c5bce.html → test-Helm-4f0c8bae6479-d7a9fa45.html} +5 -4
- /package/{images → vendor}/helm-rendering.png +0 -0
package/helm/JSDraw/test.html
CHANGED
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
<script type="text/javascript">
|
|
16
16
|
dojo.ready(function () {
|
|
17
17
|
var jsd = new JSDraw("Div2", { width: 800, height: 400, skin: "w8", viewonly: true });
|
|
18
|
+
var mol = jsd.getMolfile();
|
|
19
|
+
var m = new JSDraw2.Mol();
|
|
20
|
+
console.log(JSDraw2.FormulaParser.getAtomStats(m.setMolfile(mol)));
|
|
18
21
|
});
|
|
19
22
|
</script>
|
|
20
23
|
</body>
|
package/package.json
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/helm",
|
|
3
|
-
"beta": false,
|
|
4
3
|
"friendlyName": "Helm",
|
|
5
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.3",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Oleksandra Serhiienko",
|
|
7
|
+
"email": "oserhiienko@datagrok.ai"
|
|
8
|
+
},
|
|
6
9
|
"description": "",
|
|
7
10
|
"dependencies": {
|
|
8
|
-
"datagrok-api": "^1.
|
|
9
|
-
"cash-dom": "
|
|
10
|
-
"dayjs": "
|
|
11
|
-
"@datagrok-libraries/utils": "^1.
|
|
12
|
-
"@datagrok-libraries/bio": "^
|
|
13
|
-
|
|
14
|
-
"typescript": "^4.4.2"
|
|
11
|
+
"datagrok-api": "^1.6.0",
|
|
12
|
+
"cash-dom": "^8.1.1",
|
|
13
|
+
"dayjs": "^1.10.6",
|
|
14
|
+
"@datagrok-libraries/utils": "^1.6.2",
|
|
15
|
+
"@datagrok-libraries/bio": "^3.1.1"
|
|
16
|
+
|
|
15
17
|
},
|
|
16
18
|
"sources": [
|
|
17
19
|
"css/helm.css",
|
|
@@ -21,21 +23,24 @@
|
|
|
21
23
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
22
24
|
],
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@typescript-eslint/eslint-plugin": "latest",
|
|
25
|
-
"@typescript-eslint/parser": "latest",
|
|
26
|
-
"eslint": "latest",
|
|
27
|
-
"eslint-config-google": "latest",
|
|
28
|
-
"ts-loader": "latest",
|
|
29
|
-
"typescript": "latest",
|
|
30
|
-
"webpack": "latest",
|
|
31
|
-
"webpack-cli": "latest",
|
|
32
26
|
"@types/jest": "^27.0.0",
|
|
33
27
|
"jest": "^27.0.0",
|
|
34
|
-
"jest-html-reporter": "^3.
|
|
28
|
+
"jest-html-reporter": "^3.6.0",
|
|
29
|
+
"path": "^0.12.7",
|
|
35
30
|
"puppeteer": "^13.7.0",
|
|
36
31
|
"ts-jest": "^27.0.0",
|
|
32
|
+
"ts-loader": "^9.2.6",
|
|
33
|
+
"typescript": "^4.4.4",
|
|
34
|
+
"webpack": "^5.59.1",
|
|
35
|
+
"webpack-cli": "^4.9.1",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
|
37
|
+
"@typescript-eslint/parser": "^5.11.0",
|
|
38
|
+
"eslint": "^8.18.0",
|
|
39
|
+
"eslint-config-google": "^0.14.0",
|
|
37
40
|
"@types/js-yaml": "^4.0.5",
|
|
38
|
-
"
|
|
41
|
+
"js-yaml": "^4.1.0",
|
|
42
|
+
"@types/node-fetch": "^2.6.2",
|
|
43
|
+
"node-fetch": "^2.6.7"
|
|
39
44
|
},
|
|
40
45
|
"scripts": {
|
|
41
46
|
"link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
|
|
@@ -51,7 +56,7 @@
|
|
|
51
56
|
"release-helm-public": "grok publish public --release",
|
|
52
57
|
"lint": "eslint \"./src/**/*.ts\"",
|
|
53
58
|
"lint-fix": "eslint \"./src/**/*.ts\" --fix",
|
|
54
|
-
"test": "
|
|
59
|
+
"test": "jest",
|
|
55
60
|
"test-dev": "set HOST=dev && jest",
|
|
56
61
|
"test-local": "set HOST=localhost && jest"
|
|
57
62
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as utils from './test-node';
|
|
6
6
|
import puppeteer from 'puppeteer';
|
|
7
7
|
|
|
8
|
-
const P_START_TIMEOUT: number =
|
|
8
|
+
const P_START_TIMEOUT: number = 3600000;
|
|
9
9
|
let browser: puppeteer.Browser;
|
|
10
10
|
let page: puppeteer.Page;
|
|
11
11
|
|
|
@@ -51,10 +51,10 @@ it('TEST', async () => {
|
|
|
51
51
|
let failReport = '';
|
|
52
52
|
for (let i = 0; i < df.rowCount; i++) {
|
|
53
53
|
if (cStatus.get(i)) {
|
|
54
|
-
passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
54
|
+
passReport += `Test result : Success : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
55
55
|
} else {
|
|
56
56
|
failed = true;
|
|
57
|
-
failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
57
|
+
failReport += `Test result : Failed : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
resolve({failReport, passReport, failed});
|
|
@@ -65,4 +65,4 @@ it('TEST', async () => {
|
|
|
65
65
|
console.log(r.passReport);
|
|
66
66
|
// @ts-ignore
|
|
67
67
|
expect(r.failed).checkOutput(false, r.failReport);
|
|
68
|
-
},
|
|
68
|
+
}, 3600000);
|
|
@@ -66,6 +66,7 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
let page = await browser.newPage();
|
|
69
|
+
await page.setDefaultNavigationTimeout(0);
|
|
69
70
|
await page.goto(`${url}/oauth/`);
|
|
70
71
|
await page.setCookie({name: 'auth', value: token});
|
|
71
72
|
await page.evaluate((token: any) => {
|
|
@@ -73,8 +74,8 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
73
74
|
}, token);
|
|
74
75
|
await page.goto(url);
|
|
75
76
|
try {
|
|
76
|
-
await page.waitForSelector('.grok-preloader');
|
|
77
|
-
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout:
|
|
77
|
+
await page.waitForSelector('.grok-preloader', { timeout: 1800000 });
|
|
78
|
+
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 3600000});
|
|
78
79
|
} catch (error) {
|
|
79
80
|
throw error;
|
|
80
81
|
}
|
package/src/package-test.ts
CHANGED
|
@@ -11,7 +11,6 @@ export {tests};
|
|
|
11
11
|
//input: string category {optional: true}
|
|
12
12
|
//input: string test {optional: true}
|
|
13
13
|
//output: dataframe result
|
|
14
|
-
//top-menu: Tools | Dev | JS API Tests
|
|
15
14
|
export async function test(category: string, test: string): Promise<DG.DataFrame> {
|
|
16
15
|
const data = await runTests({category, test});
|
|
17
16
|
return DG.DataFrame.fromObjects(data)!;
|
package/src/package.ts
CHANGED
|
@@ -2,16 +2,15 @@
|
|
|
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
|
-
|
|
6
|
-
import {NotationConverter, NOTATION} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
7
|
-
import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
5
|
+
import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
8
6
|
import {createJsonMonomerLibFromSdf} from './utils';
|
|
9
7
|
import {MONOMER_MANAGER_MAP, RGROUPS, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
|
|
10
|
-
|
|
8
|
+
import {printLeftOrCentered} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
11
9
|
|
|
12
10
|
export const _package = new DG.Package();
|
|
13
11
|
|
|
14
12
|
const lru = new DG.LruCache<any, any>();
|
|
13
|
+
const molfiles = new DG.LruCache<any, any>();
|
|
15
14
|
const STORAGE_NAME = 'Libraries';
|
|
16
15
|
let i = 0;
|
|
17
16
|
const LIB_PATH = 'libraries/';
|
|
@@ -24,22 +23,24 @@ export async function initHelm(): Promise<void> {
|
|
|
24
23
|
await monomerManager(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
|
|
25
24
|
}
|
|
26
25
|
grid.invalidate();
|
|
26
|
+
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
dojo.ready(function() { resolve(null); });
|
|
30
|
+
});
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
//name:
|
|
30
|
-
|
|
31
|
-
|
|
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();
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
//name: getLru
|
|
35
|
-
export async function getLru() {
|
|
36
|
-
return await grok.functions.call('Bio:Lru');
|
|
37
|
-
}
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
//description: Macromolecule
|
|
41
|
-
//input: grid_cell cell
|
|
42
|
-
export function editMoleculeCell(cell: DG.GridCell): void {
|
|
43
|
+
export function webEditor(value: string) {
|
|
43
44
|
let view = ui.div();
|
|
44
45
|
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
45
46
|
let app = new scil.helm.App(view, {
|
|
@@ -64,55 +65,72 @@ export function editMoleculeCell(cell: DG.GridCell): void {
|
|
|
64
65
|
scil.apply(app.properties.parent.style, s);
|
|
65
66
|
app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
|
|
66
67
|
app.mex.resize(sizes.topheight - 80);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
cell.cell.value;
|
|
89
|
-
}).show({modal: true, fullScreen: true});
|
|
68
|
+
setTimeout(function() {
|
|
69
|
+
app.canvas.helm.setSequence(value, 'HELM');
|
|
70
|
+
}, 200);
|
|
71
|
+
//@ts-ignore
|
|
72
|
+
ui.dialog({showHeader: false, showFooter: true})
|
|
73
|
+
.add(view)
|
|
74
|
+
.onOK(() => {
|
|
75
|
+
const val = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
|
|
76
|
+
value = val;
|
|
77
|
+
}).show({modal: true, fullScreen: true});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
//tags: cellEditor
|
|
82
|
+
//description: Macromolecule
|
|
83
|
+
//input: grid_cell cell
|
|
84
|
+
export function editMoleculeCell(cell: DG.GridCell): void {
|
|
85
|
+
if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'helm') {
|
|
86
|
+
let grid = grok.shell.tv.grid;
|
|
87
|
+
webEditor(cell.cell.value);
|
|
88
|
+
grid.invalidate();
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
//name:
|
|
92
|
+
//name: Open Helm Web Editor
|
|
93
|
+
//description: Adds editor
|
|
94
|
+
//meta.action: Open Helm Web Editor
|
|
95
|
+
//input: string mol { semType: Macromolecule }
|
|
96
|
+
export function openEditor(mol: string): void {
|
|
97
|
+
let df = grok.shell.tv.grid.dataFrame;
|
|
98
|
+
let converter = new NotationConverter(df.columns.bySemType('Macromolecule'));
|
|
99
|
+
const resStr = converter.convertStringToHelm(mol, '/');
|
|
100
|
+
webEditor(resStr);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//name: Properties
|
|
94
104
|
//tags: panel, widgets
|
|
95
105
|
//input: string helmString {semType: Macromolecule}
|
|
96
106
|
//output: widget result
|
|
97
|
-
export async function
|
|
98
|
-
const lru = await getLru();
|
|
107
|
+
export async function propertiesPanel(helmString: string) {
|
|
108
|
+
//const lru = await getLru();
|
|
99
109
|
const result = lru.get(helmString).split(',');
|
|
100
110
|
return new DG.Widget(
|
|
101
111
|
ui.tableFromMap({
|
|
102
112
|
'formula': result[0].replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
|
|
103
113
|
'molecular weight': result[1],
|
|
104
114
|
'extinction coefficient': result[2],
|
|
105
|
-
'
|
|
106
|
-
'fasta': ui.wait(async () => ui.divText(await helmToFasta(helmString))),
|
|
115
|
+
/*'fasta': ui.wait(async () => ui.divText(await helmToFasta(helmString))),
|
|
107
116
|
'rna analogue sequence': ui.wait(async () => ui.divText(await helmToRNA(helmString))),
|
|
108
117
|
'smiles': ui.wait(async () => ui.divText(await helmToSmiles(helmString))),
|
|
109
|
-
//'peptide analogue sequence': ui.wait(async () => ui.divText(await helmToPeptide(helmString)))
|
|
118
|
+
//'peptide analogue sequence': ui.wait(async () => ui.divText(await helmToPeptide(helmString))),*/
|
|
110
119
|
})
|
|
111
120
|
);
|
|
112
121
|
}
|
|
113
122
|
|
|
123
|
+
//name: Molfile
|
|
124
|
+
//tags: panel, widgets
|
|
125
|
+
//input: string helmString {semType: Macromolecule}
|
|
126
|
+
//output: widget result
|
|
127
|
+
export async function molfilePanel(helmString: string) {
|
|
128
|
+
return ui.textInput('', await getMolfile(helmString));
|
|
129
|
+
}
|
|
114
130
|
|
|
115
|
-
|
|
131
|
+
|
|
132
|
+
//name: loadDialog
|
|
133
|
+
export async function loadDialog() {
|
|
116
134
|
let res = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
|
|
117
135
|
let FilesList = await ui.choiceInput('Monomer Libraries', ' ', res);
|
|
118
136
|
let grid = grok.shell.tv.grid;
|
|
@@ -134,21 +152,40 @@ export async function libraryPanel(helmColumn: DG.Column) {
|
|
|
134
152
|
//@ts-ignore
|
|
135
153
|
let loadButton = ui.button('Load Library');
|
|
136
154
|
loadButton.addEventListener('click', loadDialog);
|
|
155
|
+
//@ts-ignore
|
|
156
|
+
let filesButton = ui.button('Manage');
|
|
157
|
+
filesButton.addEventListener('click', manageFiles);
|
|
137
158
|
let list = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
|
|
138
159
|
let usedLibraries = [];
|
|
139
160
|
for (let j = 0; j <= i; j++) {
|
|
140
161
|
usedLibraries.push(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
|
|
141
162
|
}
|
|
142
163
|
let unusedLibraries = list.filter(x => !usedLibraries.includes(x));
|
|
143
|
-
return new DG.Widget(
|
|
144
|
-
ui.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
164
|
+
return new DG.Widget(ui.splitV([
|
|
165
|
+
ui.splitH([
|
|
166
|
+
ui.tableFromMap({
|
|
167
|
+
'Uploaded libraries': ui.divText(usedLibraries.toString()),
|
|
168
|
+
'Not used libraries': ui.divText(unusedLibraries.toString()),
|
|
169
|
+
})
|
|
170
|
+
]),
|
|
171
|
+
ui.splitH([
|
|
172
|
+
ui.divH([loadButton]),
|
|
173
|
+
ui.divH([filesButton]),
|
|
174
|
+
])
|
|
175
|
+
]));
|
|
150
176
|
}
|
|
151
177
|
|
|
178
|
+
//name: manageFiles
|
|
179
|
+
export async function manageFiles() {
|
|
180
|
+
const a = ui.dialog({title: 'Manage files'})
|
|
181
|
+
//@ts-ignore
|
|
182
|
+
.add(ui.fileBrowser({path: 'System:AppData/Helm/libraries'}).root)
|
|
183
|
+
.addButton('OK', () => a.close())
|
|
184
|
+
.show();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
152
189
|
async function accessServer(url: string, key: string) {
|
|
153
190
|
const params: RequestInit = {
|
|
154
191
|
method: 'GET',
|
|
@@ -220,12 +257,22 @@ function getRS(smiles: string) {
|
|
|
220
257
|
return res;
|
|
221
258
|
}
|
|
222
259
|
|
|
223
|
-
|
|
260
|
+
//name: monomerManager
|
|
261
|
+
//input: string value
|
|
262
|
+
export async function monomerManager(value: string) {
|
|
224
263
|
let df: any[];
|
|
264
|
+
let file;
|
|
265
|
+
let dfSdf;
|
|
225
266
|
if (value.endsWith('.sdf')) {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
267
|
+
const funcList: DG.Func[] = DG.Func.find({package: 'Chem', name: 'importSdf'});
|
|
268
|
+
console.debug(`Helm: initHelm() funcList.length = ${funcList.length}`);
|
|
269
|
+
if (funcList.length === 1) {
|
|
270
|
+
file = await _package.files.readAsBytes(`${LIB_PATH}${value}`);
|
|
271
|
+
dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
|
|
272
|
+
df = createJsonMonomerLibFromSdf(dfSdf[0]);
|
|
273
|
+
} else {
|
|
274
|
+
grok.shell.warning("Chem package is not installed");
|
|
275
|
+
}
|
|
229
276
|
} else {
|
|
230
277
|
const file = await _package.files.readAsText(`${LIB_PATH}${value}`);
|
|
231
278
|
df = JSON.parse(file);
|
|
@@ -257,28 +304,161 @@ export function helmColumnToSmiles(helmColumn: DG.Column) {
|
|
|
257
304
|
//todo: add column with smiles to col.dataFrame.
|
|
258
305
|
}
|
|
259
306
|
|
|
307
|
+
//name: getMolfile
|
|
308
|
+
//input: string helmString {semType: Macromolecule}
|
|
309
|
+
export async function getMolfile(helmString) {
|
|
310
|
+
return molfiles.get(helmString);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function split(s: string, sep: string) {
|
|
314
|
+
var ret = [];
|
|
315
|
+
var frag = "";
|
|
316
|
+
var parentheses = 0;
|
|
317
|
+
var bracket = 0;
|
|
318
|
+
var braces = 0;
|
|
319
|
+
var quote = 0;
|
|
320
|
+
for (var i = 0; i < s.length; ++i) {
|
|
321
|
+
var c = s.substring(i, i + 1);
|
|
322
|
+
if (c == sep && bracket == 0 && parentheses == 0 && braces == 0 && quote == 0) {
|
|
323
|
+
ret.push(frag);
|
|
324
|
+
frag = "";
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
frag += c;
|
|
328
|
+
if (quote > 0) {
|
|
329
|
+
if (c == '\\' && i + 1 < s.length) {
|
|
330
|
+
++i;
|
|
331
|
+
var c2 = s.substring(i, i + 1);
|
|
332
|
+
frag += c2;
|
|
333
|
+
c += c2;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (c == '\"') {
|
|
337
|
+
if (!(i > 0 && s.substring(i - 1, i) == '\\'))
|
|
338
|
+
quote = quote == 0 ? 1 : 0;
|
|
339
|
+
}
|
|
340
|
+
else if (c == '[')
|
|
341
|
+
++bracket;
|
|
342
|
+
else if (c == ']')
|
|
343
|
+
--bracket;
|
|
344
|
+
else if (c == '(')
|
|
345
|
+
++parentheses;
|
|
346
|
+
else if (c == ')')
|
|
347
|
+
--parentheses;
|
|
348
|
+
else if (c == '{')
|
|
349
|
+
++braces;
|
|
350
|
+
else if (c == '}')
|
|
351
|
+
--braces;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
ret.push(frag);
|
|
355
|
+
return ret;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function detachAnnotation(s: string) {
|
|
359
|
+
var ret = _detachAppendix(s, '\"');
|
|
360
|
+
if (ret.tag != null)
|
|
361
|
+
return ret;
|
|
362
|
+
|
|
363
|
+
var r = _detachAppendix(s, '\'');
|
|
364
|
+
return { tag: ret.tag, repeat: r.tag, str: r.str };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function _detachAppendix(s: string, c: string) {
|
|
368
|
+
var tag = null;
|
|
369
|
+
//@ts-ignore
|
|
370
|
+
if (scil.Utils.endswith(s, c)) {
|
|
371
|
+
var p = s.length - 1;
|
|
372
|
+
while (p > 0) {
|
|
373
|
+
p = s.lastIndexOf(c, p - 1);
|
|
374
|
+
if (p <= 0 || s.substring(p - 1, p) != '\\')
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (p > 0 && p < s.length - 1) {
|
|
379
|
+
tag = s.substring(p + 1, s.length - 1);
|
|
380
|
+
s = s.substring(0, p);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (tag != null)
|
|
384
|
+
tag = tag.replace(new RegExp("\\" + c, "g"), c);
|
|
385
|
+
return { tag: unescape(tag), str: s };
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function unescape(s: string) {
|
|
389
|
+
//@ts-ignore
|
|
390
|
+
if (scil.Utils.isNullOrEmpty(s))
|
|
391
|
+
return s;
|
|
392
|
+
|
|
393
|
+
return s.replace(/[\\]./g, function (m) {
|
|
394
|
+
switch (m) {
|
|
395
|
+
case "\\r":
|
|
396
|
+
return "\r";
|
|
397
|
+
case "\\n":
|
|
398
|
+
return "\n";
|
|
399
|
+
case "\\t":
|
|
400
|
+
return "\t";
|
|
401
|
+
default:
|
|
402
|
+
return m.substring(1);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function parseHelm(s: string) {
|
|
408
|
+
var sections = split(s, '$');
|
|
409
|
+
s = sections[0];
|
|
410
|
+
var monomers = [];
|
|
411
|
+
//@ts-ignore
|
|
412
|
+
if (!scil.Utils.isNullOrEmpty(s)) {
|
|
413
|
+
var seqs = split(s, '|');
|
|
414
|
+
for (var i = 0; i < seqs.length; ++i) {
|
|
415
|
+
var e = detachAnnotation(seqs[i]);
|
|
416
|
+
s = e.str;
|
|
417
|
+
|
|
418
|
+
var p = s.indexOf("{");
|
|
419
|
+
|
|
420
|
+
s = s.substring(p + 1);
|
|
421
|
+
p = s.indexOf('}');
|
|
422
|
+
s = s.substring(0, p);
|
|
423
|
+
|
|
424
|
+
var ss = split(s, '.');
|
|
425
|
+
for (var monomer of ss) {
|
|
426
|
+
if (monomer.includes('(') && monomer.includes(')')) {
|
|
427
|
+
var elements = monomer.replace(/[()]/g, "").split("");
|
|
428
|
+
for (var el of elements) {
|
|
429
|
+
monomers.push(el);
|
|
430
|
+
}
|
|
431
|
+
} else {
|
|
432
|
+
monomers.push(monomer);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return monomers;
|
|
438
|
+
}
|
|
439
|
+
|
|
260
440
|
//name: findMonomers
|
|
261
|
-
//input: string helmString
|
|
262
|
-
export
|
|
441
|
+
//input: string helmString
|
|
442
|
+
export function findMonomers(helmString: string) {
|
|
443
|
+
//@ts-ignore
|
|
263
444
|
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
264
|
-
const monomers = [];
|
|
265
|
-
const
|
|
266
|
-
for (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
monomerNames.push(monomers[i][k].id);
|
|
445
|
+
const monomers: any = [];
|
|
446
|
+
const monomer_names: any = [];
|
|
447
|
+
for (var i = 0; i < types.length; i++) {
|
|
448
|
+
//@ts-ignore
|
|
449
|
+
monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
|
|
450
|
+
Object.keys(monomers[i]).forEach(k => {
|
|
451
|
+
monomer_names.push(monomers[i][k].id);
|
|
272
452
|
});
|
|
273
453
|
}
|
|
274
|
-
const
|
|
275
|
-
return new Set(
|
|
454
|
+
const split_string = parseHelm(helmString);
|
|
455
|
+
return new Set(split_string.filter(val => !monomer_names.includes(val)));
|
|
276
456
|
}
|
|
277
457
|
|
|
278
458
|
class HelmCellRenderer extends DG.GridCellRenderer {
|
|
279
|
-
get name() { return '
|
|
459
|
+
get name() { return 'helm'; }
|
|
280
460
|
|
|
281
|
-
get cellType() { return '
|
|
461
|
+
get cellType() { return 'helm'; }
|
|
282
462
|
|
|
283
463
|
get defaultWidth(): number | null { return 400; }
|
|
284
464
|
|
|
@@ -287,17 +467,55 @@ class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
287
467
|
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
288
468
|
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle
|
|
289
469
|
) {
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
470
|
+
const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
|
|
471
|
+
const undefinedColor = 'rgb(100,100,100)';
|
|
472
|
+
const grayColor = '#808080';
|
|
473
|
+
const monomers = findMonomers(gridCell.cell.value);
|
|
474
|
+
if (monomers.size == 0) {
|
|
475
|
+
const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
|
|
476
|
+
host.setAttribute('dataformat', 'helm');
|
|
477
|
+
host.setAttribute('data', gridCell.cell.value);
|
|
478
|
+
gridCell.element = host;
|
|
479
|
+
//@ts-ignore
|
|
480
|
+
const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
|
|
481
|
+
const formula = canvas.getFormula(true);
|
|
482
|
+
if (!formula) {
|
|
483
|
+
gridCell.element = ui.divText(gridCell.cell.value, {style: {color: 'red'}});
|
|
484
|
+
}
|
|
485
|
+
const molWeight = Math.round(canvas.getMolWeight() * 100) / 100;
|
|
486
|
+
const coef = Math.round(canvas.getExtinctionCoefficient(true) * 100) / 100;
|
|
487
|
+
const molfile = canvas.getMolfile();
|
|
488
|
+
const result = formula + ', ' + molWeight + ', ' + coef;
|
|
489
|
+
lru.set(gridCell.cell.value, result);
|
|
490
|
+
molfiles.set(gridCell.cell.value, molfile);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (monomers.size > 0) {
|
|
494
|
+
w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
495
|
+
g.save();
|
|
496
|
+
g.beginPath();
|
|
497
|
+
g.rect(x, y, w, h);
|
|
498
|
+
g.clip();
|
|
499
|
+
g.font = '12px monospace';
|
|
500
|
+
g.textBaseline = 'top';
|
|
501
|
+
let x1 = x;
|
|
502
|
+
const s: string = gridCell.cell.value ?? '';
|
|
503
|
+
let subParts: string[] = parseHelm(s);
|
|
504
|
+
subParts.forEach((amino, index) => {
|
|
505
|
+
let color = monomers.has(amino) ? 'red' : grayColor;
|
|
506
|
+
g.fillStyle = undefinedColor;
|
|
507
|
+
let last = index === subParts.length - 1;
|
|
508
|
+
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, '/', last);
|
|
509
|
+
});
|
|
510
|
+
g.restore();
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
302
513
|
}
|
|
303
514
|
}
|
|
515
|
+
|
|
516
|
+
//name: getMonomerLib
|
|
517
|
+
//input: string type
|
|
518
|
+
//output: string monomerSetJSON
|
|
519
|
+
export function getMonomerLib(type: string): string {
|
|
520
|
+
return JSON.stringify(scil.helm.Monomers.getMonomerSet(type));
|
|
521
|
+
}
|