@datagrok/sequence-translator 1.1.5 → 1.2.1

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 (40) 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/tests/formats-support.ts +1 -2
  21. package/src/tests/helm-to-nucleotides.ts +0 -2
  22. package/src/view/app-ui.ts +193 -0
  23. package/src/view/{tabs/axolabs.ts → apps/oligo-pattern.ts} +106 -26
  24. package/src/view/{tabs/sdf.ts → apps/oligo-structure.ts} +15 -16
  25. package/src/view/{tabs/main.ts → apps/oligo-translator.ts} +15 -11
  26. package/src/view/const/ui.ts +14 -0
  27. package/src/view/style/pattern-app.css +1 -0
  28. package/src/view/style/structure-app.css +39 -0
  29. package/src/view/style/translator-app.css +46 -0
  30. package/src/view/utils/colored-input/colored-text-input.ts +7 -6
  31. package/src/view/utils/molecule-img.ts +26 -10
  32. package/src/view/utils/router.ts +71 -0
  33. package/src/demo/handle-error.ts +0 -12
  34. package/src/view/const/view.ts +0 -10
  35. package/src/view/css/axolabs-tab.css +0 -1
  36. package/src/view/css/main-tab.css +0 -46
  37. package/src/view/css/sdf-tab.css +0 -39
  38. package/src/view/view.ts +0 -127
  39. /package/src/view/const/{main-tab.ts → oligo-translator.ts} +0 -0
  40. /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,18 +4,16 @@ 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';
11
11
 
12
- // import {drawMolecule} from '../../utils/structures-works/draw-molecule';
13
12
  import {highlightInvalidSubsequence} from '../utils/colored-input/input-painters';
14
13
  import {getLinkedMolfile, saveSdf} from '../../model/sequence-to-structure-utils/sdf-tab';
15
14
  import {ColoredTextInput} from '../utils/colored-input/colored-text-input';
16
15
  import {MoleculeImage} from '../utils/molecule-img';
17
16
  import {StrandData} from '../../model/sequence-to-structure-utils/sdf-tab';
18
- import {DEFAULT_AXOLABS_INPUT} from '../const/view';
19
17
 
