wunderbaum
Version:
JavaScript tree/grid/treegrid control.
1,108 lines (1,107 loc) • 149 kB
TypeScript
declare module "debounce" {
/*!
* Wunderbaum - debounce.ts
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
*/
type Procedure = (...args: any[]) => any;
type DebounceOptions = {
/** Specify invoking on the leading edge of the timeout. @default false */
leading?: boolean;
/** The maximum time `func` is allowed to be delayed before it's invoked.*/
maxWait?: number;
/** Specify invoking on the trailing edge of the timeout. @default true */
trailing?: boolean;
};
type ThrottleOptions = {
/** Specify invoking on the leading edge of the timeout. @default true */
leading?: boolean;
/** Specify invoking on the trailing edge of the timeout. @default true */
trailing?: boolean;
};
export interface DebouncedFunction<F extends Procedure> {
(this: ThisParameterType<F>, ...args: Parameters<F>): ReturnType<F>;
cancel: () => void;
flush: () => any;
pending: () => boolean;
}
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked, or until the next browser frame is drawn. The debounced function
* comes with a `cancel` method to cancel delayed `func` invocations and a
* `flush` method to immediately invoke them. Provide `options` to indicate
* whether `func` should be invoked on the leading and/or trailing edge of the
* `wait` timeout. The `func` is invoked with the last arguments provided to the
* debounced function. Subsequent calls to the debounced function return the
* result of the last `func` invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the debounced function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until the next tick, similar to `setTimeout` with a timeout of `0`.
*
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
* invocation will be deferred until the next frame is drawn (typically about
* 16ms).
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `debounce` and `throttle`.
*
* @since 0.1.0
* @category Function
* @param {Function} func The function to debounce.
* @param {number} [wait=0]
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
* used (if available).
* @param [options={}] The options object.
* @returns {Function} Returns the new debounced function.
* @example
*
* // Avoid costly calculations while the window size is in flux.
* jQuery(window).on('resize', debounce(calculateLayout, 150))
*
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
* jQuery(element).on('click', debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* }))
*
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
* const source = new EventSource('/stream')
* jQuery(source).on('message', debounced)
*
* // Cancel the trailing debounced invocation.
* jQuery(window).on('popstate', debounced.cancel)
*
* // Check for pending invocations.
* const status = debounced.pending() ? "Pending..." : "Ready"
*/
export function debounce<F extends Procedure>(func: F, wait?: number, options?: DebounceOptions): DebouncedFunction<F>;
/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds (or once per browser frame). The throttled function
* comes with a `cancel` method to cancel delayed `func` invocations and a
* `flush` method to immediately invoke them. Provide `options` to indicate
* whether `func` should be invoked on the leading and/or trailing edge of the
* `wait` timeout. The `func` is invoked with the last arguments provided to the
* throttled function. Subsequent calls to the throttled function return the
* result of the last `func` invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until the next tick, similar to `setTimeout` with a timeout of `0`.
*
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
* invocation will be deferred until the next frame is drawn (typically about
* 16ms).
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `throttle` and `debounce`.
*
* @since 0.1.0
* @category Function
* @param {Function} func The function to throttle.
* @param {number} [wait=0]
* The number of milliseconds to throttle invocations to; if omitted,
* `requestAnimationFrame` is used (if available).
* @param [options={}] The options object.
* @returns {Function} Returns the new throttled function.
* @example
*
* // Avoid excessively updating the position while scrolling.
* jQuery(window).on('scroll', throttle(updatePosition, 100))
*
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
* const throttled = throttle(renewToken, 300000, { 'trailing': false })
* jQuery(element).on('click', throttled)
*
* // Cancel the trailing throttled invocation.
* jQuery(window).on('popstate', throttled.cancel)
*/
export function throttle<F extends Procedure>(func: F, wait?: number, options?: ThrottleOptions): DebouncedFunction<F>;
}
declare module "util" {
/*!
* Wunderbaum - util
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
*/
/** @module util */
import { DebouncedFunction, debounce, throttle } from "debounce";
export { debounce, throttle };
/** Readable names for `MouseEvent.button` */
export const MOUSE_BUTTONS: {
[key: number]: string;
};
export const MAX_INT = 9007199254740991;
/**True if the client is using a macOS platform. */
export const isMac: boolean;
export type FunctionType = (...args: any[]) => any;
export type EventCallbackType = (e: Event) => boolean | void;
/** A generic error that can be thrown to indicate a validation error when
* handling the `apply` event for a node title or the `change` event for a
* grid cell.
*/
export class ValidationError extends Error {
constructor(message: string);
}
/**
* A ES6 Promise, that exposes the resolve()/reject() methods.
*
* TODO: See [Promise.withResolvers()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#description)
* , a proposed standard, but not yet implemented in any browser.
*/
export class Deferred {
private thens;
private catches;
private status;
private resolvedValue;
private rejectedError;
constructor();
resolve(value?: any): void;
reject(error?: any): void;
then(cb: any): void;
catch(cb: any): void;
promise(): {
then: (cb: any) => void;
catch: (cb: any) => void;
};
}
/**Throw an `Error` if `cond` is falsey. */
export function assert(cond: any, msg: string): void;
/** Run `callback` when document was loaded. */
export function documentReady(callback: () => void): void;
/** Resolve when document was loaded. */
export function documentReadyPromise(): Promise<void>;
/**
* Iterate over Object properties or array elements.
*
* @param obj `Object`, `Array` or null
* @param callback called for every item.
* `this` also contains the item.
* Return `false` to stop the iteration.
*/
export function each(obj: any, callback: (index: number | string, item: any) => void | boolean): any;
/** Shortcut for `throw new Error(msg)`.*/
export function error(msg: string): void;
/** Convert `<`, `>`, `&`, `"`, `'`, and `/` to the equivalent entities. */
export function escapeHtml(s: string): string;
/**Convert a regular expression string by escaping special characters (e.g. `"$"` -> `"\$"`) */
export function escapeRegex(s: string): string;
/** Convert `<`, `>`, `"`, `'`, and `/` (but not `&`) to the equivalent entities. */
export function escapeTooltip(s: string): string;
/** TODO */
export function extractHtmlText(s: string): string;
/**
* Read the value from an HTML input element.
*
* If a `<span class="wb-col">` is passed, the first child input is used.
* Depending on the target element type, `value` is interpreted accordingly.
* For example for a checkbox, a value of true, false, or null is returned if
* the element is checked, unchecked, or indeterminate.
* For datetime input control a numerical value is assumed, etc.
*
* Common use case: store the new user input in a `change` event handler:
*
* ```ts
* change: (e) => {
* const tree = e.tree;
* const node = e.node;
* // Read the value from the input control that triggered the change event:
* let value = tree.getValueFromElem(e.element);
* // and store it to the node model (assuming the column id matches the property name)
* node.data[e.info.colId] = value;
* },
* ```
* @param elem `<input>` or `<select>` element. Also a parent `span.wb-col` is accepted.
* @param coerce pass true to convert date/time inputs to `Date`.
* @returns the value
*/
export function getValueFromElem(elem: HTMLElement, coerce?: boolean): any;
/**
* Set the value of an HTML input element.
*
* If a `<span class="wb-col">` is passed, the first child input is used.
* Depending on the target element type, `value` is interpreted accordingly.
* For example a checkbox is set to checked, unchecked, or indeterminate if the
* value is truethy, falsy, or `null`.
* For datetime input control a numerical value is assumed, etc.
*
* Common use case: update embedded input controls in a `render` event handler:
*
* ```ts
* render: (e) => {
* // e.node.log(e.type, e, e.node.data);
*
* for (const col of Object.values(e.renderColInfosById)) {
* switch (col.id) {
* default:
* // Assumption: we named column.id === node.data.NAME
* util.setValueToElem(col.elem, e.node.data[col.id]);
* break;
* }
* }
* },
* ```
*
* @param elem `<input>` or `<select>` element Also a parent `span.wb-col` is accepted.
* @param value a value that matches the target element.
*/
export function setValueToElem(elem: HTMLElement, value: any): void;
/** Show/hide element by setting the `display` style to 'none'. */
export function setElemDisplay(elem: string | HTMLElement, flag: boolean): void;
/** Create and return an unconnected `HTMLElement` from a HTML string. */
export function elemFromHtml<T = HTMLElement>(html: string): T;
/** Return a HtmlElement from selector or cast an existing element. */
export function elemFromSelector<T = HTMLElement>(obj: string | T): T | null;
/**
* Return a canonical descriptive string for a keyboard or mouse event.
*
* The result also contains a prefix for modifiers if any, for example
* `"x"`, `"F2"`, `"Control+Home"`, or `"Shift+clickright"`.
* This is especially useful in `switch` statements, to make sure that modifier
* keys are considered and handled correctly:
* ```ts
* const eventName = util.eventToString(e);
* switch (eventName) {
* case "+":
* case "Add":
* ...
* break;
* case "Enter":
* case "End":
* case "Control+End":
* case "Meta+ArrowDown":
* case "PageDown":
* ...
* break;
* }
* ```
*/
export function eventToString(event: Event): string;
/**
* Copy allproperties from one or more source objects to a target object.
*
* @returns the modified target object.
*/
export function extend(...args: any[]): any;
/** Return true if `obj` is of type `array`. */
export function isArray(obj: any): obj is any[];
/** Return true if `obj` is of type `Object` and has no properties. */
export function isEmptyObject(obj: any): boolean;
/** Return true if `obj` is of type `function`. */
export function isFunction(obj: any): boolean;
/** Return true if `obj` is of type `Object`. */
export function isPlainObject(obj: any): boolean;
/** A dummy function that does nothing ('no operation'). */
export function noop(...args: any[]): any;
/**
* Bind one or more event handlers directly to an [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget).
*
* @param rootTarget EventTarget or selector
* @param eventNames
* @param handler
*/
export function onEvent(rootTarget: EventTarget | string, eventNames: string, handler: EventCallbackType): void;
/**
* Bind one or more event handlers using event delegation.
*
* E.g. handle all 'input' events for input and textarea elements of a given
* form:
* ```ts
* onEvent("#form_1", "input", "input,textarea", function (e: Event) {
* console.log(e.type, e.target);
* });
* ```
*
* @param rootTarget EventTarget or selector
* @param eventNames
* @param selector
* @param handler
*/
export function onEvent(rootTarget: EventTarget | string, eventNames: string, selector: string, handler: EventCallbackType): void;
/** Return a wrapped handler method, that provides `this._super` and `this._superApply`.
*
* ```ts
// Implement `opts.createNode` event to add the 'draggable' attribute
overrideMethod(ctx.options, "createNode", (event, data) => {
// Default processing if any
this._super.apply(this, event, data);
// Add 'draggable' attribute
data.node.span.draggable = true;
});
```
*/
export function overrideMethod(instance: any, methodName: string, handler: FunctionType, ctx?: any): void;
/** Run function after ms milliseconds and return a promise that resolves when done. */
export function setTimeoutPromise<T = unknown>(this: unknown, callback: (...args: any[]) => T, ms: number): Promise<T>;
/**
* Wait `ms` microseconds.
*
* Example:
* ```js
* await sleep(1000);
* ```
* @param ms duration
* @returns
*/
export function sleep(ms: number): Promise<unknown>;
/**
* Set or rotate checkbox status with support for tri-state.
*
* An initial 'indeterminate' state becomes 'checked' on the first call.
*
* If the input element has the class 'wb-tristate' assigned, the sequence is:<br>
* 'indeterminate' -> 'checked' -> 'unchecked' -> 'indeterminate' -> ...<br>
* Otherwise we toggle like <br>
* 'checked' -> 'unchecked' -> 'checked' -> ...
*/
export function toggleCheckbox(element: HTMLElement | string, value?: boolean | null, tristate?: boolean): void;
/**
* Return `opts.NAME` if opts is valid and
*
* @param opts dict, object, or null
* @param name option name (use dot notation to access extension option, e.g. `filter.mode`)
* @param defaultValue returned when `opts` is not an object, or does not have a NAME property
*/
export function getOption(opts: any, name: string, defaultValue?: any): any;
/** Return the next value from a list of values (rotating). @since 0.11 */
export function rotate(value: any, values: any[]): any;
/** Convert an Array or space-separated string to a Set. */
export function toSet(val: any): Set<string>;
/** Convert a pixel string to number.
* We accept a number or a string like '123px'. If undefined, the first default
* value that is a number or a string ending with 'px' is returned.
*
* Example:
* ```js
* let x = undefined;
* let y = "123px";
* const width = util.toPixel(x, y, 100); // returns 123
* ```
*/
export function toPixel(...defaults: (string | number | undefined | null)[]): number;
/** Return the the boolean value of the first non-null element.
* Example:
* ```js
* const opts = { flag: true };
* const value = util.toBool(opts.foo, opts.flag, false); // returns true
* ```
*/
export function toBool(...boolDefaults: (boolean | undefined | null)[]): boolean;
/**
* Return `val` unless `val` is a number in which case we convert to boolean.
* This is useful when a boolean value is stored as a 0/1 (e.g. in JSON) and
* we still want to maintain string values. null and undefined are returned as
* is. E.g. `checkbox` may be boolean or 'radio'.
*/
export function intToBool(val: boolean | number | string | undefined): boolean | string | undefined;
/** Return a canonical string representation for an object's type (e.g. 'array', 'number', ...). */
export function type(obj: any): string;
/**
* Return a function that can be called instead of `callback`, but guarantees
* a limited execution rate.
* The execution rate is calculated based on the runtime duration of the
* previous call.
* Example:
* ```js
* throttledFoo = util.adaptiveThrottle(foo.bind(this), {});
* throttledFoo();
* throttledFoo();
* ```
*/
export function adaptiveThrottle(this: unknown, callback: (...args: any[]) => void, options: object): DebouncedFunction<(...args: any[]) => void>;
}
declare module "common" {
/*!
* Wunderbaum - common
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
*/
import { ApplyCommandType, NavigationType, SourceObjectType, IconMapType, MatcherCallback } from "types";
import { WunderbaumNode } from "wb_node";
export const DEFAULT_DEBUGLEVEL = 4;
/**
* Fixed height of a row in pixel. Must match the SCSS variable `$row-outer-height`.
*/
export const DEFAULT_ROW_HEIGHT = 22;
/**
* Fixed width of node icons in pixel. Must match the SCSS variable `$icon-outer-width`.
*/
export const ICON_WIDTH = 20;
/**
* Adjust the width of the title span, so overflow ellipsis work.
* (2 x `$col-padding-x` + 3px rounding errors).
*/
export const TITLE_SPAN_PAD_Y = 7;
/** Render row markup for N nodes above and below the visible viewport. */
export const RENDER_MAX_PREFETCH = 5;
/** Skip rendering new rows when we have at least N nodes rendeed above and below the viewport. */
export const RENDER_MIN_PREFETCH = 5;
/** Minimum column width if not set otherwise. */
export const DEFAULT_MIN_COL_WIDTH = 4;
/** Regular expression to detect if a string describes an image URL (in contrast
* to a class name). Strings are considered image urls if they contain '.' or '/'.
*/
export const TEST_IMG: RegExp;
/**
* Default node icons for icon libraries
*
* - 'bootstrap': {@link https://icons.getbootstrap.com}
* - 'fontawesome6' {@link https://fontawesome.com/icons}
*
*/
export const iconMaps: {
[key: string]: IconMapType;
};
export const KEY_NODATA = "__not_found__";
/** Define which keys are handled by embedded <input> control, and should
* *not* be passed to tree navigation handler in cell-edit mode.
*/
export const INPUT_KEYS: {
[key: string]: Array<string>;
};
/** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */
export const RESERVED_TREE_SOURCE_KEYS: Set<string>;
/** Map `KeyEvent.key` to navigation action. */
export const KEY_TO_NAVIGATION_MAP: {
[key: string]: NavigationType;
};
/** Map `KeyEvent.key` to navigation action. */
export const KEY_TO_COMMAND_MAP: {
[key: string]: ApplyCommandType;
};
/** Return a callback that returns true if the node title matches the string
* or regular expression.
* @see {@link WunderbaumNode.findAll}
*/
export function makeNodeTitleMatcher(match: string | RegExp): MatcherCallback;
/** Return a callback that returns true if the node title starts with a string (case-insensitive). */
export function makeNodeTitleStartMatcher(s: string): MatcherCallback;
/** Compare two nodes by title (case-insensitive). */
export function nodeTitleSorter(a: WunderbaumNode, b: WunderbaumNode): number;
/**
* Decompresses the source data by
* - converting from 'flat' to 'nested' format
* - expanding short alias names to long names (if defined in _keyMap)
* - resolving value indexes to value strings (if defined in _valueMap)
*
* @param source - The source object to be decompressed.
* @returns void
*/
export function decompressSourceData(source: SourceObjectType): void;
}
declare module "deferred" {
/*!
* Wunderbaum - deferred
* Copyright (c) 2021-2025, Martin Wendt. Released under the MIT license.
* @VERSION, @DATE (https://github.com/mar10/wunderbaum)
*/
type PromiseCallbackType = (val: any) => void;
type finallyCallbackType = () => void;
/**
* Implement a ES6 Promise, that exposes a resolve() and reject() method.
*
* Loosely mimics {@link https://api.jquery.com/category/deferred-object/ | jQuery.Deferred}.
* Example:
* ```js
* function foo() {
* let dfd = new Deferred(),
* ...
* dfd.resolve('foo')
* ...
* return dfd.promise();
* }
* ```
*/
export class Deferred<T> {
private _promise;
protected _resolve: any;
protected _reject: any;
constructor();
/** Resolve the Promise. */
resolve(value?: any): void;
/** Reject the Promise. */
reject(reason?: any): void;
/** Return the native Promise instance.*/
promise(): Promise<T>;
/** Call Promise.then on the embedded promise instance.*/
then(cb: PromiseCallbackType): Promise<void>;
/** Call Promise.catch on the embedded promise instance.*/
catch(cb: PromiseCallbackType): Promise<void | T>;
/** Call Promise.finally on the embedded promise instance.*/
finally(cb: finallyCallbackType): Promise<T>;
}
}
declare module "wb_node" {
import { Wunderbaum } from "wunderbaum";
import { AddChildrenOptions, ApplyCommandOptions, ApplyCommandType, ChangeType, CheckboxOption, ExpandAllOptions, IconOption, InsertNodeType, MakeVisibleOptions, MatcherCallback, NavigateOptions, NavigationType, NodeAnyCallback, NodeStatusType, NodeStringCallback, NodeToDictCallback, NodeVisitCallback, NodeVisitResponse, RenderOptions, ResetOrderOptions, ScrollIntoViewOptions, SetActiveOptions, SetExpandedOptions, SetSelectedOptions, SetStatusOptions, SortByPropertyOptions, SortCallback, SourceType, TooltipOption, TristateType, WbNodeData } from "types";
/**
* A single tree node.
*
* **NOTE:** <br>
* Generally you should not modify properties directly, since this may break
* the internal bookkeeping.
*/
export class WunderbaumNode {
static sequence: number;
/** Reference to owning tree. */
tree: Wunderbaum;
/** Parent node (null for the invisible root node `tree.root`). */
parent: WunderbaumNode;
/** Name of the node.
* @see Use {@link setTitle} to modify. */
title: string;
/** Unique key. Passed with constructor or defaults to `SEQUENCE`.
* @see Use {@link setKey} to modify. */
readonly key: string;
/** Reference key. Unlike {@link key}, a `refKey` may occur multiple
* times within a tree (in this case we have 'clone nodes').
* @see Use {@link setKey} to modify.
*/
readonly refKey: string | undefined;
/**
* Array of child nodes (null for leaf nodes).
* For lazy nodes, this is `null` or ùndefined` until the children are loaded
* and leaf nodes may be `[]` (empty array).
* @see {@link hasChildren}, {@link addChildren}, {@link lazy}.
*/
children: WunderbaumNode[] | null;
/** Render a checkbox or radio button @see {@link selected}. */
checkbox?: CheckboxOption;
/** If true, this node's children are considerd radio buttons.
* @see {@link isRadio}.
*/
radiogroup?: boolean;
/** If true, (in grid mode) no cells are rendered, except for the node title.*/
colspan?: boolean;
/** Icon definition. */
icon?: IconOption;
/** Lazy loading flag.
* @see {@link isLazy}, {@link isLoaded}, {@link isUnloaded}.
*/
lazy?: boolean;
/** Expansion state.
* @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
expanded?: boolean;
/** Selection state.
* @see {@link isSelected}, {@link setSelected}, {@link toggleSelected}. */
selected?: boolean;
unselectable?: boolean;
/** Node type (used for styling).
* @see {@link Wunderbaum.types}.
*/
type?: string;
/** Tooltip definition (`true`: use node's title). */
tooltip?: TooltipOption;
/** Icon tooltip definition (`true`: use node's title). */
iconTooltip?: TooltipOption;
/** Additional classes added to `div.wb-row`.
* @see {@link hasClass}, {@link setClass}. */
classes: Set<string> | null;
/** Custom data that was passed to the constructor */
data: any;
statusNodeType?: NodeStatusType;
_isLoading: boolean;
_requestId: number;
_errorInfo: any | null;
_partsel: boolean;
_partload: boolean;
/**
* > 0 if matched (-1 to keep system nodes visible);
* Added and removed by filter code.
*/
match?: number;
subMatchCount?: number;
/** @internal */
titleWithHighlight?: string;
_filterAutoExpanded?: boolean;
_rowIdx: number | undefined;
_rowElem: HTMLDivElement | undefined;
constructor(tree: Wunderbaum, parent: WunderbaumNode, data: any);
/**
* Return readable string representation for this instance.
* @internal
*/
toString(): string;
/**
* Iterate all descendant nodes depth-first, pre-order using `for ... of ...` syntax.
* More concise, but slightly slower than {@link WunderbaumNode.visit}.
*
* Example:
* ```js
* for(const n of node) {
* ...
* }
* ```
*/
[Symbol.iterator](): IterableIterator<WunderbaumNode>;
/** Call event handler if defined in tree.options.
* Example:
* ```js
* node._callEvent("edit.beforeEdit", {foo: 42})
* ```
*/
_callEvent(type: string, extra?: any): any;
/**
* Append (or insert) a list of child nodes.
*
* Tip: pass `{ before: 0 }` to prepend new nodes as first children.
*
* @returns first child added
*/
addChildren(nodeData: WbNodeData | WbNodeData[], options?: AddChildrenOptions): WunderbaumNode;
/**
* Append or prepend a node, or append a child node.
*
* This a convenience function that calls addChildren()
*
* @param nodeData node definition
* @param [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child')
* @returns new node
*/
addNode(nodeData: WbNodeData, mode?: InsertNodeType): WunderbaumNode;
/**
* Apply a modification (or navigation) operation.
*
* @see {@link Wunderbaum.applyCommand}
*/
applyCommand(cmd: ApplyCommandType, options: ApplyCommandOptions): any;
/**
* Collapse all expanded sibling nodes if any.
* (Automatically called when `autoCollapse` is true.)
*/
collapseSiblings(options?: SetExpandedOptions): any;
/**
* Add/remove one or more classes to `<div class='wb-row'>`.
*
* This also maintains `node.classes`, so the class will survive a re-render.
*
* @param className one or more class names. Multiple classes can be passed
* as space-separated string, array of strings, or set of strings.
*/
setClass(className: string | string[] | Set<string>, flag?: boolean): void;
/** Start editing this node's title. */
startEditTitle(): void;
/**
* Call `setExpanded()` on all descendant nodes.
*
* @param flag true to expand, false to collapse.
* @param options Additional options.
* @see {@link Wunderbaum.expandAll}
* @see {@link WunderbaumNode.setExpanded}
*/
expandAll(flag?: boolean, options?: ExpandAllOptions): Promise<void>;
/**
* Find all descendant nodes that match condition (excluding self).
*
* If `match` is a string, search for exact node title.
* If `match` is a RegExp expression, apply it to node.title, using
* [RegExp.test()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test).
* If `match` is a callback, match all nodes for that the callback(node) returns true.
*
* Returns an empty array if no nodes were found.
*
* Examples:
* ```js
* // Match all node titles that match exactly 'Joe':
* nodeList = node.findAll("Joe")
* // Match all node titles that start with 'Joe' case sensitive:
* nodeList = node.findAll(/^Joe/)
* // Match all node titles that contain 'oe', case insensitive:
* nodeList = node.findAll(/oe/i)
* // Match all nodes with `data.price` >= 99:
* nodeList = node.findAll((n) => {
* return n.data.price >= 99;
* })
* ```
*/
findAll(match: string | RegExp | MatcherCallback): WunderbaumNode[];
/** Return the direct child with a given key, index or null. */
findDirectChild(ptr: number | string | WunderbaumNode): WunderbaumNode | null;
/**
* Find first descendant node that matches condition (excluding self) or null.
*
* @see {@link WunderbaumNode.findAll} for examples.
*/
findFirst(match: string | RegExp | MatcherCallback): WunderbaumNode | null;
/** Find a node relative to self.
*
* @see {@link Wunderbaum.findRelatedNode|tree.findRelatedNode()}
*/
findRelatedNode(where: NavigationType, includeHidden?: boolean): any;
/**
* Iterator version of {@link WunderbaumNode.format}.
*/
format_iter(name_cb?: NodeStringCallback, connectors?: string[]): IterableIterator<string>;
/**
* Return a multiline string representation of a node/subnode hierarchy.
* Mostly useful for debugging.
*
* Example:
* ```js
* console.info(tree.getActiveNode().format((n)=>n.title));
* ```
* logs
* ```
* Books
* ├─ Art of War
* ╰─ Don Quixote
* ```
* @see {@link WunderbaumNode.format_iter}
*/
format(name_cb?: NodeStringCallback, connectors?: string[]): string;
/** Return the `<span class='wb-col'>` element with a given index or id.
* @returns {WunderbaumNode | null}
*/
getColElem(colIdx: number | string): HTMLSpanElement;
/**
* Return all nodes with the same refKey.
*
* @param includeSelf Include this node itself.
* @see {@link Wunderbaum.findByRefKey}
*/
getCloneList(includeSelf?: boolean): WunderbaumNode[];
/** Return the first child node or null.
* @returns {WunderbaumNode | null}
*/
getFirstChild(): WunderbaumNode;
/** Return the last child node or null.
* @returns {WunderbaumNode | null}
*/
getLastChild(): WunderbaumNode;
/** Return node depth (starting with 1 for top level nodes). */
getLevel(): number;
/** Return the successive node (under the same parent) or null. */
getNextSibling(): WunderbaumNode | null;
/** Return the parent node (null for the system root node). */
getParent(): WunderbaumNode | null;
/** Return an array of all parent nodes (top-down).
* @param includeRoot Include the invisible system root node.
* @param includeSelf Include the node itself.
*/
getParentList(includeRoot?: boolean, includeSelf?: boolean): any[];
/** Return a string representing the hierachical node path, e.g. "a/b/c".
* @param includeSelf
* @param part property name or callback
* @param separator
*/
getPath(includeSelf?: boolean, part?: keyof WunderbaumNode | NodeAnyCallback, separator?: string): string;
/** Return the preceeding node (under the same parent) or null. */
getPrevSibling(): WunderbaumNode | null;
/** Return true if node has children.
* Return undefined if not sure, i.e. the node is lazy and not yet loaded.
*/
hasChildren(): boolean;
/** Return true if node has className set. */
hasClass(className: string): boolean;
/** Return true if node ist the currently focused node. @since 0.9.0 */
hasFocus(): boolean;
/** Return true if this node is the currently active tree node. */
isActive(): boolean;
/** Return true if this node is a direct or indirect parent of `other`.
* @see {@link WunderbaumNode.isParentOf}
*/
isAncestorOf(other: WunderbaumNode): boolean;
/** Return true if this node is a **direct** subnode of `other`.
* @see {@link WunderbaumNode.isDescendantOf}
*/
isChildOf(other: WunderbaumNode): boolean;
/** Return true if this node's refKey is used by at least one other node.
*/
isClone(): boolean;
/** Return true if this node's title spans all columns, i.e. the node has no
* grid cells.
*/
isColspan(): boolean;
/** Return true if this node is a direct or indirect subnode of `other`.
* @see {@link WunderbaumNode.isChildOf}
*/
isDescendantOf(other: WunderbaumNode): boolean;
/** Return true if this node has children, i.e. the node is generally expandable.
* If `andCollapsed` is set, we also check if this node is collapsed, i.e.
* an expand operation is currently possible.
*/
isExpandable(andCollapsed?: boolean): boolean;
/** Return true if _this_ node is currently in edit-title mode.
*
* See {@link WunderbaumNode.startEditTitle}.
*/
isEditingTitle(): boolean;
/** Return true if this node is currently expanded. */
isExpanded(): boolean;
/** Return true if this node is the first node of its parent's children. */
isFirstSibling(): boolean;
/** Return true if this node is the last node of its parent's children. */
isLastSibling(): boolean;
/** Return true if this node is lazy (even if data was already loaded) */
isLazy(): boolean;
/** Return true if node is lazy and loaded. For non-lazy nodes always return true. */
isLoaded(): boolean;
/** Return true if node is currently loading, i.e. a GET request is pending. */
isLoading(): boolean;
/** Return true if this node is a temporarily generated status node of type 'paging'. */
isPagingNode(): boolean;
/** Return true if this node is a **direct** parent of `other`.
* @see {@link WunderbaumNode.isAncestorOf}
*/
isParentOf(other: WunderbaumNode): boolean;
/** Return true if this node is partially loaded. @experimental */
isPartload(): boolean;
/** Return true if this node is partially selected (tri-state). */
isPartsel(): boolean;
/** Return true if this node has DOM representaion, i.e. is displayed in the viewport. */
isRadio(): boolean;
/** Return true if this node has DOM representaion, i.e. is displayed in the viewport. */
isRendered(): boolean;
/** Return true if this node is the (invisible) system root node.
* @see {@link WunderbaumNode.isTopLevel}
*/
isRootNode(): boolean;
/** Return true if this node is selected, i.e. the checkbox is set.
* `undefined` if partly selected (tri-state), false otherwise.
*/
isSelected(): TristateType;
/** Return true if this node is a temporarily generated system node like
* 'loading', 'paging', or 'error' (node.statusNodeType contains the type).
*/
isStatusNode(): boolean;
/** Return true if this a top level node, i.e. a direct child of the (invisible) system root node. */
isTopLevel(): boolean;
/** Return true if node is marked lazy but not yet loaded.
* For non-lazy nodes always return false.
*/
isUnloaded(): boolean;
/** Return true if all parent nodes are expanded. Note: this does not check
* whether the node is scrolled into the visible part of the screen or viewport.
*/
isVisible(): boolean;
protected _loadSourceObject(source: any, level?: number): void;
_fetchWithOptions(source: any): Promise<any>;
/** Download data from the cloud, then call `.update()`. */
load(source: SourceType): Promise<void>;
/**
* Load content of a lazy node.
* If the node is already loaded, nothing happens.
* @param [forceReload=false] If true, reload even if already loaded.
*/
loadLazy(forceReload?: boolean): Promise<void>;
/** Write to `console.log` with node name as prefix if opts.debugLevel >= 4.
* @see {@link WunderbaumNode.logDebug}
*/
log(...args: any[]): void;
/** Write to `console.debug` with node name as prefix if opts.debugLevel >= 4
* and browser console level includes debug/verbose messages.
* @see {@link WunderbaumNode.log}
*/
logDebug(...args: any[]): void;
/** Write to `console.error` with node name as prefix if opts.debugLevel >= 1. */
logError(...args: any[]): void;
/** Write to `console.info` with node name as prefix if opts.debugLevel >= 3. */
logInfo(...args: any[]): void;
/** Write to `console.warn` with node name as prefix if opts.debugLevel >= 2. */
logWarn(...args: any[]): void;
/** Expand all parents and optionally scroll into visible area as neccessary.
* Promise is resolved, when lazy loading and animations are done.
* @param {object} [options] passed to `setExpanded()`.
* Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true}
*/
makeVisible(options?: MakeVisibleOptions): Promise<unknown>;
/** Move this node to targetNode. */
moveTo(targetNode: WunderbaumNode, mode?: InsertNodeType, map?: NodeAnyCallback): void;
/** Set focus relative to this node and optionally activate.
*
* 'left' collapses the node if it is expanded, or move to the parent
* otherwise.
* 'right' expands the node if it is collapsed, or move to the first
* child otherwise.
*
* @param where 'down', 'first', 'last', 'left', 'parent', 'right', or 'up'.
* (Alternatively the `event.key` that would normally trigger this move,
* e.g. `ArrowLeft` = 'left'.
* @param options
*/
navigate(where: NavigationType | string, options?: NavigateOptions): Promise<any>;
/** Delete this node and all descendants. */
remove(): void;
/** Remove all descendants of this node. */
removeChildren(): void;
/** Remove all HTML markup from the DOM. */
removeMarkup(): void;
protected _getRenderInfo(): any;
protected _createIcon(parentElem: HTMLElement, replaceChild: HTMLElement | null, showLoading: boolean): HTMLElement | null;
/**
* Create a whole new `<div class="wb-row">` element.
* @see {@link WunderbaumNode._render}
*/
protected _render_markup(opts: RenderOptions): void;
/**
* Render `node.title`, `.icon` into an existing row.
*
* @see {@link WunderbaumNode._render}
*/
protected _render_data(opts: RenderOptions): void;
/**
* Update row classes to reflect active, focuses, etc.
* @see {@link WunderbaumNode._render}
*/
protected _render_status(opts: RenderOptions): void;
_render(options?: RenderOptions): void;
/**
* Remove all children, collapse, and set the lazy-flag, so that the lazyLoad
* event is triggered on next expand.
*/
resetLazy(): void;
/** Convert node (or whole branch) into a plain object.
*
* The result is compatible with node.addChildren().
*
* @param recursive include child nodes
* @param callback is called for every node, in order to allow
* modifications.
* Return `false` to ignore this node or `"skip"` to include this node
* without its children.
* @see {@link Wunderbaum.toDictArray}.
*/
toDict(recursive?: boolean, callback?: NodeToDictCallback): WbNodeData;
/** Return an option value that has a default, but may be overridden by a
* callback or a node instance attribute.
*
* Evaluation sequence:
*
* - If `tree.options.<name>` is a callback that returns something, use that.
* - Else if `node.<name>` is defined, use that.
* - Else if `tree.types[<node.type>]` is a value, use that.
* - Else if `tree.options.<name>` is a value, use that.
* - Else use `defaultValue`.
*
* @param name name of the option property (on node and tree)
* @param defaultValue return this if nothing else matched
* {@link Wunderbaum.getOption|Wunderbaum.getOption}
*/
getOption(name: string, defaultValue?: any): any;
/** Make sure that this node is visible in the viewport.
* @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo}
*/
scrollIntoView(options?: ScrollIntoViewOptions): Promise<void>;
/**
* Activate this node, deactivate previous, send events, activate column and
* scroll into viewport.
*/
setActive(flag?: boolean, options?: SetActiveOptions): Promise<void>;
/**
* Expand or collapse this node.
*/
setExpanded(flag?: boolean, options?: SetExpandedOptions): Promise<void>;
/**
* Set keyboard focus here.
* @see {@link setActive}
*/
setFocus(flag?: boolean): void;
/** Set a new icon path or class. */
setIcon(icon: string): void;
/** Change node's {@link key} and/or {@link refKey}. */
setKey(key: string | null, refKey: string | null): void;
/**
* Trigger a repaint, typically after a status or data change.
*
* `change` defaults to 'data', which handles modifcations of title, icon,
* and column content. It can be reduced to 'ChangeType.status' if only
* active/focus/selected state has changed.
*
* This method will eventually call {@link WunderbaumNode._render} with
* default options, but may be more consistent with the tree's
* {@link Wunderbaum.update} API.
*/
update(change?: ChangeType): void;
/**
* Return an array of selected nodes.
* @param stopOnParents only return the topmost selected node (useful with selectMode 'hier')
*/
getSelectedNodes(stopOnParents?: boolean): WunderbaumNode[];
/** Toggle the check/uncheck state. */
toggleSelected(options?: SetSelectedOptions): TristateType;
/** Return true if at least on selectable descendant end-node is unselected. @internal */
_anySelectable(): boolean;
protected _changeSelectStatusProps(state: TristateType): boolean;
/**
* Fix selection status, after this node was (de)selected in `selectMode: 'hier'`.
* This includes (de)selecting all descendants.
*/
fixSelection3AfterClick(opts?: SetSelectedOptions): void;
/**
* Fix selection status for multi-hier mode.
* Only end-nodes are considered to update the descendants branch and parents.
* Should be called after this node has loaded new children or after
* children have been modified using the API.
*/
fixSelection3FromEndNodes(opts?: SetSelectedOptions): void;
/** Modify the check/uncheck state. */
setSelected(flag?: boolean, options?: SetSelectedOptions): TristateType;
/** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
setStatus(status: NodeStatusType, options?: SetStatusOptions): WunderbaumNode | null;
/** Rename this node. */
setTitle(title: string): void;
/** Set the node tooltip. */
setTooltip(tooltip: TooltipOption): void;
_sortChildren(cmp: SortCallback, deep: boolean): void;
/**
* Sort child list by title or custom criteria.
* @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1
* (defaults to sorting by title).
* @param {boolean} deep pass true to sort all descendant nodes recursively
*/
sortChildren(cmp?: SortCallback | null, deep?: boolean): void;
/**
* Renumber nodes `_nativeIndex`. This is useful to allow to restore the
* order after sorting a column.
* This method is automatically called after loading new child nodes.
* @since 0.11.0
*/
resetNativeChildOrder(options?: ResetOrderOptions): void;
/**
* Convenience method to implement column sorting.
* @since 0.11.0
*/
sortByProperty(options: SortByPropertyOptions): void;
/**
* Trigger `modifyChild` event on a parent to signal that a child was modified.
* @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
*/
triggerModifyChild(operation: string, child: WunderbaumNode | null, extra?: any): void;
/**
* Trigger `modifyChild` event on node.parent(!).
* @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
* @param {object} [extra]
*/
triggerModify(operation: string, extra?: any): void;
/**
* Call `callback(node)` for all descendant nodes in hierarchical order (depth-first, pre-order).
*
* Stop iteration, if fn() returns false. Skip current branch, if fn()
* returns "skip".<br>
* Return false if iteration was stopped.
*
* @param {function} callback the callback function.
* Return false to stop iteration, return "skip" to skip this node and
* its children only.
* @see {@link IterableIterator<WunderbaumNode>}, {@link Wunderbaum.visit}.
*/
visit(callback: NodeVisitCallback, includeSelf?: boolean): NodeVisitResponse;
/** Call fn(node) for all parent nodes, bottom-up, including invisible system root.<br>
* Stop iteration, if callback() returns false.<br>
* Return false if iteration was stopped.
*
* @param callback the callback function. Return false to stop iteration
*/
visitParents(callback: (node: WunderbaumNode) => boolean | void, includeSelf?: boolean): boolean;
/**
* Call fn(node) for all sibling nodes.<br>
* Stop iteration, if fn() returns false.<br>