wunderbaum 0.0.8 → 0.1.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/src/types.ts CHANGED
@@ -17,16 +17,24 @@ export type BoolOrStringOptionResolver = (
17
17
  ) => boolean | string;
18
18
 
19
19
  export type NodeAnyCallback = (node: WunderbaumNode) => any;
20
+ export type NodeStringCallback = (node: WunderbaumNode) => string;
20
21
 
21
22
  export type NodeVisitResponse = "skip" | boolean | void;
22
23
  export type NodeVisitCallback = (node: WunderbaumNode) => NodeVisitResponse;
23
24
 
24
25
  // type WithWildcards<T> = T & { [key: string]: unknown };
26
+
27
+ /* -----------------------------------------------------------------------------
28
+ * EVENT CALLBACK TYPES
29
+ * ---------------------------------------------------------------------------*/
30
+
25
31
  export interface WbTreeEventType {
26
32
  /** Name of the event. */
27
33
  type: string;
28
- /** The affected tree. */
34
+ /** The affected tree instance. */
29
35
  tree: Wunderbaum;
36
+ /** Exposed utility module methods. */
37
+ util: any;
30
38
  /** Originating HTML event, e.g. `click` if any. */
31
39
  event?: Event;
32
40
  // [key: string]: unknown;
@@ -42,6 +50,63 @@ export interface WbNodeEventType extends WbTreeEventType {
42
50
  typeInfo: NodeTypeDefinition;
43
51
  }
44
52
 
53
+ export interface WbActivateEventType extends WbNodeEventType {
54
+ prevNode: WunderbaumNode;
55
+ /** The original event. */
56
+ event: Event;
57
+ }
58
+
59
+ export interface WbChangeEventType extends WbNodeEventType {
60
+ info: WbEventInfo;
61
+ inputElem: HTMLInputElement;
62
+ inputValue: any;
63
+ }
64
+
65
+ export interface WbClickEventType extends WbTreeEventType {
66
+ /** The original event. */
67
+ event: MouseEvent;
68
+ node: WunderbaumNode;
69
+ info: WbEventInfo;
70
+ }
71
+
72
+ export interface WbErrorEventType extends WbNodeEventType {
73
+ error: any;
74
+ }
75
+
76
+ export interface WbDeactivateEventType extends WbNodeEventType {
77
+ nextNode: WunderbaumNode;
78
+ /** The original event. */
79
+ event: Event;
80
+ }
81
+
82
+ export interface WbEnhanceTitleEventType extends WbNodeEventType {
83
+ titleSpan: HTMLSpanElement;
84
+ }
85
+
86
+ export interface WbFocusEventType extends WbTreeEventType {
87
+ /** The original event. */
88
+ event: FocusEvent;
89
+ /** True if `focusin`, false if `focusout`. */
90
+ flag: boolean;
91
+ }
92
+
93
+ export interface WbKeydownEventType extends WbTreeEventType {
94
+ /** The original event. */
95
+ event: KeyboardEvent;
96
+ node: WunderbaumNode;
97
+ info: WbEventInfo;
98
+ /** Canical name of the key including modifiers. @see {@link eventToString} */
99
+ eventName: string;
100
+ }
101
+
102
+ export interface WbInitEventType extends WbTreeEventType {
103
+ error?: any;
104
+ }
105
+
106
+ export interface WbReceiveEventType extends WbNodeEventType {
107
+ response: any;
108
+ }
109
+
45
110
  export interface WbRenderEventType extends WbNodeEventType {
46
111
  /**
47
112
  * True if the node's markup was not yet created. In this case the render
@@ -49,24 +114,22 @@ export interface WbRenderEventType extends WbNodeEventType {
49
114
  * values according to to current node data).
50
115
  */
51
116
  isNew: boolean;
52
- /** True if the node only displays the title and is stretched over all remaining columns. */
53
- isColspan: boolean;
54
- // /** */
55
- // isDataChange: boolean;
56
117
  /** The node's `<span class='wb-node'>` element. */
57
118
  nodeElem: HTMLSpanElement;
119
+ /** True if the node only displays the title and is stretched over all remaining columns. */
120
+ isColspan: boolean;
58
121
  /**
59
122
  * Array of node's `<span class='wb-col'>` elements.
60
123
  * The first element is `<span class='wb-node wb-col'>`, which contains the
61
124
  * node title and icon (`idx: 0`, id: '*'`).
62
125
  */
63
- allColInfosById: ColumnEventInfos;
126
+ allColInfosById: ColumnEventInfoMap;
64
127
  /**
65
128
  * Array of node's `<span class='wb-node'>` elements, *that should be rendered*.
66
129
  * In contrast to `allColInfosById`, the node title is not part of this array.
67
130
  * If node.isColspan() is true, this array is empty (`[]`).
68
131
  */
69
- renderColInfosById: ColumnEventInfos;
132
+ renderColInfosById: ColumnEventInfoMap;
70
133
  }
71
134
 
72
135
  /**
@@ -76,13 +139,13 @@ export interface WbRenderEventType extends WbNodeEventType {
76
139
  export interface NodeTypeDefinition {
77
140
  // /** Type ID that matches `node.type`. */
78
141
  // id: string;
79
- /** En/disable checkbox for matching nodes.*/
142
+ /** En/disable checkbox for matching nodes. */
80
143
  checkbox?: boolean | BoolOrStringOptionResolver;
81
- /** En/disable checkbox for matching nodes.*/
82
- colspan?: boolean | BoolOptionResolver;
83
- /** Optional class names that are added to all `div.wb-row` elements of matching nodes.*/
144
+ /** Optional class names that are added to all `div.wb-row` elements of matching nodes. */
84
145
  classes?: string;
85
- /**Default icon for matching nodes.*/
146
+ /** Only show title and hide other columns if any. */
147
+ colspan?: boolean | BoolOptionResolver;
148
+ /** Default icon for matching nodes. */
86
149
  icon?: boolean | string | BoolOrStringOptionResolver;
87
150
  /**
88
151
  * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
@@ -93,26 +156,19 @@ export interface NodeTypeDefinition {
93
156
  // _any: any;
94
157
  }
95
158
 
96
- // /**
97
- // * Contains the node's type information, i.e. `tree.types[node.type]` if
98
- // * defined. @see {@link Wunderbaum.types}
99
- // */
100
- // export type NodeTypeInfo = {
101
- // icon?: string;
102
- // classes?: string;
103
- // // and more
104
- // [key: string]: unknown;
105
- // };
106
- export type NodeTypeDefinitions = { [type: string]: NodeTypeDefinition };
159
+ /* -----------------------------------------------------------------------------
160
+ * DATA TYPES
161
+ * ---------------------------------------------------------------------------*/
162
+
163
+ export type NodeTypeDefinitionMap = { [type: string]: NodeTypeDefinition };
107
164
 
108
165
  /**
166
+ * Column type definitions.
109
167
  * @see {@link `Wunderbaum.columns`}
110
168
  */
111
169
  export interface ColumnDefinition {
112
170
  /** Column ID as defined in `tree.columns` definition ("*" for title column). */
113
171
  id: string;
114
- // /** */
115
- // idx: number;
116
172
  /** Column header (defaults to id) */
117
173
  title: string;
118
174
  /** Column header tooltip (optional) */
@@ -136,8 +192,12 @@ export interface ColumnDefinition {
136
192
  _widthPx?: number;
137
193
  _ofsPx?: number;
138
194
  }
195
+
139
196
  export type ColumnDefinitionList = Array<ColumnDefinition>;
140
197
 
198
+ /**
199
+ * Column information (passed to the `render` event).
200
+ */
141
201
  export interface ColumnEventInfo {
142
202
  /** Column ID as defined in `tree.columns` definition ("*" for title column). */
143
203
  id: string;
@@ -148,11 +208,33 @@ export interface ColumnEventInfo {
148
208
  /** The value of `tree.columns[]` for the current index. */
149
209
  info: ColumnDefinition;
150
210
  }
151
- export type ColumnEventInfos = { [colId: string]: ColumnEventInfo };
152
211
 
153
- export type WbTreeCallbackType = (e: WbTreeEventType) => any;
154
- export type WbNodeCallbackType = (e: WbNodeEventType) => any;
155
- export type WbRenderCallbackType = (e: WbRenderEventType) => void;
212
+ export type ColumnEventInfoMap = { [colId: string]: ColumnEventInfo };
213
+
214
+ /**
215
+ * Additional inforation derived from mouse or keyboard events.
216
+ * @see {@link Wunderbaum.getEventInfo}
217
+ */
218
+ export interface WbEventInfo {
219
+ /** The tree instance. */
220
+ tree: Wunderbaum;
221
+ /** The affected node instance instance if any. */
222
+ node: WunderbaumNode | null;
223
+ /** The affected part of the node span (e.g. title, expander, ...). */
224
+ region: NodeRegion;
225
+ /** The definition of the affected column if any. */
226
+ colDef?: ColumnDefinition;
227
+ /** The index of affected column or -1. */
228
+ colIdx: number;
229
+ /** The column definition ID of affected column if any. */
230
+ colId?: string;
231
+ /** The affected column's span tag if any. */
232
+ colElem?: HTMLSpanElement;
233
+ }
234
+
235
+ // export type WbTreeCallbackType = (e: WbTreeEventType) => any;
236
+ // export type WbNodeCallbackType = (e: WbNodeEventType) => any;
237
+ // export type WbRenderCallbackType = (e: WbRenderEventType) => void;
156
238
 
157
239
  export type FilterModeType = null | "dim" | "hide";
158
240
  export type ApplyCommandType =
@@ -210,7 +292,7 @@ export enum NodeStatusType {
210
292
  }
211
293
 
212
294
  /** Define the subregion of a node, where an event occurred. */
213
- export enum TargetType {
295
+ export enum NodeRegion {
214
296
  unknown = "",
215
297
  checkbox = "checkbox",
216
298
  column = "column",
@@ -220,6 +302,18 @@ export enum TargetType {
220
302
  title = "title",
221
303
  }
222
304
 
305
+ /** Initial navigation mode and possible transition. */
306
+ export enum NavModeEnum {
307
+ startRow = "startRow", // Start with row mode, but allow cell-nav mode
308
+ cell = "cell", // Cell-nav mode only
309
+ startCell = "startCell", // Start in cell-nav mode, but allow row mode
310
+ row = "row", // Row mode only
311
+ }
312
+
313
+ /* -----------------------------------------------------------------------------
314
+ * METHOD OPTIONS TYPES
315
+ * ---------------------------------------------------------------------------*/
316
+
223
317
  /** Possible values for {@link WunderbaumNode.addChildren()}. */
224
318
  export interface AddChildrenOptions {
225
319
  /** Insert children before this node (or index)
@@ -236,6 +330,11 @@ export interface AddChildrenOptions {
236
330
  _level?: number;
237
331
  }
238
332
 
333
+ /** Possible values for {@link Wunderbaum.applyCommand()} and {@link WunderbaumNode.applyCommand()}. */
334
+ export interface ApplyCommandOptions {
335
+ [key: string]: unknown;
336
+ }
337
+
239
338
  /** Possible values for {@link Wunderbaum.expandAll()} and {@link WunderbaumNode.expandAll()}. */
240
339
  export interface ExpandAllOptions {
241
340
  /** Restrict expand level @default 99 */
@@ -246,6 +345,17 @@ export interface ExpandAllOptions {
246
345
  force?: boolean;
247
346
  }
248
347
 
348
+ /** Possible values for {@link Wunderbaum.filterNodes()} and {@link Wunderbaum.filterBranches()}. */
349
+ export interface FilterNodesOptions {
350
+ mode?: string;
351
+ leavesOnly?: boolean;
352
+ fuzzy?: boolean;
353
+ highlight?: boolean;
354
+ hideExpanders?: boolean;
355
+ autoExpand?: boolean;
356
+ noData?: boolean;
357
+ }
358
+
249
359
  /** Possible values for {@link WunderbaumNode.makeVisible()}. */
250
360
  export interface MakeVisibleOptions {
251
361
  /** Do not animate expand (currently not implemented). @default false */
@@ -256,12 +366,20 @@ export interface MakeVisibleOptions {
256
366
  noEvents?: boolean;
257
367
  }
258
368
 
259
- /** Initial navigation mode and possible transition. */
260
- export enum NavigationOptions {
261
- startRow = "startRow", // Start with row mode, but allow cell-nav mode
262
- cell = "cell", // Cell-nav mode only
263
- startCell = "startCell", // Start in cell-nav mode, but allow row mode
264
- row = "row", // Row mode only
369
+ /** Possible values for {@link Wunderbaum.navigate()}. */
370
+ export interface NavigateOptions {
371
+ activate?: boolean;
372
+ event?: Event;
373
+ }
374
+
375
+ /** Possible values for {@link WunderbaumNode.render()}. */
376
+ export interface RenderOptions {
377
+ change?: ChangeType;
378
+ after?: any;
379
+ isNew?: boolean;
380
+ preventScroll?: boolean;
381
+ isDataChange?: boolean;
382
+ top?: number;
265
383
  }
266
384
 
267
385
  /** Possible values for {@link scrollIntoView()}. */
@@ -336,9 +454,25 @@ export interface SetStatusOptions {
336
454
  details?: string;
337
455
  }
338
456
 
457
+ /** Possible values for {@link Wunderbaum.updateColumns()}. */
458
+ export interface UpdateColumnsOptions {
459
+ calculateCols?: boolean;
460
+ updateRows?: boolean;
461
+ }
462
+
463
+ /** Possible values for {@link Wunderbaum.visitRows()} and {@link Wunderbaum.visitRowsUp()}. */
464
+ export interface VisitRowsOptions {
465
+ reverse?: boolean;
466
+ includeSelf?: boolean;
467
+ includeHidden?: boolean;
468
+ wrap?: boolean;
469
+ start?: WunderbaumNode | null;
470
+ }
471
+
339
472
  /* -----------------------------------------------------------------------------
340
473
  * wb_ext_dnd
341
- */
474
+ * ---------------------------------------------------------------------------*/
475
+
342
476
  export type DropRegionType = "over" | "before" | "after";
343
477
  export type DropRegionTypeSet = Set<DropRegionType>;
344
478
  // type AllowedDropRegionType =
package/src/wb_ext_dnd.ts CHANGED
@@ -144,7 +144,7 @@ export class DndExtension extends WunderbaumExtension {
144
144
  protected autoScroll(event: DragEvent): number {
145
145
  let tree = this.tree,
146
146
  dndOpts = tree.options.dnd!,
147
- sp = tree.scrollContainerElement,
147
+ sp = tree.listContainerElement,
148
148
  sensitivity = dndOpts.scrollSensitivity,
149
149
  speed = dndOpts.scrollSpeed,
150
150
  scrolled = 0;
@@ -180,6 +180,11 @@ export class DndExtension extends WunderbaumExtension {
180
180
  if (e.type === "dragstart") {
181
181
  // Set a default definition of allowed effects
182
182
  e.dataTransfer!.effectAllowed = dndOpts.effectAllowed; //"copyMove"; // "all";
183
+ if (srcNode.isEditing()) {
184
+ srcNode.logDebug("Prevented dragging node in edit mode.");
185
+ e.preventDefault();
186
+ return false;
187
+ }
183
188
  // Let user cancel the drag operation, override effectAllowed, etc.:
184
189
  const res = srcNode._callEvent("dnd.dragStart", { event: e });
185
190
  if (!res) {
@@ -196,7 +196,7 @@ export class EditExtension extends WunderbaumExtension {
196
196
  // (we also treat a `true` return value as 'use default'):
197
197
  if (inputHtml === true || !inputHtml) {
198
198
  const title = escapeHtml(node.title);
199
- inputHtml = `<input type=text class="wb-input-edit" value="${title}" required autocorrect=off>`;
199
+ inputHtml = `<input type=text class="wb-input-edit" tabindex=-1 value="${title}" required autocorrect=off>`;
200
200
  }
201
201
  const titleSpan = node
202
202
  .getColElem(0)!
@@ -236,11 +236,11 @@ export class EditExtension extends WunderbaumExtension {
236
236
  * @param apply
237
237
  * @param opts.canKeepOpen
238
238
  */
239
- _stopEditTitle(apply: boolean, opts: any) {
239
+ _stopEditTitle(apply: boolean, options: any) {
240
240
  const focusElem = document.activeElement as HTMLInputElement;
241
241
  let newValue = focusElem ? getValueFromElem(focusElem) : null;
242
242
  const node = this.curEditNode;
243
- const forceClose = !!opts.forceClose;
243
+ const forceClose = !!options.forceClose;
244
244
  const validity = this.getPluginOption("validity");
245
245
 
246
246
  if (newValue && this.getPluginOption("trim")) {
@@ -250,7 +250,7 @@ export class EditExtension extends WunderbaumExtension {
250
250
  this.tree.logDebug("stopEditTitle: not in edit mode.");
251
251
  return;
252
252
  }
253
- node.logDebug(`stopEditTitle(${apply})`, opts, focusElem, newValue);
253
+ node.logDebug(`stopEditTitle(${apply})`, options, focusElem, newValue);
254
254
 
255
255
  if (apply && newValue !== null && newValue !== node.title) {
256
256
  const errMsg = focusElem.validationMessage;
@@ -283,21 +283,23 @@ export class EditExtension extends WunderbaumExtension {
283
283
  return;
284
284
  }
285
285
  node?.setTitle(newValue);
286
- this.curEditNode!.render();
286
+ // NOTE: At least on Safari, this render call triggers a scroll event
287
+ // probably because the focused input is replaced.
288
+ this.curEditNode!.render({ preventScroll: true });
287
289
  this.curEditNode = null;
288
290
  this.relatedNode = null;
289
291
  this.tree.setFocus(); // restore focus that was in the input element
290
292
  })
291
293
  .catch((err) => {
292
- // this.curEditNode!.render();
293
- // this.curEditNode = null;
294
- // this.relatedNode = null;
294
+ node.logError(err);
295
295
  });
296
296
  // Trigger 'change' event for embedded `<input>`
297
297
  // focusElem.blur();
298
298
  } else {
299
299
  // Discard the embedded `<input>`
300
- this.curEditNode!.render();
300
+ // NOTE: At least on Safari, this render call triggers a scroll event
301
+ // probably because the focused input is replaced.
302
+ this.curEditNode!.render({ preventScroll: true });
301
303
  this.curEditNode = null;
302
304
  this.relatedNode = null;
303
305
  // We discarded the <input>, so we have to acquire keyboard focus again
@@ -11,7 +11,11 @@ import {
11
11
  extend,
12
12
  onEvent,
13
13
  } from "./util";
14
- import { NodeFilterCallback, NodeStatusType } from "./types";
14
+ import {
15
+ FilterNodesOptions,
16
+ NodeFilterCallback,
17
+ NodeStatusType,
18
+ } from "./types";
15
19
  import { Wunderbaum } from "./wunderbaum";
16
20
  import { WunderbaumNode } from "./wb_node";
17
21
  import { WunderbaumExtension } from "./wb_extension_base";
@@ -243,19 +247,25 @@ export class FilterExtension extends WunderbaumExtension {
243
247
  /**
244
248
  * [ext-filter] Dim or hide nodes.
245
249
  *
246
- * @param {boolean} [opts={autoExpand: false, leavesOnly: false}]
250
+ * @param {boolean} [options={autoExpand: false, leavesOnly: false}]
247
251
  */
248
- filterNodes(filter: string | NodeFilterCallback, opts: any) {
249
- return this._applyFilterNoUpdate(filter, false, opts);
252
+ filterNodes(
253
+ filter: string | NodeFilterCallback,
254
+ options: FilterNodesOptions
255
+ ) {
256
+ return this._applyFilterNoUpdate(filter, false, options);
250
257
  }
251
258
 
252
259
  /**
253
260
  * [ext-filter] Dim or hide whole branches.
254
261
  *
255
- * @param {boolean} [opts={autoExpand: false}]
262
+ * @param {boolean} [options={autoExpand: false}]
256
263
  */
257
- filterBranches(filter: string | NodeFilterCallback, opts: any) {
258
- return this._applyFilterNoUpdate(filter, true, opts);
264
+ filterBranches(
265
+ filter: string | NodeFilterCallback,
266
+ options: FilterNodesOptions
267
+ ) {
268
+ return this._applyFilterNoUpdate(filter, true, options);
259
269
  }
260
270
 
261
271
  /**
@@ -4,7 +4,7 @@
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
 
7
- import { NavigationOptions } from "./types";
7
+ import { NavModeEnum } from "./types";
8
8
  import { eventToString } from "./util";
9
9
  import { Wunderbaum } from "./wunderbaum";
10
10
  import { WunderbaumNode } from "./wb_node";
@@ -47,7 +47,7 @@ export class KeynavExtension extends WunderbaumExtension {
47
47
  opts = data.options,
48
48
  activate = !event.ctrlKey || opts.autoActivate,
49
49
  curInput = this._getEmbeddedInputElem(event.target),
50
- navModeOption = opts.navigationModeOption as NavigationOptions;
50
+ navModeOption = opts.navigationModeOption as NavModeEnum;
51
51
  // isCellEditMode = tree.navMode === NavigationMode.cellEdit;
52
52
 
53
53
  let focusNode,
@@ -122,17 +122,30 @@ export class KeynavExtension extends WunderbaumExtension {
122
122
 
123
123
  // Pre-Evaluate expand/collapse action for LEFT/RIGHT
124
124
  switch (eventName) {
125
+ case "Enter":
126
+ if (node.isActive()) {
127
+ if (node.isExpanded()) {
128
+ eventName = "Subtract"; // callapse
129
+ } else if (node.isExpandable(true)) {
130
+ eventName = "Add"; // expand
131
+ }
132
+ }
133
+ break;
125
134
  case "ArrowLeft":
126
135
  if (node.expanded) {
127
136
  eventName = "Subtract"; // collapse
128
137
  }
129
138
  break;
130
139
  case "ArrowRight":
131
- if (!node.expanded && (node.children || node.lazy)) {
140
+ if (!node.expanded && node.isExpandable(true)) {
132
141
  eventName = "Add"; // expand
133
- } else if (navModeOption === NavigationOptions.startRow) {
142
+ } else if (
143
+ navModeOption === NavModeEnum.startCell ||
144
+ navModeOption === NavModeEnum.startRow
145
+ ) {
146
+ event.preventDefault();
134
147
  tree.setCellNav();
135
- return;
148
+ return false;
136
149
  }
137
150
  break;
138
151
  }
@@ -148,7 +161,7 @@ export class KeynavExtension extends WunderbaumExtension {
148
161
  case "Subtract":
149
162
  node.setExpanded(false);
150
163
  break;
151
- case " ":
164
+ case " ": // Space
152
165
  // if (node.isPagingNode()) {
153
166
  // tree._triggerNodeEvent("clickPaging", ctx, event);
154
167
  // } else
@@ -228,7 +241,16 @@ export class KeynavExtension extends WunderbaumExtension {
228
241
  }
229
242
 
230
243
  switch (eventName) {
231
- case " ":
244
+ case "+":
245
+ case "Add":
246
+ // case "=": // 187: '+' @ Chrome, Safari
247
+ node.setExpanded(true);
248
+ break;
249
+ case "-":
250
+ case "Subtract":
251
+ node.setExpanded(false);
252
+ break;
253
+ case " ": // Space
232
254
  if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
233
255
  node.setSelected(!node.isSelected());
234
256
  handled = true;
@@ -248,7 +270,7 @@ export class KeynavExtension extends WunderbaumExtension {
248
270
  break;
249
271
  case "Enter":
250
272
  tree.setFocus(); // Blur prev. input if any
251
- if (tree.activeColIdx === 0 && node.isExpandable()) {
273
+ if ((tree.activeColIdx === 0 || isColspan) && node.isExpandable()) {
252
274
  node.setExpanded(!node.isExpanded());
253
275
  handled = true;
254
276
  } else if (curInput && !inputHasFocus && inputCanFocus) {
@@ -258,7 +280,7 @@ export class KeynavExtension extends WunderbaumExtension {
258
280
  break;
259
281
  case "Escape":
260
282
  tree.setFocus(); // Blur prev. input if any
261
- if (tree.isCellNav() && navModeOption !== NavigationOptions.cell) {
283
+ if (tree.isCellNav() && navModeOption !== NavModeEnum.cell) {
262
284
  tree.setCellNav(false); // row-nav mode
263
285
  handled = true;
264
286
  }
@@ -269,7 +291,7 @@ export class KeynavExtension extends WunderbaumExtension {
269
291
  node.setExpanded(false);
270
292
  } else if (!isColspan && tree.activeColIdx > 0) {
271
293
  tree.setColumn(tree.activeColIdx - 1);
272
- } else if (navModeOption !== NavigationOptions.cell) {
294
+ } else if (navModeOption !== NavModeEnum.cell) {
273
295
  tree.setCellNav(false); // row-nav mode
274
296
  }
275
297
  handled = true;
@@ -286,17 +308,31 @@ export class KeynavExtension extends WunderbaumExtension {
286
308
  }
287
309
  handled = true;
288
310
  break;
311
+ case "Home": // Generated by [Fn] + ArrowLeft on Mac
312
+ // case "Meta+ArrowLeft":
313
+ tree.setFocus(); // Blur prev. input if any
314
+ if (!isColspan && tree.activeColIdx > 0) {
315
+ tree.setColumn(0);
316
+ }
317
+ handled = true;
318
+ break;
319
+ case "End": // Generated by [Fn] + ArrowRight on Mac
320
+ // case "Meta+ArrowRight":
321
+ tree.setFocus(); // Blur prev. input if any
322
+ if (!isColspan && tree.activeColIdx < tree.columns.length - 1) {
323
+ tree.setColumn(tree.columns.length - 1);
324
+ }
325
+ handled = true;
326
+ break;
289
327
  case "ArrowDown":
290
328
  case "ArrowUp":
291
329
  case "Backspace":
292
- case "End":
293
- case "Home":
294
- case "Control+End":
295
- case "Control+Home":
296
- case "Meta+ArrowDown":
297
- case "Meta+ArrowUp":
298
- case "PageDown":
299
- case "PageUp":
330
+ case "Control+End": // Generated by Control + [Fn] + ArrowRight on Mac
331
+ case "Control+Home": // Generated by Control + [Fn] + Arrowleft on Mac
332
+ case "Meta+ArrowDown": // [⌘] + ArrowDown on Mac
333
+ case "Meta+ArrowUp": // [⌘] + ArrowUp on Mac
334
+ case "PageDown": // Generated by [Fn] + ArrowDown on Mac
335
+ case "PageUp": // Generated by [Fn] + ArrowUp on Mac
300
336
  node.navigate(eventName, { activate: activate, event: event });
301
337
  // if (isCellEditMode) {
302
338
  // this._getEmbeddedInputElem(null, true); // set focus to input