@trebco/treb 31.1.1 → 31.3.2

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.
@@ -46,10 +46,16 @@ export interface AddressLabelEvent {
46
46
  text?: string;
47
47
  }
48
48
 
49
+ export interface TollEvent {
50
+ type: 'toll';
51
+ value?: string;
52
+ }
53
+
49
54
  export type FormulaBar2Event
50
55
  = FormulaButtonEvent
51
56
  // | FormulaBarResizeEvent
52
57
  | AddressLabelEvent
58
+ | TollEvent
53
59
  ;
54
60
 
55
61
  // ---
@@ -59,6 +65,8 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
59
65
 
60
66
  public committed = false;
61
67
 
68
+ public tolled?: { text: string, substring: string };
69
+
62
70
  /** is the _editor_ currently focused */
63
71
  // tslint:disable-next-line:variable-name
64
72
  public focused_ = false;
@@ -221,11 +229,16 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
221
229
  this.active_editor.node.spellcheck = false; // change the default back
222
230
 
223
231
  this.RegisterListener(descriptor, 'focusin', () => {
224
-
232
+
233
+ const restore = this.tolled !== undefined;
234
+ this.tolled = undefined;
235
+
225
236
  // this.editor_node.addEventListener('focusin', () => {
226
237
 
227
238
  // can't happen
228
- if (!this.active_editor) { return; }
239
+ if (!this.active_editor) {
240
+ return;
241
+ }
229
242
 
230
243
  // console.info('focus in');
231
244
 
@@ -243,6 +256,18 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
243
256
  this.UpdateText(this.active_editor);
244
257
  this.UpdateColors(undefined, true); // toll update event -- we will send in order, below
245
258
 
259
+ if (restore) {
260
+
261
+ // FIXME: we probably want to hold the caret so we can restore
262
+ // to a particular place. or set the caret explicitly.
263
+
264
+ const node = this.NodeAtIndex(text.length - 1);
265
+ // console.info({text, node});
266
+ if (node) {
267
+ this.SetCaret({node: node as ChildNode, offset: (node.textContent || '').length});
268
+ }
269
+ }
270
+
246
271
  this.committed = false;
247
272
 
248
273
  this.Publish([
@@ -254,7 +279,14 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
254
279
 
255
280
  });
256
281
 
257
- this.RegisterListener(descriptor, 'focusout', () => {
282
+ this.RegisterListener(descriptor, 'focusout', (event: FocusEvent) => {
283
+
284
+ // this is new, to support an external "insert function" dialog.
285
+ // still working out the semantics, but essentially we won't commit
286
+ // and we'll keep pending text. we need some sort of flag to indicate
287
+ // that we're in the editing state.
288
+
289
+ const toll = (event.relatedTarget instanceof HTMLElement && event.relatedTarget.dataset.tollEditor);
258
290
 
259
291
  if (this.selecting) {
260
292
  console.info('focusout, but selecting...');
@@ -265,7 +297,27 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
265
297
  const text = (this.active_editor ?
266
298
  this.GetTextContent(this.active_editor.node).join('') : '').trim();
267
299
 
268
- if (this.committed) {
300
+ if (toll) {
301
+
302
+ let substring = text;
303
+ if (this.active_editor?.node) {
304
+ const s2c = this.SubstringToCaret2(this.active_editor.node, true);
305
+ substring = s2c[0];
306
+ }
307
+
308
+ this.committed = true;
309
+ this.tolled = {
310
+ text,
311
+ substring,
312
+ };
313
+
314
+ this.Publish({
315
+ type: 'toll',
316
+ value: text,
317
+ });
318
+
319
+ }
320
+ else if (this.committed) {
269
321
  this.Publish([
270
322
  { type: 'stop-editing' },
271
323
  ]);
@@ -278,14 +330,10 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
278
330
  });
279
331
  }
280
332
 
333
+ // huh? we're publishing this twice?
334
+
281
335
  this.Publish([
282
336
  { type: 'stop-editing' },
283
- /*
284
- {
285
- type: 'commit',
286
- value: text,
287
- }
288
- */
289
337
  ]);
290
338
 
291
339
  this.focused_ = false;
@@ -336,6 +384,31 @@ export class FormulaBar extends Editor<FormulaBar2Event|FormulaEditorEvent> {
336
384
 
337
385
  }
338
386
 
387
+ /**
388
+ * we might be overthinking this, we don't necessarily need to restore.
389
+ *
390
+ * this method will focus the editor and set the caret (to the end, atm)
391
+ * in case of a tolled editor. the idea is you call Restore() after your
392
+ * dialog is complete and it's like you are back where you started.
393
+ *
394
+ * alternatively, call `Release()` to clean up any saved state.
395
+ */
396
+ public Restore() {
397
+ const target = this.container_node?.firstElementChild as HTMLDivElement;
398
+ if (target) {
399
+ target.focus();
400
+ }
401
+ }
402
+
403
+ /**
404
+ * release anything that's been tolled. call this if you toll the editor
405
+ * but don't want to restore it when you are done. I think this will be
406
+ * the default.
407
+ */
408
+ public Release() {
409
+ this.tolled = undefined;
410
+ }
411
+
339
412
  public IsElement(element: HTMLElement): boolean {
340
413
  return element === this.active_editor?.node;
341
414
  }
@@ -400,6 +400,17 @@ export class OverlayEditor extends Editor<ResetSelectionEvent> {
400
400
 
401
401
  }
402
402
 
403
+ public GetEditState() {
404
+ const text = this.active_editor?.node?.textContent || '';
405
+
406
+ let substring = '';
407
+ if (this.active_editor?.node) {
408
+ substring = this.SubstringToCaret2(this.active_editor.node, true)[0];
409
+ }
410
+
411
+ return { text, substring };
412
+ }
413
+
403
414
  /**
404
415
  * check if we want to handle this key. we have some special cases (tab,
405
416
  * enter, escape) where we do take some action but we also let the
@@ -219,6 +219,9 @@ export class Grid extends GridBase {
219
219
  /** */
220
220
  private editing_annotation?: Annotation;
221
221
 
222
+ /** */
223
+ private pending_reset_selection = false;
224
+
222
225
  /** */
223
226
  private view_node?: HTMLElement;
224
227
 
@@ -1742,8 +1745,15 @@ export class Grid extends GridBase {
1742
1745
  if (this.selected_annotation) {
1743
1746
 
1744
1747
  if (click) {
1745
- this.selected_annotation = undefined;
1746
- this.ShowGridSelection();
1748
+
1749
+ if (this.editing_annotation === this.selected_annotation) {
1750
+ this.pending_reset_selection = true;
1751
+ }
1752
+ else {
1753
+ this.selected_annotation = undefined;
1754
+ this.ShowGridSelection();
1755
+ }
1756
+
1747
1757
  }
1748
1758
  else {
1749
1759
  // console.info("reselect annotation...", this.selected_annotation);
@@ -2964,6 +2974,10 @@ export class Grid extends GridBase {
2964
2974
 
2965
2975
  case 'stop-editing':
2966
2976
 
2977
+ if (this.pending_reset_selection) {
2978
+ this.ShowGridSelection();
2979
+ }
2980
+ this.pending_reset_selection = false;
2967
2981
  this.editing_state = EditingState.NotEditing;
2968
2982
  break;
2969
2983
 
@@ -2986,6 +3000,19 @@ export class Grid extends GridBase {
2986
3000
  this.editing_selection = { ...this.primary_selection };
2987
3001
  break;
2988
3002
 
3003
+ case 'toll':
3004
+
3005
+ // this is basically "stop editing", with some special
3006
+ // semantics to capture the editing state. it's intended
3007
+ // for external clients, specifically for an "insert function"
3008
+ // dialog.
3009
+
3010
+ this.editing_state = EditingState.NotEditing;
3011
+ this.ClearAdditionalSelections();
3012
+ this.ClearSelection(this.active_selection);
3013
+ this.DelayedRender();
3014
+ break;
3015
+
2989
3016
  case 'discard':
2990
3017
 
2991
3018
  this.editing_state = EditingState.NotEditing;
@@ -3037,10 +3064,14 @@ export class Grid extends GridBase {
3037
3064
  this.ClearAdditionalSelections();
3038
3065
  this.ClearSelection(this.active_selection);
3039
3066
  annotation.data.formula = event.value ? this.FixFormula(event.value) : '';
3040
- const node = this.editing_annotation.view[this.view_index]?.node;
3041
- if (node) {
3042
- node.focus();
3067
+
3068
+ if (!this.pending_reset_selection) {
3069
+ const node = this.editing_annotation.view[this.view_index]?.node;
3070
+ if (node) {
3071
+ node.focus();
3072
+ }
3043
3073
  }
3074
+
3044
3075
  this.grid_events.Publish({ type: 'annotation', event: 'update', annotation });
3045
3076
  this.editing_annotation = undefined;
3046
3077
  this.DelayedRender();
@@ -4774,6 +4805,26 @@ export class Grid extends GridBase {
4774
4805
  // || (this.select_argument);
4775
4806
  }
4776
4807
 
4808
+ /**
4809
+ * for external clients. the expected pattern is
4810
+ * - start overlay editor
4811
+ * - click on "insert function"
4812
+ * - do something
4813
+ * - release editor (this function)
4814
+ */
4815
+ public ReleaseOverlayEditor() {
4816
+ this.editing_state = EditingState.NotEditing;
4817
+ this.DismissEditor();
4818
+ this.DelayedRender();
4819
+ }
4820
+
4821
+ public RestoreOverlayEditor() {
4822
+
4823
+ // ?
4824
+ this.overlay_editor?.FocusEditor();
4825
+
4826
+ }
4827
+
4777
4828
  /**
4778
4829
  * consolidated event handler for overlay, which both handles grid keys
4779
4830
  * and acts as the ICE, depending on state. going to be a little tricky
@@ -161,6 +161,10 @@ export interface UnitCall extends BaseUnit {
161
161
  name: string;
162
162
  position: number;
163
163
  args: ExpressionUnit[];
164
+
165
+ /** testing */
166
+ end?: number;
167
+
164
168
  }
165
169
 
166
170
  /**
@@ -36,6 +36,7 @@ import type {
36
36
  RenderOptions,
37
37
  BaseExpressionUnit,
38
38
  } from './parser-types';
39
+
39
40
  import {
40
41
  ArgumentSeparatorType,
41
42
  DecimalMarkType,
@@ -1137,7 +1138,6 @@ export class Parser {
1137
1138
 
1138
1139
  }
1139
1140
 
1140
-
1141
1141
  // so we're moving complex handling to post-reordering, to support
1142
1142
  // precedence properly. there's still one thing we have to do here,
1143
1143
  // though: handle those cases of naked imaginary values "i". these
@@ -1233,7 +1233,13 @@ export class Parser {
1233
1233
 
1234
1234
  // return this.BinaryToRange(this.ArrangeUnits(stream));
1235
1235
  // return this.ArrangeUnits(stream);
1236
+
1237
+ // const arranged = this.ArrangeUnits(stream);
1238
+ // const result = this.BinaryToComplex(arranged);
1239
+ // return result;
1240
+
1236
1241
  return this.BinaryToComplex(this.ArrangeUnits(stream));
1242
+
1237
1243
  }
1238
1244
 
1239
1245
  /**
@@ -1808,6 +1814,7 @@ export class Parser {
1808
1814
  * reorders operations for precendence
1809
1815
  */
1810
1816
  protected ArrangeUnits(stream: ExpressionUnit[]): ExpressionUnit {
1817
+
1811
1818
  // probably should not happen
1812
1819
  if (stream.length === 0) return { type: 'missing', id: this.id_counter++ };
1813
1820
 
@@ -1908,7 +1915,41 @@ export class Parser {
1908
1915
  }
1909
1916
  }
1910
1917
 
1911
- if (stack.length < 2) {
1918
+ //
1919
+ // why is this 2? are we thinking about combining complex numbers?
1920
+ // or ranges? (those would be binary). or was this for dimensioned
1921
+ // quantities? [actually that makes sense] [A: no, it wasn't that]
1922
+ //
1923
+ // actually what's the case where this is triggered and it's _not_
1924
+ // an error? can we find that?
1925
+ //
1926
+
1927
+ if (stack.length < 2) {
1928
+
1929
+ // we know that `element` is not an operator, because we
1930
+ // would have consumed it
1931
+
1932
+ if (stack.length === 1) {
1933
+ const a = stack[0].type;
1934
+
1935
+ if (a !== 'operator') {
1936
+
1937
+ // console.warn("unexpected element", stack[0], element);
1938
+
1939
+ this.error = `unexpected element [3]: ${element.type}`;
1940
+ this.error_position = (element.type === 'missing' || element.type === 'group' || element.type === 'dimensioned') ? -1 : element.position;
1941
+ this.valid = false;
1942
+ return {
1943
+ type: 'group',
1944
+ id: this.id_counter++,
1945
+ elements: stream,
1946
+ explicit: false,
1947
+ };
1948
+
1949
+ }
1950
+
1951
+ }
1952
+
1912
1953
  stack.push(element);
1913
1954
  }
1914
1955
  else if (stack[stack.length - 1].type === 'operator') {
@@ -2353,6 +2394,7 @@ export class Parser {
2353
2394
  name: str,
2354
2395
  args,
2355
2396
  position,
2397
+ end: this.index, // testing
2356
2398
  };
2357
2399
  }
2358
2400