@datagrok/sequence-translator 1.1.4 → 1.2.0
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 +6 -0
- 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/img/icons/calculator.png +0 -0
- package/img/icons/pattern.png +0 -0
- package/img/icons/structure.png +0 -0
- package/img/icons/toolkit.png +0 -0
- package/img/icons/translator.png +0 -0
- package/package.json +1 -1
- package/src/demo/demo-st-ui.ts +26 -36
- package/src/model/helpers.ts +17 -0
- package/src/model/sequence-to-structure-utils/monomer-code-parser.ts +2 -5
- package/src/model/sequence-to-structure-utils/sdf-tab.ts +1 -1
- package/src/model/sequence-to-structure-utils/sequence-to-molfile.ts +20 -3
- package/src/package.ts +57 -37
- package/src/plugins/const.ts +4 -0
- package/src/plugins/mermade.ts +48 -0
- package/src/view/app-ui.ts +193 -0
- package/src/view/{tabs/axolabs.ts → apps/oligo-pattern.ts} +106 -26
- package/src/view/{tabs/sdf.ts → apps/oligo-structure.ts} +13 -14
- package/src/view/{tabs/main.ts → apps/oligo-translator.ts} +15 -11
- package/src/view/const/ui.ts +14 -0
- package/src/view/style/pattern-app.css +1 -0
- package/src/view/style/structure-app.css +39 -0
- package/src/view/style/translator-app.css +46 -0
- package/src/view/utils/colored-input/colored-text-input.ts +7 -6
- package/src/view/utils/molecule-img.ts +21 -10
- package/src/view/utils/router.ts +71 -0
- package/src/demo/handle-error.ts +0 -12
- package/src/view/const/view.ts +0 -10
- package/src/view/css/axolabs-tab.css +0 -1
- package/src/view/css/main-tab.css +0 -46
- package/src/view/css/sdf-tab.css +0 -39
- package/src/view/view.ts +0 -127
- /package/src/view/const/{main-tab.ts → oligo-translator.ts} +0 -0
- /package/src/view/{css → style}/colored-text-input.css +0 -0
|
@@ -18,7 +18,7 @@ import $ from 'cash-dom';
|
|
|
18
18
|
type BooleanInput = DG.InputBase<boolean | null>;
|
|
19
19
|
type StringInput = DG.InputBase<string | null>;
|
|
20
20
|
|
|
21
|
-
export class
|
|
21
|
+
export class PatternLayoutHandler {
|
|
22
22
|
get htmlDivElement() {
|
|
23
23
|
function updateModification(strand: string) {
|
|
24
24
|
modificationItems[strand].innerHTML = '';
|
|
@@ -79,11 +79,12 @@ export class AxolabsTabUI {
|
|
|
79
79
|
updateInputExamples();
|
|
80
80
|
updateOutputExamples();
|
|
81
81
|
} else {
|
|
82
|
-
ui.dialog('
|
|
82
|
+
ui.dialog('Out of range')
|
|
83
83
|
.add(ui.divText('Sequence length should be less than ' +
|
|
84
84
|
MAX_SEQUENCE_LENGTH.toString() + ' due to UI constrains.'))
|
|
85
|
-
.
|
|
86
|
-
.
|
|
85
|
+
.onOK(()=> {Object.values(strandLengthInput).every((input)=> input.value = 34)})
|
|
86
|
+
.onCancel(()=> {Object.values(strandLengthInput).every((input)=> input.value = 34)})
|
|
87
|
+
.showModal(false);
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -294,7 +295,8 @@ export class AxolabsTabUI {
|
|
|
294
295
|
loadPattern.root.append(patternListChoiceInput.input);
|
|
295
296
|
loadPattern.root.append(loadPattern.input);
|
|
296
297
|
// @ts-ignore
|
|
297
|
-
loadPattern.input.style.maxWidth = '
|
|
298
|
+
loadPattern.input.style.maxWidth = '120px';
|
|
299
|
+
loadPattern.input.style.marginLeft = '12px';
|
|
298
300
|
loadPattern.setTooltip('Apply Existing Pattern');
|
|
299
301
|
|
|
300
302
|
loadPatternDiv.innerHTML = '';
|
|
@@ -315,6 +317,7 @@ export class AxolabsTabUI {
|
|
|
315
317
|
], 'ui-input-options'),
|
|
316
318
|
);
|
|
317
319
|
});
|
|
320
|
+
patternListChoiceInput.input.style.maxWidth = '142px';
|
|
318
321
|
loadPattern.root.append(patternListChoiceInput.input);
|
|
319
322
|
loadPattern.root.append(loadPattern.input);
|
|
320
323
|
// @ts-ignore
|
|
@@ -400,6 +403,12 @@ export class AxolabsTabUI {
|
|
|
400
403
|
updatePto(v);
|
|
401
404
|
updateOutputExamples();
|
|
402
405
|
});
|
|
406
|
+
fullyPto.captionLabel.classList.add('ui-label-right');
|
|
407
|
+
fullyPto.captionLabel.style.textAlign = 'left';
|
|
408
|
+
fullyPto.captionLabel.style.maxWidth = '100px';
|
|
409
|
+
fullyPto.captionLabel.style.maxWidth = '100px';
|
|
410
|
+
fullyPto.captionLabel.style.minWidth = '40px';
|
|
411
|
+
fullyPto.captionLabel.style.width = 'auto';
|
|
403
412
|
|
|
404
413
|
const maxStrandLength = Object.fromEntries(STRANDS.map(
|
|
405
414
|
(strand) => [strand, DEFAULT_SEQUENCE_LENGTH]
|
|
@@ -432,7 +441,7 @@ export class AxolabsTabUI {
|
|
|
432
441
|
));
|
|
433
442
|
const inputExample = Object.fromEntries(STRANDS.map(
|
|
434
443
|
(strand) => [strand, ui.textInput(
|
|
435
|
-
|
|
444
|
+
``, generateExample(strandLengthInput[strand].value!, sequenceBase.value!))
|
|
436
445
|
]));
|
|
437
446
|
|
|
438
447
|
// todo: rename to strandColumnInput
|
|
@@ -442,12 +451,22 @@ export class AxolabsTabUI {
|
|
|
442
451
|
strandVar[strand] = colName;
|
|
443
452
|
});
|
|
444
453
|
inputStrandColumnDiv[strand].append(input.root);
|
|
454
|
+
//input.addPostfix(``);
|
|
445
455
|
return [strand, input];
|
|
446
456
|
}));
|
|
447
457
|
|
|
448
458
|
const firstPto = Object.fromEntries(STRANDS.map((strand) => {
|
|
449
459
|
const input = ui.boolInput(`First ${strand} PTO`, fullyPto.value!, () => updateSvgScheme());
|
|
450
460
|
input.setTooltip(`ps linkage before first nucleotide of ${STRAND_NAME[strand].toLowerCase()}`);
|
|
461
|
+
|
|
462
|
+
input.captionLabel.classList.add('ui-label-right');
|
|
463
|
+
input.captionLabel.style.textAlign = 'left';
|
|
464
|
+
input.captionLabel.style.maxWidth = '100px';
|
|
465
|
+
input.captionLabel.style.minWidth = '40px';
|
|
466
|
+
input.captionLabel.style.width = 'auto';
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
451
470
|
return [strand, input];
|
|
452
471
|
}));
|
|
453
472
|
|
|
@@ -464,14 +483,17 @@ export class AxolabsTabUI {
|
|
|
464
483
|
}));
|
|
465
484
|
|
|
466
485
|
const outputExample = Object.fromEntries(STRANDS.map((strand) => {
|
|
467
|
-
const input = ui.textInput('
|
|
486
|
+
const input = ui.textInput('', translateSequence(
|
|
468
487
|
inputExample[strand].value, baseInputsObject[strand], ptoLinkages[strand], terminalModification[strand][THREE_PRIME],terminalModification[strand][FIVE_PRIME], firstPto[strand].value!
|
|
469
488
|
));
|
|
489
|
+
input.input.style.minWidth = 'none';
|
|
490
|
+
input.input.style.flexGrow = '1';
|
|
491
|
+
$(input.root.lastChild).css('height', 'auto');
|
|
470
492
|
return [strand, input];
|
|
471
493
|
}));
|
|
472
494
|
|
|
473
495
|
const modificationSection = Object.fromEntries(STRANDS.map((strand) => {
|
|
474
|
-
const panel = ui.
|
|
496
|
+
const panel = ui.block([
|
|
475
497
|
ui.h1(`${STRAND_NAME[strand]}`),
|
|
476
498
|
ui.divH([
|
|
477
499
|
ui.div([ui.divText('#')], {style: {width: '20px'}})!,
|
|
@@ -484,13 +506,15 @@ export class AxolabsTabUI {
|
|
|
484
506
|
}));
|
|
485
507
|
|
|
486
508
|
STRANDS.forEach((s) => {
|
|
509
|
+
|
|
487
510
|
inputExample[s].input.style.resize = 'none';
|
|
488
|
-
inputExample[s].input.style.minWidth = EXAMPLE_MIN_WIDTH;
|
|
511
|
+
//inputExample[s].input.style.minWidth = EXAMPLE_MIN_WIDTH;
|
|
489
512
|
outputExample[s].input.style.resize = 'none';
|
|
490
|
-
outputExample[s].input.
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
outputExample[s].input.
|
|
513
|
+
//outputExample[s].input.styl
|
|
514
|
+
inputExample[s].input.style.minWidth = 'none';
|
|
515
|
+
inputExample[s].input.style.flexGrow = '1';
|
|
516
|
+
outputExample[s].input.style.minWidth = 'none';
|
|
517
|
+
outputExample[s].input.style.flexGrow = '1';
|
|
494
518
|
let options = ui.div([
|
|
495
519
|
ui.button(ui.iconFA('copy', () => {}), () => {
|
|
496
520
|
navigator.clipboard.writeText(outputExample[s].value).then(() =>
|
|
@@ -508,7 +532,7 @@ export class AxolabsTabUI {
|
|
|
508
532
|
const asExampleDiv = ui.div([], 'ui-form ui-form-wide');
|
|
509
533
|
const appAxolabsDescription = ui.div([]);
|
|
510
534
|
const loadPatternDiv = ui.div([]);
|
|
511
|
-
const asModificationDiv = ui.
|
|
535
|
+
const asModificationDiv = ui.form([]);
|
|
512
536
|
const isEnumerateModificationsDiv = ui.divH([
|
|
513
537
|
ui.boolInput(defaultBase, true, (v: boolean) => {
|
|
514
538
|
if (v) {
|
|
@@ -591,6 +615,7 @@ export class AxolabsTabUI {
|
|
|
591
615
|
.show();
|
|
592
616
|
}
|
|
593
617
|
});
|
|
618
|
+
saveAs.addOptions(savePatternButton);
|
|
594
619
|
|
|
595
620
|
const convertSequenceButton = ui.bigButton('Convert', () => {
|
|
596
621
|
const condition = [true, createAsStrand.value];
|
|
@@ -649,8 +674,26 @@ export class AxolabsTabUI {
|
|
|
649
674
|
]);
|
|
650
675
|
inputsSection.classList.add('ui-form');
|
|
651
676
|
|
|
652
|
-
const downloadButton = ui.
|
|
653
|
-
{backgroundColor: 'white'}));
|
|
677
|
+
const downloadButton = ui.link('Download', () => svg.saveSvgAsPng(document.getElementById('mySvg'), saveAs.value,
|
|
678
|
+
{backgroundColor: 'white'}), 'Download pattern as PNG image', '');
|
|
679
|
+
|
|
680
|
+
const editPattern = ui.link('Edit pattern', ()=>{
|
|
681
|
+
ui.dialog('Edit patter')
|
|
682
|
+
.add(ui.divV([
|
|
683
|
+
ui.h1('PTO'),
|
|
684
|
+
ui.divH([
|
|
685
|
+
fullyPto.root,
|
|
686
|
+
firstPto[SS].root,
|
|
687
|
+
firstPto[AS].root,
|
|
688
|
+
], {style:{gap:'12px'}})
|
|
689
|
+
]))
|
|
690
|
+
.add(ui.divH([
|
|
691
|
+
modificationSection[SS],
|
|
692
|
+
modificationSection[AS],
|
|
693
|
+
], {style:{gap:'24px'}}))
|
|
694
|
+
.onOK(()=>{grok.shell.info('Saved')})
|
|
695
|
+
.show()
|
|
696
|
+
}, 'Edit pattern', '');
|
|
654
697
|
|
|
655
698
|
const mainSection = ui.panel([
|
|
656
699
|
ui.block([
|
|
@@ -672,7 +715,7 @@ export class AxolabsTabUI {
|
|
|
672
715
|
loadPatternDiv,
|
|
673
716
|
saveAs.root,
|
|
674
717
|
ui.buttonsInput([
|
|
675
|
-
savePatternButton,
|
|
718
|
+
//savePatternButton,
|
|
676
719
|
]),
|
|
677
720
|
], 'ui-form'),
|
|
678
721
|
ui.block([
|
|
@@ -702,18 +745,55 @@ export class AxolabsTabUI {
|
|
|
702
745
|
ui.divText('This will add the result column(s) to the right of the table'),
|
|
703
746
|
], 'Create and apply Axolabs translation patterns.',
|
|
704
747
|
);
|
|
748
|
+
strandLengthInput[SS].addCaption('Length');
|
|
705
749
|
|
|
706
750
|
return ui.splitH([
|
|
707
|
-
ui.div([
|
|
708
|
-
appAxolabsDescription,
|
|
709
|
-
mainSection!,
|
|
710
|
-
])!,
|
|
711
751
|
ui.box(
|
|
752
|
+
ui.div([
|
|
753
|
+
ui.h1('Pattern'),
|
|
754
|
+
createAsStrand.root,
|
|
755
|
+
strandLengthInput[SS],
|
|
756
|
+
strandLengthInput[AS],
|
|
757
|
+
sequenceBase.root,
|
|
758
|
+
comment.root,
|
|
759
|
+
loadPatternDiv,
|
|
760
|
+
saveAs.root,
|
|
761
|
+
ui.h1('Convert'),
|
|
762
|
+
tables.root,
|
|
763
|
+
inputStrandColumn[SS],
|
|
764
|
+
inputStrandColumn[AS],
|
|
765
|
+
inputIdColumn.root,
|
|
766
|
+
ui.buttonsInput([
|
|
767
|
+
convertSequenceButton,
|
|
768
|
+
]),
|
|
769
|
+
], 'ui-form')
|
|
770
|
+
, {style:{maxWidth:'450px'}}),
|
|
771
|
+
ui.panel([
|
|
772
|
+
svgDiv,
|
|
773
|
+
isEnumerateModificationsDiv,
|
|
712
774
|
ui.divH([
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
]
|
|
716
|
-
|
|
717
|
-
|
|
775
|
+
downloadButton,
|
|
776
|
+
editPattern
|
|
777
|
+
], {style:{gap:'12px', marginTop:'12px'}}),
|
|
778
|
+
ui.divH([
|
|
779
|
+
ui.divV([
|
|
780
|
+
ui.h1('Sense strand'),
|
|
781
|
+
inputExample[SS].root,
|
|
782
|
+
outputExample[SS].root,
|
|
783
|
+
], 'ui-block'),
|
|
784
|
+
ui.divV([
|
|
785
|
+
ui.h1('Anti sense'),
|
|
786
|
+
inputExample[AS],
|
|
787
|
+
outputExample[AS]
|
|
788
|
+
], 'ui-block'),
|
|
789
|
+
], {style:{gap:'24px', marginTop:'24px'}}),
|
|
790
|
+
ui.h1('Additional modifications'),
|
|
791
|
+
ui.form([
|
|
792
|
+
terminalModification[SS][FIVE_PRIME],
|
|
793
|
+
terminalModification[SS][THREE_PRIME],
|
|
794
|
+
]),
|
|
795
|
+
asModificationDiv,
|
|
796
|
+
], {style: {overflowX: 'scroll', padding:'12px 24px'}})
|
|
797
|
+
], {}, true)
|
|
718
798
|
}
|
|
719
799
|
}
|
|
@@ -4,7 +4,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
6
|
import * as rxjs from 'rxjs';
|
|
7
|
-
import '../
|
|
7
|
+
import '../style/structure-app.css';
|
|
8
8
|
import $ from 'cash-dom';
|
|
9
9
|
|
|
10
10
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
@@ -15,7 +15,6 @@ import {getLinkedMolfile, saveSdf} from '../../model/sequence-to-structure-utils
|
|
|
15
15
|
import {ColoredTextInput} from '../utils/colored-input/colored-text-input';
|
|
16
16
|
import {MoleculeImage} from '../utils/molecule-img';
|
|
17
17
|
import {StrandData} from '../../model/sequence-to-structure-utils/sdf-tab';
|
|
18
|
-
import {DEFAULT_AXOLABS_INPUT} from '../const/view';
|
|
19
18
|
|
|
20
19
|
const enum DIRECTION {
|
|
21
20
|
STRAIGHT = '5′ → 3′',
|
|
@@ -23,7 +22,7 @@ const enum DIRECTION {
|
|
|
23
22
|
};
|
|
24
23
|
const STRANDS = ['ss', 'as', 'as2'] as const;
|
|
25
24
|
|
|
26
|
-
export class
|
|
25
|
+
export class StructureLayoutHandler {
|
|
27
26
|
constructor() {
|
|
28
27
|
this.onInput = new rxjs.Subject<string>();
|
|
29
28
|
this.onInvalidInput = new rxjs.Subject<string>();
|
|
@@ -39,7 +38,7 @@ export class SdfTabUI {
|
|
|
39
38
|
STRANDS.map((key) => [key, false])
|
|
40
39
|
);
|
|
41
40
|
this.moleculeImgDiv = ui.block([]);
|
|
42
|
-
$(this.moleculeImgDiv).addClass('st-
|
|
41
|
+
$(this.moleculeImgDiv).addClass('st-structure-mol-img');
|
|
43
42
|
|
|
44
43
|
DG.debounce<string>(this.onInput, 300).subscribe(async () => {
|
|
45
44
|
await this.updateMoleculeImg();
|
|
@@ -63,10 +62,10 @@ export class SdfTabUI {
|
|
|
63
62
|
const boolInputsAndButton = this.getBoolInputsAndButton();
|
|
64
63
|
await this.updateMoleculeImg();
|
|
65
64
|
const bottomDiv = ui.divH([boolInputsAndButton, this.moleculeImgDiv]);
|
|
66
|
-
$(bottomDiv).addClass('st-
|
|
65
|
+
$(bottomDiv).addClass('st-structure-bottom');
|
|
67
66
|
|
|
68
67
|
const sdfTabBody = ui.divV([tableLayout, bottomDiv]);
|
|
69
|
-
$(sdfTabBody).addClass('st-
|
|
68
|
+
$(sdfTabBody).addClass('st-structure-body');
|
|
70
69
|
|
|
71
70
|
return sdfTabBody;
|
|
72
71
|
}
|
|
@@ -83,7 +82,7 @@ export class SdfTabUI {
|
|
|
83
82
|
const boolInputsAndButtonArray = [this.saveAllStrandsInput.root, this.useChiralInput.root, saveButton];
|
|
84
83
|
const boolInputsAndButton = ui.divV(boolInputsAndButtonArray);
|
|
85
84
|
for (const item of boolInputsAndButtonArray)
|
|
86
|
-
$(item).addClass('st-
|
|
85
|
+
$(item).addClass('st-structure-bool-button-block');
|
|
87
86
|
return boolInputsAndButton;
|
|
88
87
|
}
|
|
89
88
|
|
|
@@ -138,16 +137,16 @@ export class SdfTabUI {
|
|
|
138
137
|
|
|
139
138
|
for (const strand of STRANDS) {
|
|
140
139
|
let element = label[strand].parentElement!;
|
|
141
|
-
element.classList.add('st-
|
|
140
|
+
element.classList.add('st-structure-input-form');
|
|
142
141
|
// the following line is necessary because otherwise overridden by
|
|
143
142
|
// d4-item-table class
|
|
144
143
|
$(element).css('padding-top', '3px');
|
|
145
144
|
|
|
146
145
|
element = directionChoiceInput[strand].root.parentElement!;
|
|
147
|
-
element.classList.add('st-
|
|
146
|
+
element.classList.add('st-structure-input-form', 'st-structure-direction-choice');
|
|
148
147
|
|
|
149
148
|
element = this.inputBase[strand].root.parentElement!;
|
|
150
|
-
element.classList.add('st-
|
|
149
|
+
element.classList.add('st-structure-text-input-td');
|
|
151
150
|
}
|
|
152
151
|
return tableLayout;
|
|
153
152
|
}
|
|
@@ -165,10 +164,10 @@ export class SdfTabUI {
|
|
|
165
164
|
}
|
|
166
165
|
|
|
167
166
|
private getMolfile(ss: StrandData, as: StrandData, as2: StrandData): string {
|
|
168
|
-
if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
167
|
+
// if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
|
|
168
|
+
// this.onInvalidInput.next();
|
|
169
|
+
// return '';
|
|
170
|
+
// }
|
|
172
171
|
|
|
173
172
|
return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!);
|
|
174
173
|
}
|
|
@@ -4,7 +4,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
6
|
import * as rxjs from 'rxjs';
|
|
7
|
-
import '../
|
|
7
|
+
import '../style/translator-app.css';
|
|
8
8
|
import $ from 'cash-dom';
|
|
9
9
|
|
|
10
10
|
import {highlightInvalidSubsequence} from '../utils/colored-input/input-painters';
|
|
@@ -13,18 +13,23 @@ import {SequenceToMolfileConverter} from '../../model/sequence-to-structure-util
|
|
|
13
13
|
import {getTranslatedSequences} from '../../model/format-translation/conversion-utils';
|
|
14
14
|
import {MoleculeImage} from '../utils/molecule-img';
|
|
15
15
|
import {download} from '../../model/helpers';
|
|
16
|
-
import {SEQUENCE_COPIED_MSG, SEQ_TOOLTIP_MSG} from '../const/
|
|
17
|
-
import {DEFAULT_AXOLABS_INPUT} from '../const/
|
|
16
|
+
import {SEQUENCE_COPIED_MSG, SEQ_TOOLTIP_MSG} from '../const/oligo-translator';
|
|
17
|
+
import {DEFAULT_AXOLABS_INPUT} from '../const/ui';
|
|
18
18
|
import {FormatDetector} from '../../model/parsing-validation/format-detector';
|
|
19
19
|
import {SequenceValidator} from '../../model/parsing-validation/sequence-validator';
|
|
20
20
|
import {FormatConverter} from '../../model/format-translation/format-converter';
|
|
21
21
|
import {codesToHelmDictionary} from '../../model/data-loading-utils/json-loader';
|
|
22
22
|
import {DEFAULT_FORMATS} from '../../model/const';
|
|
23
23
|
|
|
24
|
-
export class
|
|
24
|
+
export class TranslatorLayoutHandler {
|
|
25
25
|
constructor() {
|
|
26
26
|
const INPUT_FORMATS = Object.keys(codesToHelmDictionary).concat(DEFAULT_FORMATS.HELM);
|
|
27
|
-
this.moleculeImgDiv = ui.
|
|
27
|
+
this.moleculeImgDiv = ui.div([]);
|
|
28
|
+
this.moleculeImgDiv.className = 'mol-host';
|
|
29
|
+
this.moleculeImgDiv.style.border = '1px solid var(--grey-2)';
|
|
30
|
+
this.moleculeImgDiv.style.borderRadius = '1px';
|
|
31
|
+
this.moleculeImgDiv.style.marginTop = '12px';
|
|
32
|
+
|
|
28
33
|
this.outputTableDiv = ui.div([]);
|
|
29
34
|
this.formatChoiceInput = ui.choiceInput('', DEFAULT_FORMATS.HELM, INPUT_FORMATS, async () => {
|
|
30
35
|
this.format = this.formatChoiceInput.value;
|
|
@@ -76,7 +81,7 @@ export class MainTabUI {
|
|
|
76
81
|
const upperBlock = ui.table(
|
|
77
82
|
[inputTableRow], (item) => [item.format, item.textInput]
|
|
78
83
|
);
|
|
79
|
-
upperBlock.classList.add('st-
|
|
84
|
+
upperBlock.classList.add('st-translator-input-table');
|
|
80
85
|
|
|
81
86
|
const outputTable = ui.block([
|
|
82
87
|
this.outputTableDiv,
|
|
@@ -85,11 +90,11 @@ export class MainTabUI {
|
|
|
85
90
|
]);
|
|
86
91
|
|
|
87
92
|
const mainTabBody = ui.box(
|
|
88
|
-
ui.
|
|
93
|
+
ui.panel([
|
|
89
94
|
upperBlock,
|
|
90
95
|
outputTable,
|
|
91
|
-
this.moleculeImgDiv
|
|
92
|
-
],
|
|
96
|
+
ui.block([ui.box(this.moleculeImgDiv)])
|
|
97
|
+
]),
|
|
93
98
|
);
|
|
94
99
|
|
|
95
100
|
this.formatChoiceInput.value = this.format;
|
|
@@ -135,7 +140,7 @@ export class MainTabUI {
|
|
|
135
140
|
const outputTable = ui.table(tableRows, (item) => [item.format, item.sequence], ['FORMAT', 'SEQUENCE']);
|
|
136
141
|
|
|
137
142
|
this.outputTableDiv.append(outputTable);
|
|
138
|
-
this.outputTableDiv.classList.add('st-
|
|
143
|
+
this.outputTableDiv.classList.add('st-translator-output-table');
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
private async updateMolImg(): Promise<void> {
|
|
@@ -144,7 +149,6 @@ export class MainTabUI {
|
|
|
144
149
|
const molImgObj = new MoleculeImage(this.molfile);
|
|
145
150
|
await molImgObj.drawMolecule(this.moleculeImgDiv, canvasWidth, canvasHeight);
|
|
146
151
|
// should the canvas be returned from the above function?
|
|
147
|
-
$(this.moleculeImgDiv).find('canvas').css('float', 'inherit');
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
// todo: sort mehtods
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const enum TAB {
|
|
2
|
+
TRANSLATOR = 'TRANSLATOR',
|
|
3
|
+
PATTERN = 'PATTERN',
|
|
4
|
+
STRUCTRE = 'STRUCTURE'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const enum APP {
|
|
8
|
+
COMBINED = 'Oligo Toolkit',
|
|
9
|
+
TRANSLATOR = 'Oligo Translator',
|
|
10
|
+
PATTERN = 'Oligo Pattern',
|
|
11
|
+
STRUCTRE = 'Oligo Structure',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const DEFAULT_AXOLABS_INPUT = 'Afcgacsu';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/* Naming convention: class names should begin with st and app name to avoid naming collitions */
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* Naming convention: class names should begin with st and app name to avoid naming collitions */
|
|
2
|
+
|
|
3
|
+
.st-structure-body {
|
|
4
|
+
padding-right: 20px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.st-structure-input-form {
|
|
8
|
+
text-align: right;
|
|
9
|
+
vertical-align: top;
|
|
10
|
+
min-width: 95px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.st-structure-direction-choice label {
|
|
14
|
+
min-width: 100px;
|
|
15
|
+
float: right;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.st-structure-direction-choice div {
|
|
19
|
+
justify-content: right;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.st-structure-text-input-td { /* Style for td containing textarea */
|
|
23
|
+
width: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.st-structure-mol-img {
|
|
27
|
+
margin-right: 30px;
|
|
28
|
+
float: right;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.st-structure-bool-button-block {
|
|
32
|
+
justify-content: right;
|
|
33
|
+
margin-bottom: 10px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.st-structure-bottom {
|
|
37
|
+
flex-direction: row-reverse;
|
|
38
|
+
padding-top: 20px;
|
|
39
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* Naming convention: class names should begin with st and app name to avoid naming collitions */
|
|
2
|
+
.st-translator-input-table {
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.st-translator-input-table td:has(textarea) {
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding-right: 20px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.st-translator-input-table td:has(select) {
|
|
12
|
+
min-width: 120px;
|
|
13
|
+
vertical-align: top;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.st-translator-output-table {
|
|
17
|
+
margin-top: 20px;
|
|
18
|
+
margin-right: 20px;
|
|
19
|
+
margin-bottom: 10px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.st-translator-output-table table {
|
|
23
|
+
width: 100%;
|
|
24
|
+
table-layout: fixed;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* .st-translator-output-table table tbody tr td { */
|
|
28
|
+
/* max-width: 20%; */
|
|
29
|
+
/* } */
|
|
30
|
+
|
|
31
|
+
.st-translator-output-table td {
|
|
32
|
+
padding-top: 6px;
|
|
33
|
+
padding-bottom: 6px;
|
|
34
|
+
}
|
|
35
|
+
.st-translator-output-table tr:nth-child(even) {
|
|
36
|
+
background-color: var(--grey-1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.st-translator-output-table td:nth-child(odd) {
|
|
40
|
+
width: 120px;
|
|
41
|
+
vertical-align: top;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.st-translator-output-table td a {
|
|
45
|
+
overflow-wrap: break-word;
|
|
46
|
+
}
|
|
@@ -7,19 +7,18 @@ import * as DG from 'datagrok-api/dg';
|
|
|
7
7
|
import $ from 'cash-dom';
|
|
8
8
|
|
|
9
9
|
// inner dependencies
|
|
10
|
-
import '../../
|
|
10
|
+
import '../../style/colored-text-input.css';
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
/** Class for colorizing input in the textarea of DG.InputBase. */
|
|
14
14
|
export class ColoredTextInput {
|
|
15
15
|
constructor(
|
|
16
16
|
private textInputBase: DG.InputBase<string>,
|
|
17
|
-
|
|
17
|
+
/** Divide input value into an array of spans, each with its own text color, use -webkit-text-fill-color. */
|
|
18
|
+
private painter: (str: string) => HTMLSpanElement[],
|
|
18
19
|
/** Resize, no scrolls */
|
|
19
20
|
resizeable: boolean = true
|
|
20
21
|
) {
|
|
21
|
-
this.textInputBase = textInputBase;
|
|
22
|
-
this.painter = painter;
|
|
23
22
|
$(this.root).addClass('colored-text-input');
|
|
24
23
|
if (resizeable) {
|
|
25
24
|
// make input field automatically resizeable
|
|
@@ -39,13 +38,15 @@ export class ColoredTextInput {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
private highlights: HTMLDivElement;
|
|
42
|
-
/** Divide input value into an array of spans, each with its own text color, use -webkit-text-fill-color. */
|
|
43
|
-
private painter: (str: string) => HTMLSpanElement[];
|
|
44
41
|
|
|
45
42
|
get textArea() {
|
|
46
43
|
return this.textInputBase.root.getElementsByTagName('textarea').item(0);
|
|
47
44
|
};
|
|
48
45
|
|
|
46
|
+
get inputBase() {
|
|
47
|
+
return this.textInputBase;
|
|
48
|
+
}
|
|
49
|
+
|
|
49
50
|
get root() { return this.textInputBase.root; };
|
|
50
51
|
|
|
51
52
|
private colorize() {
|
|
@@ -59,11 +59,10 @@ export class MoleculeImage {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
private async zoomIn(): Promise<void> {
|
|
62
|
-
const dialog = ui.dialog('Molecule');
|
|
62
|
+
const dialog = ui.dialog({title: 'Molecule', showFooter:false});
|
|
63
63
|
const dialogDivStyle = {
|
|
64
64
|
overflowX: 'scroll',
|
|
65
65
|
};
|
|
66
|
-
const dialogDiv = ui.div([], {style: dialogDivStyle});
|
|
67
66
|
|
|
68
67
|
const height = $(window).height() * 0.7;
|
|
69
68
|
const molDimensions = this.getMoleculeDimensions();
|
|
@@ -75,9 +74,14 @@ export class MoleculeImage {
|
|
|
75
74
|
|
|
76
75
|
const dialogCanvas = ui.canvas(dialogCanvasWidth, dialogCanvasHeight);
|
|
77
76
|
await this.drawMolBlockOnCanvas(dialogCanvas);
|
|
78
|
-
|
|
79
|
-
dialogDiv.
|
|
77
|
+
|
|
78
|
+
const dialogDiv = ui.block([dialogCanvas], {style: dialogDivStyle});
|
|
80
79
|
dialog.add(dialogDiv).showModal(true);
|
|
80
|
+
|
|
81
|
+
$(dialog.root).find('.d4-dialog-contents').removeClass('ui-form');
|
|
82
|
+
$(dialog.root).find('.d4-dialog-contents').removeClass('ui-panel');
|
|
83
|
+
$(dialog.root).find('.d4-dialog-contents').addClass('ui-box');
|
|
84
|
+
$(dialog.root).find('.d4-dialog-contents').css('padding', '0');
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
public async drawMolecule(
|
|
@@ -91,16 +95,23 @@ export class MoleculeImage {
|
|
|
91
95
|
// Draw zoomed-out molecule
|
|
92
96
|
canvas.style.width = `${canvasWidth}px`;
|
|
93
97
|
canvas.style.height = `${canvasHeight}px`;
|
|
98
|
+
canvas.style.cursor = 'zoom-in';
|
|
99
|
+
/*
|
|
94
100
|
canvas.style.borderStyle = 'solid';
|
|
95
|
-
canvas.style.
|
|
101
|
+
canvas.style.borderRadius = '1px';
|
|
102
|
+
canvas.style.borderColor = 'var(--grey-2)';
|
|
96
103
|
canvas.style.borderWidth = 'thin';
|
|
104
|
+
*/
|
|
97
105
|
this.drawMolBlockOnCanvas(canvas);
|
|
98
106
|
|
|
99
107
|
// Dialog with zoomed-in molecule
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
canvas.addEventListener('click', async () => {
|
|
109
|
+
await this.zoomIn();
|
|
110
|
+
});
|
|
111
|
+
//$(canvas).on('click', async () => { await this.zoomIn(); });
|
|
112
|
+
//$(canvas).on('mouseover', () => $(canvas).css('cursor', 'grab')); // for some reason 'zoom-in' value wouldn't work
|
|
113
|
+
//$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
114
|
+
|
|
115
|
+
moleculeImgDiv.append(ui.tooltip.bind(canvas,'Click to zoom'));
|
|
105
116
|
}
|
|
106
117
|
}
|