20
18
  const enum DIRECTION {
21
19
  STRAIGHT = '5′ → 3′',
@@ -23,7 +21,7 @@ const enum DIRECTION {
23
21
  };
24
22
  const STRANDS = ['ss', 'as', 'as2'] as const;
25
23
 
26
- export class SdfTabUI {
24
+ export class StructureLayoutHandler {
27
25
  constructor() {
28
26
  this.onInput = new rxjs.Subject<string>();
29
27
  this.onInvalidInput = new rxjs.Subject<string>();
@@ -39,7 +37,7 @@ export class SdfTabUI {
39
37
  STRANDS.map((key) => [key, false])
40
38
  );
41
39
  this.moleculeImgDiv = ui.block([]);
42
- $(this.moleculeImgDiv).addClass('st-sdf-mol-img');
40
+ $(this.moleculeImgDiv).addClass('st-structure-mol-img');
43
41
 
44
42
  DG.debounce<string>(this.onInput, 300).subscribe(async () => {
45
43
  await this.updateMoleculeImg();
@@ -63,10 +61,10 @@ export class SdfTabUI {
63
61
  const boolInputsAndButton = this.getBoolInputsAndButton();
64
62
  await this.updateMoleculeImg();
65
63
  const bottomDiv = ui.divH([boolInputsAndButton, this.moleculeImgDiv]);
66
- $(bottomDiv).addClass('st-sdf-bottom');
64
+ $(bottomDiv).addClass('st-structure-bottom');
67
65
 
68
66
  const sdfTabBody = ui.divV([tableLayout, bottomDiv]);
69
- $(sdfTabBody).addClass('st-sdf-body');
67
+ $(sdfTabBody).addClass('st-structure-body');
70
68
 
71
69
  return sdfTabBody;
72
70
  }
@@ -83,7 +81,7 @@ export class SdfTabUI {
83
81
  const boolInputsAndButtonArray = [this.saveAllStrandsInput.root, this.useChiralInput.root, saveButton];
84
82
  const boolInputsAndButton = ui.divV(boolInputsAndButtonArray);
85
83
  for (const item of boolInputsAndButtonArray)
86
- $(item).addClass('st-sdf-bool-button-block');
84
+ $(item).addClass('st-structure-bool-button-block');
87
85
  return boolInputsAndButton;
88
86
  }
89
87
 
@@ -138,16 +136,16 @@ export class SdfTabUI {
138
136
 
139
137
  for (const strand of STRANDS) {
140
138
  let element = label[strand].parentElement!;
141
- element.classList.add('st-sdf-input-form');
139
+ element.classList.add('st-structure-input-form');
142
140
  // the following line is necessary because otherwise overridden by
143
141
  // d4-item-table class
144
142
  $(element).css('padding-top', '3px');
145
143
 
146
144
  element = directionChoiceInput[strand].root.parentElement!;
147
- element.classList.add('st-sdf-input-form', 'st-sdf-direction-choice');
145
+ element.classList.add('st-structure-input-form', 'st-structure-direction-choice');
148
146
 
149
147
  element = this.inputBase[strand].root.parentElement!;
150
- element.classList.add('st-sdf-text-input-td');
148
+ element.classList.add('st-structure-text-input-td');
151
149
  }
152
150
  return tableLayout;
153
151
  }
@@ -165,10 +163,10 @@ export class SdfTabUI {
165
163
  }
166
164
 
167
165
  private getMolfile(ss: StrandData, as: StrandData, as2: StrandData): string {
168
- if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
169
- this.onInvalidInput.next();
170
- return '';
171
- }
166
+ // if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
167
+ // this.onInvalidInput.next();
168
+ // return '';
169
+ // }
172
170
 
173
171
  return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!);
174
172
  }
@@ -177,7 +175,8 @@ export class SdfTabUI {
177
175
  let molfile = '';
178
176
  try {
179
177
  const strandData = this.getStrandData();
180
- molfile = this.getMolfile(strandData.ss, strandData.as, strandData.as2);
178
+ if (Object.values(strandData).some((data) => data.strand !== ''))
179
+ molfile = this.getMolfile(strandData.ss, strandData.as, strandData.as2);
181
180
  } catch (err) {
182
181
  const errStr = errorToConsole(err);
183
182
  console.error(errStr);
@@ -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() {
@@ -21,6 +21,11 @@ export class MoleculeImage {
21
21
  get molblock(): string { return this._validMolBlock; }
22
22
 
23
23
  set molblock(value: string) {
24
+ if (value === '') {
25
+ this._validMolBlock = value;
26
+ return;
27
+ }
28
+
24
29
  try {
25
30
  this.validateMolBlock(value);
26
31
  } catch (error) {
@@ -59,11 +64,10 @@ export class MoleculeImage {
59
64
  }
60
65
 
61
66
  private async zoomIn(): Promise<void> {
62
- const dialog = ui.dialog('Molecule');
67
+ const dialog = ui.dialog({title: 'Molecule', showFooter:false});
63
68
  const dialogDivStyle = {
64
69
  overflowX: 'scroll',
65
70
  };
66
- const dialogDiv = ui.div([], {style: dialogDivStyle});
67
71
 
68
72
  const height = $(window).height() * 0.7;
69
73
  const molDimensions = this.getMoleculeDimensions();
@@ -75,9 +79,14 @@ export class MoleculeImage {
75
79
 
76
80
  const dialogCanvas = ui.canvas(dialogCanvasWidth, dialogCanvasHeight);
77
81
  await this.drawMolBlockOnCanvas(dialogCanvas);
78
-
79
- dialogDiv.appendChild(dialogCanvas);
82
+
83
+ const dialogDiv = ui.block([dialogCanvas], {style: dialogDivStyle});
80
84
  dialog.add(dialogDiv).showModal(true);
85
+
86
+ $(dialog.root).find('.d4-dialog-contents').removeClass('ui-form');
87
+ $(dialog.root).find('.d4-dialog-contents').removeClass('ui-panel');
88
+ $(dialog.root).find('.d4-dialog-contents').addClass('ui-box');
89
+ $(dialog.root).find('.d4-dialog-contents').css('padding', '0');
81
90
  }
82
91
 
83
92
  public async drawMolecule(
@@ -91,16 +100,23 @@ export class MoleculeImage {
91
100
  // Draw zoomed-out molecule
92
101
  canvas.style.width = `${canvasWidth}px`;
93
102
  canvas.style.height = `${canvasHeight}px`;
103
+ canvas.style.cursor = 'zoom-in';
104
+ /*
94
105
  canvas.style.borderStyle = 'solid';
95
- canvas.style.borderColor = 'var(--grey-3)';
106
+ canvas.style.borderRadius = '1px';
107
+ canvas.style.borderColor = 'var(--grey-2)';
96
108
  canvas.style.borderWidth = 'thin';
109
+ */
97
110
  this.drawMolBlockOnCanvas(canvas);
98
111
 
99
112
  // 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);
113
+ canvas.addEventListener('click', async () => {
114
+ await this.zoomIn();
115
+ });
116
+ //$(canvas).on('click', async () => { await this.zoomIn(); });
117
+ //$(canvas).on('mouseover', () => $(canvas).css('cursor', 'grab')); // for some reason 'zoom-in' value wouldn't work
118
+ //$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
119
+
120
+ moleculeImgDiv.append(ui.tooltip.bind(canvas,'Click to zoom'));
105
121
  }
106
122
  }