@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/package-test.js +1 -1
  3. package/dist/package-test.js.map +1 -1
  4. package/dist/package.js +1 -1
  5. package/dist/package.js.map +1 -1
  6. package/img/icons/calculator.png +0 -0
  7. package/img/icons/pattern.png +0 -0
  8. package/img/icons/structure.png +0 -0
  9. package/img/icons/toolkit.png +0 -0
  10. package/img/icons/translator.png +0 -0
  11. package/package.json +1 -1
  12. package/src/demo/demo-st-ui.ts +26 -36
  13. package/src/model/helpers.ts +17 -0
  14. package/src/model/sequence-to-structure-utils/monomer-code-parser.ts +2 -5
  15. package/src/model/sequence-to-structure-utils/sdf-tab.ts +1 -1
  16. package/src/model/sequence-to-structure-utils/sequence-to-molfile.ts +20 -3
  17. package/src/package.ts +57 -37
  18. package/src/plugins/const.ts +4 -0
  19. package/src/plugins/mermade.ts +48 -0
  20. package/src/view/app-ui.ts +193 -0
  21. package/src/view/{tabs/axolabs.ts → apps/oligo-pattern.ts} +106 -26
  22. package/src/view/{tabs/sdf.ts → apps/oligo-structure.ts} +13 -14
  23. package/src/view/{tabs/main.ts → apps/oligo-translator.ts} +15 -11
  24. package/src/view/const/ui.ts +14 -0
  25. package/src/view/style/pattern-app.css +1 -0
  26. package/src/view/style/structure-app.css +39 -0
  27. package/src/view/style/translator-app.css +46 -0
  28. package/src/view/utils/colored-input/colored-text-input.ts +7 -6
  29. package/src/view/utils/molecule-img.ts +21 -10
  30. package/src/view/utils/router.ts +71 -0
  31. package/src/demo/handle-error.ts +0 -12
  32. package/src/view/const/view.ts +0 -10
  33. package/src/view/css/axolabs-tab.css +0 -1
  34. package/src/view/css/main-tab.css +0 -46
  35. package/src/view/css/sdf-tab.css +0 -39
  36. package/src/view/view.ts +0 -127
  37. /package/src/view/const/{main-tab.ts → oligo-translator.ts} +0 -0
  38. /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 AxolabsTabUI {
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('Sequence length is out of range')
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
- .add(ui.divText('Please change sequence length in order to define new pattern.'))
86
- .show();
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 = '100px';
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
- `${STRAND_NAME[strand]}`, generateExample(strandLengthInput[strand].value!, sequenceBase.value!))
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(' ', translateSequence(
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.panel([
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.style.minWidth = EXAMPLE_MIN_WIDTH;
491
- // todo: remove ts-ignore
492
- // @ts-ignore
493
- outputExample[s].input.disabled = 'true';
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.div([]);
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.button('Download', () => svg.saveSvgAsPng(document.getElementById('mySvg'), saveAs.value,
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
- modificationSection[SS],
714
- modificationSection[AS],
715
- ]), {style: {maxWidth: '360px'}},
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 '../css/sdf-tab.css';
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 SdfTabUI {
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-sdf-mol-img');
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-sdf-bottom');
65
+ $(bottomDiv).addClass('st-structure-bottom');
67
66
 
68
67
  const sdfTabBody = ui.divV([tableLayout, bottomDiv]);
69
- $(sdfTabBody).addClass('st-sdf-body');
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-sdf-bool-button-block');
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-sdf-input-form');
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-sdf-input-form', 'st-sdf-direction-choice');
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-sdf-text-input-td');
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
- this.onInvalidInput.next();
170
- return '';
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 '../css/main-tab.css';
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/main-tab';
17
- import {DEFAULT_AXOLABS_INPUT} from '../const/view';
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 MainTabUI {
24
+ export class TranslatorLayoutHandler {
25
25
  constructor() {
26
26
  const INPUT_FORMATS = Object.keys(codesToHelmDictionary).concat(DEFAULT_FORMATS.HELM);
27
- this.moleculeImgDiv = ui.block([]);
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-main-input-table');
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.div([
93
+ ui.panel([
89
94
  upperBlock,
90
95
  outputTable,
91
- this.moleculeImgDiv,
92
- ], {style: {paddingTop: '20px', paddingLeft: '20px'}})
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-main-output-table');
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 '../../css/colored-text-input.css';
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
- painter: (str: string) => HTMLSpanElement[],
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.appendChild(dialogCanvas);
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.borderColor = 'var(--grey-3)';
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
- $(canvas).on('click', async () => { await this.zoomIn(); });
101
- $(canvas).on('mouseover', () => $(canvas).css('cursor', 'grab')); // for some reason 'zoom-in' value wouldn't work
102
- $(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
103
-
104
- moleculeImgDiv.append(canvas);
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
  }