wunderbaum 0.0.1 → 0.0.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.
- package/README.md +3 -2
- package/dist/wunderbaum.css +1 -1
- package/dist/wunderbaum.d.ts +400 -80
- package/dist/wunderbaum.esm.js +356 -135
- package/dist/wunderbaum.esm.min.js +28 -18
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +358 -137
- package/dist/wunderbaum.umd.min.js +34 -24
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +29 -30
- package/src/common.ts +6 -5
- package/src/drag_observer.ts +169 -0
- package/src/util.ts +47 -13
- package/src/wb_ext_dnd.ts +144 -3
- package/src/wb_ext_filter.ts +35 -35
- package/src/wb_ext_grid.ts +45 -0
- package/src/wb_node.ts +23 -29
- package/src/wb_options.ts +138 -25
- package/src/wunderbaum.scss +20 -1
- package/src/wunderbaum.ts +82 -37
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Wunderbaum - drag_observer
|
|
3
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
4
|
+
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
|
|
5
|
+
*/
|
|
6
|
+
import * as util from "./util";
|
|
7
|
+
|
|
8
|
+
export type DragCallbackArgType = {
|
|
9
|
+
/** "dragstart", "drag", or "dragstop". */
|
|
10
|
+
type: string;
|
|
11
|
+
/** Original mouse or touch event that triggered the drag event. */
|
|
12
|
+
event: MouseEvent | TouchEvent;
|
|
13
|
+
/** Element which is currently dragged. */
|
|
14
|
+
dragElem: HTMLElement | null;
|
|
15
|
+
/** Relative horizontal drag distance since start. */
|
|
16
|
+
dx: number;
|
|
17
|
+
/** Relative vertical drag distance since start. */
|
|
18
|
+
dy: number;
|
|
19
|
+
/** False if drag was canceled. */
|
|
20
|
+
apply?: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type DragCallbackType = (e: DragCallbackArgType) => boolean | void;
|
|
23
|
+
type DragObserverOptionsType = {
|
|
24
|
+
/**Event target (typically `window.document`). */
|
|
25
|
+
root: EventTarget;
|
|
26
|
+
/**Event delegation selector.*/
|
|
27
|
+
selector?: string;
|
|
28
|
+
/**Minimum drag distance in px. */
|
|
29
|
+
thresh?: number;
|
|
30
|
+
/**Return `false` to cancel drag. */
|
|
31
|
+
dragstart: DragCallbackType;
|
|
32
|
+
drag?: DragCallbackType;
|
|
33
|
+
dragstop?: DragCallbackType;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
|
|
38
|
+
*/
|
|
39
|
+
export class DragObserver {
|
|
40
|
+
protected _handler;
|
|
41
|
+
protected root: EventTarget;
|
|
42
|
+
protected start = {
|
|
43
|
+
x: 0,
|
|
44
|
+
y: 0,
|
|
45
|
+
altKey: false,
|
|
46
|
+
ctrlKey: false,
|
|
47
|
+
metaKey: false,
|
|
48
|
+
shiftKey: false,
|
|
49
|
+
};
|
|
50
|
+
protected dragElem: HTMLElement | null = null;
|
|
51
|
+
protected dragging: boolean = false;
|
|
52
|
+
// TODO: touch events
|
|
53
|
+
protected events = ["mousedown", "mouseup", "mousemove", "keydown"];
|
|
54
|
+
protected opts: DragObserverOptionsType;
|
|
55
|
+
|
|
56
|
+
constructor(opts: DragObserverOptionsType) {
|
|
57
|
+
util.assert(opts.root);
|
|
58
|
+
this.opts = util.extend({ thresh: 5 }, opts);
|
|
59
|
+
this.root = opts.root;
|
|
60
|
+
this._handler = this.handleEvent.bind(this) as EventListener;
|
|
61
|
+
this.events.forEach((type) => {
|
|
62
|
+
this.root.addEventListener(type, this._handler);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Unregister all event listeners. */
|
|
66
|
+
disconnect() {
|
|
67
|
+
this.events.forEach((type) => {
|
|
68
|
+
this.root.removeEventListener(type, this._handler);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public getDragElem(): HTMLElement | null {
|
|
73
|
+
return this.dragElem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public isDragging(): boolean {
|
|
77
|
+
return this.dragging;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public stopDrag(cb_event?: DragCallbackArgType): void {
|
|
81
|
+
if (this.dragging && this.opts.dragstop && cb_event) {
|
|
82
|
+
cb_event.type = "dragstop";
|
|
83
|
+
this.opts.dragstop(cb_event);
|
|
84
|
+
}
|
|
85
|
+
this.dragElem = null;
|
|
86
|
+
this.dragging = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected handleEvent(e: MouseEvent): boolean | void {
|
|
90
|
+
const type = e.type;
|
|
91
|
+
const opts = this.opts;
|
|
92
|
+
const cb_event: DragCallbackArgType = {
|
|
93
|
+
type: e.type,
|
|
94
|
+
event: e,
|
|
95
|
+
dragElem: this.dragElem,
|
|
96
|
+
dx: e.pageX - this.start.x,
|
|
97
|
+
dy: e.pageY - this.start.y,
|
|
98
|
+
apply: undefined,
|
|
99
|
+
};
|
|
100
|
+
switch (type) {
|
|
101
|
+
case "keydown":
|
|
102
|
+
this.stopDrag(cb_event);
|
|
103
|
+
break;
|
|
104
|
+
case "mousedown":
|
|
105
|
+
if (this.dragElem) {
|
|
106
|
+
this.stopDrag(cb_event);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
if (opts.selector) {
|
|
110
|
+
let elem = e.target as HTMLElement;
|
|
111
|
+
if (elem.matches(opts.selector)) {
|
|
112
|
+
this.dragElem = elem;
|
|
113
|
+
} else {
|
|
114
|
+
elem = elem.closest(opts.selector) as HTMLElement;
|
|
115
|
+
if (elem) {
|
|
116
|
+
this.dragElem = elem;
|
|
117
|
+
} else {
|
|
118
|
+
break; // no event delegation selector matched
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
this.start.x = e.pageX;
|
|
123
|
+
this.start.y = e.pageY;
|
|
124
|
+
this.start.altKey = e.altKey;
|
|
125
|
+
this.start.ctrlKey = e.ctrlKey;
|
|
126
|
+
this.start.metaKey = e.metaKey;
|
|
127
|
+
this.start.shiftKey = e.shiftKey;
|
|
128
|
+
break;
|
|
129
|
+
|
|
130
|
+
case "mousemove":
|
|
131
|
+
// TODO: debounce/throttle?
|
|
132
|
+
// TODO: horizontal mode: ignore if dx unchanged
|
|
133
|
+
if (!this.dragElem) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
if (!this.dragging) {
|
|
137
|
+
if (opts.thresh) {
|
|
138
|
+
const dist2 = cb_event.dx * cb_event.dx + cb_event.dy * cb_event.dy;
|
|
139
|
+
if (dist2 < opts.thresh * opts.thresh) {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
cb_event.type = "dragstart";
|
|
144
|
+
if (opts.dragstart(cb_event) === false) {
|
|
145
|
+
this.stopDrag(cb_event);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
this.dragging = true;
|
|
149
|
+
}
|
|
150
|
+
if (this.dragging && this.opts.drag) {
|
|
151
|
+
cb_event.type = "drag";
|
|
152
|
+
this.opts.drag(cb_event);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
case "mouseup":
|
|
156
|
+
if (!this.dragging) {
|
|
157
|
+
this.stopDrag(cb_event);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
if (e.button === 0) {
|
|
161
|
+
cb_event.apply = true;
|
|
162
|
+
} else {
|
|
163
|
+
cb_event.apply = false;
|
|
164
|
+
}
|
|
165
|
+
this.stopDrag(cb_event);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -16,7 +16,7 @@ export const MOUSE_BUTTONS: { [key: number]: string } = {
|
|
|
16
16
|
|
|
17
17
|
export const MAX_INT = 9007199254740991;
|
|
18
18
|
const userInfo = _getUserInfo();
|
|
19
|
-
/**True if the
|
|
19
|
+
/**True if the client is using a macOS platform. */
|
|
20
20
|
export const isMac = userInfo.isMac;
|
|
21
21
|
|
|
22
22
|
const REX_HTML = /[&<>"'/]/g; // Escape those characters
|
|
@@ -186,7 +186,7 @@ export function escapeTooltip(s: string): string {
|
|
|
186
186
|
/** TODO */
|
|
187
187
|
export function extractHtmlText(s: string) {
|
|
188
188
|
if (s.indexOf(">") >= 0) {
|
|
189
|
-
error("
|
|
189
|
+
error("Not implemented");
|
|
190
190
|
// return $("<div/>").html(s).text();
|
|
191
191
|
}
|
|
192
192
|
return s;
|
|
@@ -315,7 +315,7 @@ export function setValueToElem(elem: HTMLElement, value: any): void {
|
|
|
315
315
|
input.valueAsNumber = value;
|
|
316
316
|
break;
|
|
317
317
|
case "radio":
|
|
318
|
-
|
|
318
|
+
error("Not implemented");
|
|
319
319
|
// const name = input.name;
|
|
320
320
|
// const checked = input.parentElement!.querySelector(
|
|
321
321
|
// `input[name="${name}"]:checked`
|
|
@@ -338,7 +338,7 @@ export function setValueToElem(elem: HTMLElement, value: any): void {
|
|
|
338
338
|
// return value;
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
/**
|
|
341
|
+
/** Create and return an unconnected `HTMLElement` from a HTML string. */
|
|
342
342
|
export function elemFromHtml(html: string): HTMLElement {
|
|
343
343
|
const t = document.createElement("template");
|
|
344
344
|
t.innerHTML = html.trim();
|
|
@@ -358,11 +358,26 @@ export function elemFromSelector(obj: string | Element): HTMLElement | null {
|
|
|
358
358
|
return obj as HTMLElement;
|
|
359
359
|
}
|
|
360
360
|
|
|
361
|
+
/** Return a EventTarget from selector or cast an existing element. */
|
|
362
|
+
export function eventTargetFromSelector(
|
|
363
|
+
obj: string | EventTarget
|
|
364
|
+
): EventTarget | null {
|
|
365
|
+
if (!obj) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
if (typeof obj === "string") {
|
|
369
|
+
return document.querySelector(obj) as EventTarget;
|
|
370
|
+
}
|
|
371
|
+
return obj as EventTarget;
|
|
372
|
+
}
|
|
373
|
+
|
|
361
374
|
/**
|
|
362
|
-
* Return a descriptive string for a keyboard or mouse event.
|
|
375
|
+
* Return a canonical descriptive string for a keyboard or mouse event.
|
|
363
376
|
*
|
|
364
377
|
* The result also contains a prefix for modifiers if any, for example
|
|
365
378
|
* `"x"`, `"F2"`, `"Control+Home"`, or `"Shift+clickright"`.
|
|
379
|
+
* This is especially useful in `switch` statements, to make sure that modifier
|
|
380
|
+
* keys are considered and handled correctly.
|
|
366
381
|
*/
|
|
367
382
|
export function eventToString(event: Event): string {
|
|
368
383
|
let key = (<KeyboardEvent>event).key,
|
|
@@ -397,6 +412,13 @@ export function eventToString(event: Event): string {
|
|
|
397
412
|
return s.join("+");
|
|
398
413
|
}
|
|
399
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Copy allproperties from one or more source objects to a target object.
|
|
417
|
+
*
|
|
418
|
+
* @returns the modified target object.
|
|
419
|
+
*/
|
|
420
|
+
// TODO: use Object.assign()? --> https://stackoverflow.com/a/42740894
|
|
421
|
+
// TODO: support deep merge --> https://stackoverflow.com/a/42740894
|
|
400
422
|
export function extend(...args: any[]) {
|
|
401
423
|
for (let i = 1; i < args.length; i++) {
|
|
402
424
|
let arg = args[i];
|
|
@@ -412,18 +434,22 @@ export function extend(...args: any[]) {
|
|
|
412
434
|
return args[0];
|
|
413
435
|
}
|
|
414
436
|
|
|
437
|
+
/** Return true if `obj` is of type `array`. */
|
|
415
438
|
export function isArray(obj: any) {
|
|
416
439
|
return Array.isArray(obj);
|
|
417
440
|
}
|
|
418
441
|
|
|
442
|
+
/** Return true if `obj` is of type `Object` and has no propertied. */
|
|
419
443
|
export function isEmptyObject(obj: any) {
|
|
420
444
|
return Object.keys(obj).length === 0 && obj.constructor === Object;
|
|
421
445
|
}
|
|
422
446
|
|
|
447
|
+
/** Return true if `obj` is of type `function`. */
|
|
423
448
|
export function isFunction(obj: any) {
|
|
424
449
|
return typeof obj === "function";
|
|
425
450
|
}
|
|
426
451
|
|
|
452
|
+
/** Return true if `obj` is of type `Object`. */
|
|
427
453
|
export function isPlainObject(obj: any) {
|
|
428
454
|
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
429
455
|
}
|
|
@@ -432,14 +458,14 @@ export function isPlainObject(obj: any) {
|
|
|
432
458
|
export function noop(...args: any[]): any {}
|
|
433
459
|
|
|
434
460
|
/**
|
|
435
|
-
* Bind one or more event handlers directly to an [[
|
|
461
|
+
* Bind one or more event handlers directly to an [[EventTarget]].
|
|
436
462
|
*
|
|
437
|
-
* @param element
|
|
463
|
+
* @param element EventTarget or selector
|
|
438
464
|
* @param eventNames
|
|
439
465
|
* @param handler
|
|
440
466
|
*/
|
|
441
467
|
export function onEvent(
|
|
442
|
-
|
|
468
|
+
rootTarget: EventTarget | string,
|
|
443
469
|
eventNames: string,
|
|
444
470
|
handler: EventCallbackType
|
|
445
471
|
): void;
|
|
@@ -455,26 +481,26 @@ export function onEvent(
|
|
|
455
481
|
* });
|
|
456
482
|
* ```
|
|
457
483
|
*
|
|
458
|
-
* @param element
|
|
484
|
+
* @param element EventTarget or selector
|
|
459
485
|
* @param eventNames
|
|
460
486
|
* @param selector
|
|
461
487
|
* @param handler
|
|
462
488
|
*/
|
|
463
489
|
export function onEvent(
|
|
464
|
-
|
|
490
|
+
rootTarget: EventTarget | string,
|
|
465
491
|
eventNames: string,
|
|
466
492
|
selector: string,
|
|
467
493
|
handler: EventCallbackType
|
|
468
494
|
): void;
|
|
469
495
|
|
|
470
496
|
export function onEvent(
|
|
471
|
-
|
|
497
|
+
rootTarget: EventTarget | string,
|
|
472
498
|
eventNames: string,
|
|
473
499
|
selectorOrHandler: string | EventCallbackType,
|
|
474
500
|
handlerOrNone?: EventCallbackType
|
|
475
501
|
): void {
|
|
476
502
|
let selector: string | null, handler: EventCallbackType;
|
|
477
|
-
|
|
503
|
+
rootTarget = eventTargetFromSelector(rootTarget)!;
|
|
478
504
|
|
|
479
505
|
if (handlerOrNone) {
|
|
480
506
|
selector = selectorOrHandler as string;
|
|
@@ -485,7 +511,7 @@ export function onEvent(
|
|
|
485
511
|
}
|
|
486
512
|
|
|
487
513
|
eventNames.split(" ").forEach((evn) => {
|
|
488
|
-
(<
|
|
514
|
+
(<EventTarget>rootTarget).addEventListener(evn, function (e) {
|
|
489
515
|
if (!selector) {
|
|
490
516
|
return handler!(e); // no event delegation
|
|
491
517
|
} else if (e.target) {
|
|
@@ -578,6 +604,13 @@ export async function sleep(ms: number) {
|
|
|
578
604
|
|
|
579
605
|
/**
|
|
580
606
|
* Set or rotate checkbox status with support for tri-state.
|
|
607
|
+
*
|
|
608
|
+
* An initial 'indeterminate' state becomes 'checked' on the first call.
|
|
609
|
+
*
|
|
610
|
+
* If the input element has the class 'wb-tristate' assigned, the sequence is:<br>
|
|
611
|
+
* 'indeterminate' -> 'checked' -> 'unchecked' -> 'indeterminate' -> ...<br>
|
|
612
|
+
* Otherwise we toggle like <br>
|
|
613
|
+
* 'checked' -> 'unchecked' -> 'checked' -> ...
|
|
581
614
|
*/
|
|
582
615
|
export function toggleCheckbox(
|
|
583
616
|
element: HTMLElement | string,
|
|
@@ -648,6 +681,7 @@ export function toSet(val: any): Set<string> {
|
|
|
648
681
|
throw new Error("Cannot convert to Set<string>: " + val);
|
|
649
682
|
}
|
|
650
683
|
|
|
684
|
+
/**Return a canonical string representation for an object's type (e.g. 'array', 'number', ...) */
|
|
651
685
|
export function type(obj: any): string {
|
|
652
686
|
return Object.prototype.toString
|
|
653
687
|
.call(obj)
|
package/src/wb_ext_dnd.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { EventCallbackType, onEvent } from "./util";
|
|
|
8
8
|
import { Wunderbaum } from "./wunderbaum";
|
|
9
9
|
import { WunderbaumExtension } from "./wb_extension_base";
|
|
10
10
|
import { WunderbaumNode } from "./wb_node";
|
|
11
|
-
import { ROW_HEIGHT } from "./common";
|
|
11
|
+
import { ROW_HEIGHT, WbNodeEventType } from "./common";
|
|
12
12
|
|
|
13
13
|
const nodeMimeType = "application/x-wunderbaum-node";
|
|
14
14
|
export type DropRegionType = "over" | "before" | "after";
|
|
@@ -24,6 +24,147 @@ type DropRegionTypeSet = Set<DropRegionType>;
|
|
|
24
24
|
// | "none" // == false == "" == null
|
|
25
25
|
// | "over"; // == "child"
|
|
26
26
|
|
|
27
|
+
export type DndOptionsType = {
|
|
28
|
+
/**
|
|
29
|
+
* Expand nodes after n milliseconds of hovering
|
|
30
|
+
* Default: 1500
|
|
31
|
+
*/
|
|
32
|
+
autoExpandMS: 1500;
|
|
33
|
+
// /**
|
|
34
|
+
// * Additional offset for drop-marker with hitMode = "before"/"after"
|
|
35
|
+
// * Default:
|
|
36
|
+
// */
|
|
37
|
+
// dropMarkerInsertOffsetX: -16;
|
|
38
|
+
// /**
|
|
39
|
+
// * Absolute position offset for .fancytree-drop-marker relatively to ..fancytree-title (icon/img near a node accepting drop)
|
|
40
|
+
// * Default:
|
|
41
|
+
// */
|
|
42
|
+
// dropMarkerOffsetX: -24;
|
|
43
|
+
// /**
|
|
44
|
+
// * Root Container used for drop marker (could be a shadow root)
|
|
45
|
+
// * (#1021 `document.body` is not available yet)
|
|
46
|
+
// * Default:
|
|
47
|
+
// */
|
|
48
|
+
// dropMarkerParent: "body";
|
|
49
|
+
/**
|
|
50
|
+
* true: Drag multiple (i.e. selected) nodes. Also a callback() is allowed
|
|
51
|
+
* Default: false
|
|
52
|
+
*/
|
|
53
|
+
multiSource: false;
|
|
54
|
+
/**
|
|
55
|
+
* Restrict the possible cursor shapes and modifier operations (can also be set in the dragStart event)
|
|
56
|
+
* Default: "all"
|
|
57
|
+
*/
|
|
58
|
+
effectAllowed: "all";
|
|
59
|
+
// /**
|
|
60
|
+
// * 'copy'|'link'|'move'|'auto'(calculate from `effectAllowed`+modifier keys) or callback(node, data) that returns such string.
|
|
61
|
+
// * Default:
|
|
62
|
+
// */
|
|
63
|
+
// dropEffect: "auto";
|
|
64
|
+
/**
|
|
65
|
+
* Default dropEffect ('copy', 'link', or 'move') when no modifier is pressed (overide in dragDrag, dragOver).
|
|
66
|
+
* Default: "move"
|
|
67
|
+
*/
|
|
68
|
+
dropEffectDefault: string;
|
|
69
|
+
/**
|
|
70
|
+
* Prevent dropping nodes from different Wunderbaum trees
|
|
71
|
+
* Default: false
|
|
72
|
+
*/
|
|
73
|
+
preventForeignNodes: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Prevent dropping items on unloaded lazy Wunderbaum tree nodes
|
|
76
|
+
* Default: true
|
|
77
|
+
*/
|
|
78
|
+
preventLazyParents: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Prevent dropping items other than Wunderbaum tree nodes
|
|
81
|
+
* Default: false
|
|
82
|
+
*/
|
|
83
|
+
preventNonNodes: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Prevent dropping nodes on own descendants
|
|
86
|
+
* Default: true
|
|
87
|
+
*/
|
|
88
|
+
preventRecursion: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Prevent dropping nodes under same direct parent
|
|
91
|
+
* Default: false
|
|
92
|
+
*/
|
|
93
|
+
preventSameParent: false;
|
|
94
|
+
/**
|
|
95
|
+
* Prevent dropping nodes 'before self', etc. (move only)
|
|
96
|
+
* Default: true
|
|
97
|
+
*/
|
|
98
|
+
preventVoidMoves: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Enable auto-scrolling while dragging
|
|
101
|
+
* Default: true
|
|
102
|
+
*/
|
|
103
|
+
scroll: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Active top/bottom margin in pixel
|
|
106
|
+
* Default: 20
|
|
107
|
+
*/
|
|
108
|
+
scrollSensitivity: 20;
|
|
109
|
+
/**
|
|
110
|
+
* Pixel per event
|
|
111
|
+
* Default: 5
|
|
112
|
+
*/
|
|
113
|
+
scrollSpeed: 5;
|
|
114
|
+
// /**
|
|
115
|
+
// * Allow dragging of nodes to different IE windows
|
|
116
|
+
// * Default: false
|
|
117
|
+
// */
|
|
118
|
+
// setTextTypeJson: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Optional callback passed to `toDict` on dragStart @since 2.38
|
|
121
|
+
* Default: null
|
|
122
|
+
*/
|
|
123
|
+
sourceCopyHook: null;
|
|
124
|
+
// Events (drag support)
|
|
125
|
+
/**
|
|
126
|
+
* Callback(sourceNode, data), return true, to enable dnd drag
|
|
127
|
+
* Default: null
|
|
128
|
+
*/
|
|
129
|
+
dragStart?: WbNodeEventType;
|
|
130
|
+
/**
|
|
131
|
+
* Callback(sourceNode, data)
|
|
132
|
+
* Default: null
|
|
133
|
+
*/
|
|
134
|
+
dragDrag: null;
|
|
135
|
+
/**
|
|
136
|
+
* Callback(sourceNode, data)
|
|
137
|
+
* Default: null
|
|
138
|
+
*/
|
|
139
|
+
dragEnd: null;
|
|
140
|
+
// Events (drop support)
|
|
141
|
+
/**
|
|
142
|
+
* Callback(targetNode, data), return true, to enable dnd drop
|
|
143
|
+
* Default: null
|
|
144
|
+
*/
|
|
145
|
+
dragEnter: null;
|
|
146
|
+
/**
|
|
147
|
+
* Callback(targetNode, data)
|
|
148
|
+
* Default: null
|
|
149
|
+
*/
|
|
150
|
+
dragOver: null;
|
|
151
|
+
/**
|
|
152
|
+
* Callback(targetNode, data), return false to prevent autoExpand
|
|
153
|
+
* Default: null
|
|
154
|
+
*/
|
|
155
|
+
dragExpand: null;
|
|
156
|
+
/**
|
|
157
|
+
* Callback(targetNode, data)
|
|
158
|
+
* Default: null
|
|
159
|
+
*/
|
|
160
|
+
dragDrop: null;
|
|
161
|
+
/**
|
|
162
|
+
* Callback(targetNode, data)
|
|
163
|
+
* Default: null
|
|
164
|
+
*/
|
|
165
|
+
dragLeave: null;
|
|
166
|
+
};
|
|
167
|
+
|
|
27
168
|
export class DndExtension extends WunderbaumExtension {
|
|
28
169
|
// public dropMarkerElem?: HTMLElement;
|
|
29
170
|
protected srcNode: WunderbaumNode | null = null;
|
|
@@ -78,7 +219,7 @@ export class DndExtension extends WunderbaumExtension {
|
|
|
78
219
|
// this.$scrollParent = $temp.scrollParent();
|
|
79
220
|
// $temp.remove();
|
|
80
221
|
const tree = this.tree;
|
|
81
|
-
const dndOpts = tree.options.dnd
|
|
222
|
+
const dndOpts = tree.options.dnd!;
|
|
82
223
|
|
|
83
224
|
// Enable drag support if dragStart() is specified:
|
|
84
225
|
if (dndOpts.dragStart) {
|
|
@@ -153,7 +294,7 @@ export class DndExtension extends WunderbaumExtension {
|
|
|
153
294
|
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
154
295
|
protected autoScroll(event: DragEvent): number {
|
|
155
296
|
let tree = this.tree,
|
|
156
|
-
dndOpts = tree.options.dnd
|
|
297
|
+
dndOpts = tree.options.dnd!,
|
|
157
298
|
sp = tree.scrollContainer,
|
|
158
299
|
sensitivity = dndOpts.scrollSensitivity,
|
|
159
300
|
speed = dndOpts.scrollSpeed,
|
package/src/wb_ext_filter.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
escapeHtml,
|
|
10
10
|
escapeRegex,
|
|
11
11
|
extend,
|
|
12
|
-
extractHtmlText,
|
|
13
12
|
onEvent,
|
|
14
13
|
} from "./util";
|
|
15
14
|
import { NodeFilterCallback, NodeStatusType } from "./common";
|
|
@@ -79,7 +78,7 @@ export class FilterExtension extends WunderbaumExtension {
|
|
|
79
78
|
count = 0,
|
|
80
79
|
tree = this.tree,
|
|
81
80
|
treeOpts = tree.options,
|
|
82
|
-
escapeTitles = treeOpts.escapeTitles,
|
|
81
|
+
// escapeTitles = treeOpts.escapeTitles,
|
|
83
82
|
prevAutoCollapse = treeOpts.autoCollapse,
|
|
84
83
|
opts = extend({}, treeOpts.filter, _opts),
|
|
85
84
|
hideMode = opts.mode === "hide",
|
|
@@ -118,35 +117,36 @@ export class FilterExtension extends WunderbaumExtension {
|
|
|
118
117
|
if (!node.title) {
|
|
119
118
|
return false;
|
|
120
119
|
}
|
|
121
|
-
let text = escapeTitles ? node.title : extractHtmlText(node.title);
|
|
120
|
+
// let text = escapeTitles ? node.title : extractHtmlText(node.title);
|
|
121
|
+
let text = node.title;
|
|
122
122
|
// `.match` instead of `.test` to get the capture groups
|
|
123
123
|
let res = text.match(re);
|
|
124
124
|
|
|
125
125
|
if (res && opts.highlight) {
|
|
126
|
-
if (escapeTitles) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} else {
|
|
130
|
-
// #740: we must not apply the marks to escaped entity names, e.g. `"`
|
|
131
|
-
// Use some exotic characters to mark matches:
|
|
132
|
-
temp = text.replace(reHighlight, function (s) {
|
|
133
|
-
return START_MARKER + s + END_MARKER;
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
// now we can escape the title...
|
|
137
|
-
node.titleWithHighlight = escapeHtml(temp)
|
|
138
|
-
// ... and finally insert the desired `<mark>` tags
|
|
139
|
-
.replace(RE_START_MARKER, "<mark>")
|
|
140
|
-
.replace(RE_END_MARTKER, "</mark>");
|
|
126
|
+
// if (escapeTitles) {
|
|
127
|
+
if (opts.fuzzy) {
|
|
128
|
+
temp = _markFuzzyMatchedChars(text, res, true);
|
|
141
129
|
} else {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
148
|
-
}
|
|
130
|
+
// #740: we must not apply the marks to escaped entity names, e.g. `"`
|
|
131
|
+
// Use some exotic characters to mark matches:
|
|
132
|
+
temp = text.replace(reHighlight, function (s) {
|
|
133
|
+
return START_MARKER + s + END_MARKER;
|
|
134
|
+
});
|
|
149
135
|
}
|
|
136
|
+
// now we can escape the title...
|
|
137
|
+
node.titleWithHighlight = escapeHtml(temp)
|
|
138
|
+
// ... and finally insert the desired `<mark>` tags
|
|
139
|
+
.replace(RE_START_MARKER, "<mark>")
|
|
140
|
+
.replace(RE_END_MARTKER, "</mark>");
|
|
141
|
+
// } else {
|
|
142
|
+
// if (opts.fuzzy) {
|
|
143
|
+
// node.titleWithHighlight = _markFuzzyMatchedChars(text, res);
|
|
144
|
+
// } else {
|
|
145
|
+
// node.titleWithHighlight = text.replace(reHighlight, function (s) {
|
|
146
|
+
// return "<mark>" + s + "</mark>";
|
|
147
|
+
// });
|
|
148
|
+
// }
|
|
149
|
+
// }
|
|
150
150
|
// node.debug("filter", escapeTitles, text, node.titleWithHighlight);
|
|
151
151
|
}
|
|
152
152
|
return !!res;
|
|
@@ -266,9 +266,9 @@ export class FilterExtension extends WunderbaumExtension {
|
|
|
266
266
|
* [ext-filter] Reset the filter.
|
|
267
267
|
*/
|
|
268
268
|
clearFilter() {
|
|
269
|
-
let tree = this.tree
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
let tree = this.tree;
|
|
270
|
+
// statusNode = tree.root.findDirectChild(KEY_NODATA),
|
|
271
|
+
// escapeTitles = tree.options.escapeTitles;
|
|
272
272
|
// enhanceTitle = tree.options.enhanceTitle,
|
|
273
273
|
tree.enableUpdate(false);
|
|
274
274
|
|
|
@@ -284,11 +284,11 @@ export class FilterExtension extends WunderbaumExtension {
|
|
|
284
284
|
if (node.match && node._rowElem) {
|
|
285
285
|
// #491, #601
|
|
286
286
|
let titleElem = node._rowElem.querySelector("span.wb-title")!;
|
|
287
|
-
if (escapeTitles) {
|
|
288
|
-
|
|
289
|
-
} else {
|
|
290
|
-
|
|
291
|
-
}
|
|
287
|
+
// if (escapeTitles) {
|
|
288
|
+
titleElem.textContent = node.title;
|
|
289
|
+
// } else {
|
|
290
|
+
// titleElem.innerHTML = node.title;
|
|
291
|
+
// }
|
|
292
292
|
node._callEvent("enhanceTitle", { titleElem: titleElem });
|
|
293
293
|
}
|
|
294
294
|
delete node.match;
|
|
@@ -330,7 +330,7 @@ export class FilterExtension extends WunderbaumExtension {
|
|
|
330
330
|
function _markFuzzyMatchedChars(
|
|
331
331
|
text: string,
|
|
332
332
|
matches: RegExpMatchArray,
|
|
333
|
-
escapeTitles =
|
|
333
|
+
escapeTitles = true
|
|
334
334
|
) {
|
|
335
335
|
let matchingIndices = [];
|
|
336
336
|
// get the indices of matched characters (Iterate through `RegExpMatchArray`)
|
|
@@ -350,7 +350,7 @@ function _markFuzzyMatchedChars(
|
|
|
350
350
|
// Map each `text` char to its position and store in `textPoses`.
|
|
351
351
|
let textPoses = text.split("");
|
|
352
352
|
if (escapeTitles) {
|
|
353
|
-
// If escaping the title, then wrap the
|
|
353
|
+
// If escaping the title, then wrap the matching char within exotic chars
|
|
354
354
|
matchingIndices.forEach(function (v) {
|
|
355
355
|
textPoses[v] = START_MARKER + textPoses[v] + END_MARKER;
|
|
356
356
|
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Wunderbaum - ext-grid
|
|
3
|
+
* Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
|
|
4
|
+
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
|
|
5
|
+
*/
|
|
6
|
+
import { Wunderbaum } from "./wunderbaum";
|
|
7
|
+
import { WunderbaumExtension } from "./wb_extension_base";
|
|
8
|
+
import { DragCallbackArgType, DragObserver } from "./drag_observer";
|
|
9
|
+
|
|
10
|
+
export class GridExtension extends WunderbaumExtension {
|
|
11
|
+
protected observer: DragObserver;
|
|
12
|
+
|
|
13
|
+
constructor(tree: Wunderbaum) {
|
|
14
|
+
super(tree, "grid", {
|
|
15
|
+
// throttle: 200,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
this.observer = new DragObserver({
|
|
19
|
+
root: window.document,
|
|
20
|
+
selector: "span.wb-col-resizer",
|
|
21
|
+
thresh: 4,
|
|
22
|
+
// throttle: 400,
|
|
23
|
+
dragstart: (e) => {
|
|
24
|
+
return this.tree.element.contains(e.dragElem);
|
|
25
|
+
},
|
|
26
|
+
drag: (e) => {
|
|
27
|
+
// TODO: throttle
|
|
28
|
+
return this.handleDrag(e);
|
|
29
|
+
},
|
|
30
|
+
dragstop: (e) => {
|
|
31
|
+
return this.handleDrag(e);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
init() {
|
|
37
|
+
super.init();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected handleDrag(e: DragCallbackArgType): void {
|
|
41
|
+
const info = Wunderbaum.getEventInfo(e.event);
|
|
42
|
+
// this.tree.options.
|
|
43
|
+
this.tree.log(`${e.type}(${e.dx})`, e, info);
|
|
44
|
+
}
|
|
45
|
+
}
|