@trebco/treb 31.7.8 → 31.9.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.
@@ -36,7 +36,7 @@ import { Theme } from './workbook-theme2';
36
36
  import { Sheet, VisibleState } from './workbook-sheet2';
37
37
  import type { RelationshipMap } from './relationship';
38
38
  import { ZipWrapper } from './zip-wrapper';
39
- import type { CellStyle, ThemeColor } from 'treb-base-types';
39
+ import type { CellStyle, ICellAddress, ThemeColor } from 'treb-base-types';
40
40
  import type { SerializedNamed } from 'treb-data-model';
41
41
 
42
42
  /**
@@ -86,11 +86,13 @@ export interface AnchoredChartDescription {
86
86
  export interface AnchoredTextBoxDescription {
87
87
  type: 'textbox';
88
88
  style?: CellStyle;
89
+ reference?: string;
89
90
  paragraphs: {
90
91
  style?: CellStyle,
91
92
  content: {
92
93
  text: string,
93
94
  style?: CellStyle
95
+ reference?: boolean,
94
96
  }[],
95
97
  }[];
96
98
  anchor: TwoCellAnchor,
@@ -397,100 +399,122 @@ export class Workbook {
397
399
 
398
400
  let style: CellStyle|undefined;
399
401
 
400
- const sppr = XMLUtils.FindAll(anchor_node, 'xdr:sp/xdr:spPr')[0];
401
- if (sppr) {
402
- style = {};
403
- const fill = sppr['a:solidFill'];
404
- if (fill) {
405
- if (fill['a:schemeClr']?.a$?.val) {
406
- const m = (fill['a:schemeClr'].a$.val).match(/accent(\d+)/);
407
- if (m) {
408
- style.fill = { theme: Number(m[1]) + 3 }
409
- if (fill['a:schemeClr']['a:lumOff']?.a$?.val) {
410
- const num = Number(fill['a:schemeClr']['a:lumOff'].a$.val);
411
- if (!isNaN(num)) {
412
- (style.fill as ThemeColor).tint = num / 1e5;
402
+ const sp = XMLUtils.FindAll(anchor_node, 'xdr:sp')[0];
403
+ if (sp) {
404
+
405
+ const reference = sp.a$?.textlink || undefined;
406
+
407
+ const sppr = XMLUtils.FindAll(sp, 'xdr:spPr')[0];
408
+ if (sppr) {
409
+ style = {};
410
+ const fill = sppr['a:solidFill'];
411
+ if (fill) {
412
+ if (fill['a:schemeClr']?.a$?.val) {
413
+ const m = (fill['a:schemeClr'].a$.val).match(/accent(\d+)/);
414
+ if (m) {
415
+ style.fill = { theme: Number(m[1]) + 3 }
416
+ if (fill['a:schemeClr']['a:lumOff']?.a$?.val) {
417
+ const num = Number(fill['a:schemeClr']['a:lumOff'].a$.val);
418
+ if (!isNaN(num)) {
419
+ (style.fill as ThemeColor).tint = num / 1e5;
420
+ }
413
421
  }
414
422
  }
415
- }
416
423
 
424
+ }
417
425
  }
418
426
  }
419
- }
420
427
 
421
- const tx = XMLUtils.FindAll(anchor_node, 'xdr:sp/xdr:txBody')[0];
422
- if (tx) {
423
-
424
- const paragraphs: {
425
- style?: CellStyle,
426
- content: {
427
- text: string,
428
- style?: CellStyle
429
- }[],
430
- }[] = [];
431
-
432
- /*
433
- const content: {
434
- text: string,
435
- style?: CellStyle,
436
- }[][] = [];
437
- */
438
-
439
- const p_list = XMLUtils.FindAll(tx, 'a:p');
440
- for (const paragraph of p_list) {
441
- const para: { text: string, style?: CellStyle }[] = [];
442
- let style: CellStyle|undefined;
443
-
444
- const appr = paragraph['a:pPr'];
445
- if (appr) {
446
- style = {};
447
- if (appr.a$?.algn === 'r') {
448
- style.horizontal_align = 'right';
428
+ const tx = XMLUtils.FindAll(sp, 'xdr:txBody')[0];
429
+ if (tx) {
430
+
431
+ const paragraphs: {
432
+ style?: CellStyle,
433
+ content: {
434
+ text: string,
435
+ style?: CellStyle
436
+ reference?: boolean;
437
+ }[],
438
+ }[] = [];
439
+
440
+ const p_list = XMLUtils.FindAll(tx, 'a:p');
441
+ for (const paragraph of p_list) {
442
+ const para: { text: string, style?: CellStyle, reference?: boolean }[] = [];
443
+ let style: CellStyle|undefined;
444
+
445
+ const fld = paragraph['a:fld'];
446
+ if (fld) {
447
+ if (fld.a$?.type === 'TxLink') {
448
+ const entry: {text: string, reference?: boolean, style?: CellStyle } = { text: `{${reference}}`, reference: true };
449
+
450
+ // format
451
+ const fmt = fld['a:rPr'];
452
+ if (fmt) {
453
+ entry.style = {};
454
+ if (fmt.a$?.b === '1') {
455
+ entry.style.bold = true;
456
+ }
457
+ if (fmt.a$?.i === '1') {
458
+ entry.style.italic = true;
459
+ }
460
+ }
461
+
462
+ para.push(entry);
463
+ }
449
464
  }
450
- else if (appr.a$?.algn === 'ctr') {
451
- style.horizontal_align = 'center';
465
+
466
+ const appr = paragraph['a:pPr'];
467
+ if (appr) {
468
+ style = {};
469
+ if (appr.a$?.algn === 'r') {
470
+ style.horizontal_align = 'right';
471
+ }
472
+ else if (appr.a$?.algn === 'ctr') {
473
+ style.horizontal_align = 'center';
474
+ }
452
475
  }
453
- }
454
476
 
455
- let ar = paragraph['a:r'];
456
- if (ar) {
457
- if (!Array.isArray(ar)) {
458
- ar = [ar];
459
- }
460
- for (const line of ar) {
461
-
462
- const entry: { text: string, style?: CellStyle } = {
463
- text: line['a:t'] || '',
464
- };
465
-
466
- // format
467
- const fmt = line['a:rPr'];
468
- if (fmt) {
469
- entry.style = {};
470
- if (fmt.a$?.b === '1') {
471
- entry.style.bold = true;
472
- }
473
- if (fmt.a$?.i === '1') {
474
- entry.style.italic = true;
475
- }
477
+ let ar = paragraph['a:r'];
478
+ if (ar) {
479
+ if (!Array.isArray(ar)) {
480
+ ar = [ar];
476
481
  }
482
+ for (const line of ar) {
483
+
484
+ const entry: { text: string, style?: CellStyle } = {
485
+ text: line['a:t'] || '',
486
+ };
487
+
488
+ // format
489
+ const fmt = line['a:rPr'];
490
+ if (fmt) {
491
+ entry.style = {};
492
+ if (fmt.a$?.b === '1') {
493
+ entry.style.bold = true;
494
+ }
495
+ if (fmt.a$?.i === '1') {
496
+ entry.style.italic = true;
497
+ }
498
+ }
477
499
 
478
- para.push(entry);
500
+ para.push(entry);
479
501
 
502
+ }
480
503
  }
481
- }
482
504
 
483
- paragraphs.push({ content: para, style });
505
+ paragraphs.push({ content: para, style });
484
506
 
485
- }
486
-
487
- results.push({
488
- type: 'textbox',
489
- style,
490
- paragraphs,
491
- anchor,
492
- });
507
+ }
508
+
509
+ results.push({
510
+ type: 'textbox',
511
+ style,
512
+ paragraphs,
513
+ anchor,
514
+ reference,
515
+ });
493
516
 
517
+ }
494
518
  }
495
519
 
496
520
  }
@@ -10,6 +10,7 @@
10
10
  "../treb-format/**/*.ts",
11
11
  "../treb-parser/**/*.ts",
12
12
  "../treb-calculator/**/*.ts",
13
+ "../treb-data-model/**/*.ts",
13
14
  "../treb-base-types/**/*.ts"
14
15
  ],
15
16
  "exclude": [
@@ -730,6 +730,27 @@ export abstract class BaseLayout {
730
730
  view.node.style.fontVariant = '';
731
731
  }
732
732
 
733
+ if (annotation.data.style?.bold) {
734
+ view.node.style.fontWeight = '600';
735
+ }
736
+ else {
737
+ view.node.style.fontWeight = '400';
738
+ }
739
+
740
+ if (annotation.data.style?.italic) {
741
+ view.node.style.fontStyle = 'italic';
742
+ }
743
+ else {
744
+ view.node.style.fontStyle = '';
745
+ }
746
+
747
+ if (annotation.data.style?.underline) {
748
+ view.node.style.textDecoration = 'underline';
749
+ }
750
+ else {
751
+ view.node.style.textDecoration = '';
752
+ }
753
+
733
754
  view.node.style.fontSize = `${font_size_pt}pt`;
734
755
 
735
756
  // update the layout here if necessary. after that it should
@@ -52,7 +52,7 @@ export class SVGSelectionBlock {
52
52
  this.g = DOM.SVG('g');
53
53
  this.g.setAttribute('transform', `translate(${offset.x}, ${offset.y})`);
54
54
 
55
- this.outline = DOM.SVG('rect', 'outline');
55
+ this.outline = DOM.SVG('rect', 'treb-selection-outline');
56
56
 
57
57
  if (primary) {
58
58
 
@@ -61,8 +61,8 @@ export class SVGSelectionBlock {
61
61
  // primary selections have a separate fill, plus the nub. separate
62
62
  // fill because the "target" is unfilled.
63
63
 
64
- this.fill = DOM.SVG('path', 'fill');
65
- this.nub = DOM.SVG('rect', 'nub');
64
+ this.fill = DOM.SVG('path', 'treb-selection-fill');
65
+ this.nub = DOM.SVG('rect', 'treb-selection-nub');
66
66
 
67
67
  this.g.appendChild(this.fill);
68
68
  this.g.appendChild(this.outline);
@@ -78,7 +78,7 @@ export class SVGSelectionBlock {
78
78
  // and use currentColor, but we can't set opacity separately so we
79
79
  // need another node. which is a waste, but ergonomics ftw!
80
80
 
81
- this.fill = DOM.SVG('rect', 'fill');
81
+ this.fill = DOM.SVG('rect', 'treb-selection-fill');
82
82
 
83
83
  // this.SetThemeColor(0);
84
84
  // if (theme.additional_selection_line_dash_array) {
@@ -95,42 +95,6 @@ export class SVGSelectionBlock {
95
95
  this.g.setAttribute('transform', `translate(${offset.x}, ${offset.y})`);
96
96
  }
97
97
 
98
- /*
99
- public SetThemeColor(index = 0) {
100
-
101
- if (Array.isArray(this.theme.additional_selection_color)) {
102
- if (index >= this.theme.additional_selection_color.length) {
103
- index = index % this.theme.additional_selection_color.length;
104
- }
105
- }
106
-
107
- if (this.theme.additional_selection_overlay_color) {
108
- if (typeof this.theme.additional_selection_overlay_color === 'string') {
109
- this.outline.setAttribute('fill', this.theme.additional_selection_overlay_color);
110
- }
111
- else {
112
- this.outline.setAttribute('fill', this.theme.additional_selection_overlay_color[index] || '');
113
- }
114
- }
115
- else {
116
- this.outline.setAttribute('fill', '');
117
- }
118
-
119
- if (this.theme.additional_selection_color) {
120
- if (typeof this.theme.additional_selection_color === 'string') {
121
- this.outline.setAttribute('stroke', this.theme.additional_selection_color);
122
- }
123
- else {
124
- this.outline.setAttribute('stroke', this.theme.additional_selection_color[index] || '');
125
- }
126
- }
127
- else {
128
- this.outline.setAttribute('stroke', '');
129
- }
130
-
131
- }
132
- */
133
-
134
98
  public Show(show = true) {
135
99
  this.g.style.display = show ? 'block' : 'none';
136
100
  }
@@ -956,6 +956,33 @@ export class Grid extends GridBase {
956
956
 
957
957
  const elements = [node, ...this.layout.GetFrozenAnnotations(annotation)];
958
958
 
959
+ if (event.ctrlKey || (UA.is_mac && event.metaKey)) {
960
+
961
+ const annotation_style = annotation.data.style ? { ...annotation.data.style } : {};
962
+ let handled = true;
963
+
964
+ switch (event.key) {
965
+ case 'b':
966
+ this.ApplyAnnotationStyle({bold: !annotation_style.bold});
967
+ break;
968
+ case 'i':
969
+ this.ApplyAnnotationStyle({italic: !annotation_style.italic});
970
+ break;
971
+ case 'u':
972
+ this.ApplyAnnotationStyle({underline: !annotation_style.underline});
973
+ break;
974
+ default:
975
+ handled = false;
976
+ }
977
+
978
+ if (handled) {
979
+ event.stopPropagation();
980
+ event.preventDefault();
981
+ return;
982
+ }
983
+
984
+ }
985
+
959
986
  const target = { x: rect.left, y: rect.top };
960
987
  switch (event.key) {
961
988
  case 'ArrowUp':
@@ -1773,9 +1800,17 @@ export class Grid extends GridBase {
1773
1800
  if (this.selected_annotation) {
1774
1801
 
1775
1802
  const annotation = this.selected_annotation;
1803
+
1804
+ // we need to adjust textbox paragraph styles so they don't
1805
+ // override the annotation style. OR, we need to apply this
1806
+ // styling to the paragraphs. the former sounds better to me,
1807
+ // but then if we allow you to edit the paragraphs we'll have
1808
+ // to adjust the annotation style later. not sure which is
1809
+ // preferable.
1810
+
1776
1811
  annotation.data.style = JSON.parse(JSON.stringify(
1777
- delta ? Style.Composite([annotation.data.style || {}, style]) : style
1778
- ));
1812
+ delta ? Style.Composite([annotation.data.style || {}, style]) : style));
1813
+
1779
1814
  const node = annotation.view[this.view_index]?.node;
1780
1815
 
1781
1816
  this.layout.UpdateAnnotation(annotation, this.theme);