wunderbaum 0.0.4 → 0.0.5

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 CHANGED
@@ -9,6 +9,8 @@
9
9
  > Potential successor of [Fancytree](https://github.com/mar10/fancytree).<br>
10
10
  > **NOTE: Status _experimental_. Do not use in production!**
11
11
 
12
+ [![Demo](docs/assets/teaser_1.png?raw=true)](https://mar10.github.io/wunderbaum/demo/)
13
+
12
14
  <!-- https://de.wikipedia.org/wiki/Wunderbaum -->
13
15
 
14
16
  Wunderbaum is a rewrite of the [Fancytree](https://github.com/mar10/fancytree)
@@ -2,4 +2,4 @@
2
2
  * Wunderbaum style sheet (generated from wunderbaum.scss)
3
3
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
4
4
  * @VERSION, @DATE (https://github.com/mar10/wunderbaum)
5
- */div.wunderbaum{box-sizing:border-box;height:100%;background-color:#fff;margin:0;padding:0;font-family:Helvetica,sans-serif;font-size:14px;color:#56534c;border:2px solid #56534c;border-radius:4px;background-clip:content-box;overflow:hidden}div.wunderbaum:focus,div.wunderbaum:focus-within{border-color:#275dc5}div.wunderbaum div.wb-scroll-container{position:relative;overflow:auto;min-height:4px}div.wunderbaum div.wb-row{position:absolute;width:100%;height:22px;line-height:22px;border:1px solid transparent}div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active,div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected{background-color:#f0f0f0;border-color:#acacac}div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected:hover,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected:hover{background-color:#eaeaea}div.wunderbaum div.wb-node-list div.wb-row:hover{background-color:#f7fcfe}div.wunderbaum div.wb-node-list div.wb-row.wb-active,div.wunderbaum div.wb-node-list div.wb-row.wb-selected{background-color:#e5f3fb}div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum div.wb-node-list div.wb-row.wb-selected:hover{background-color:#dceff8}div.wunderbaum div.wb-node-list div.wb-row.wb-focus:not(.wb-active){border-style:dotted;border-color:#70c0e7}div.wunderbaum div.wb-node-list div.wb-row.wb-active{border-style:solid;border-color:#70c0e7}div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover{border-color:#26a0da}div.wunderbaum div.wb-node-list div.wb-row.wb-loading{font-style:italic}div.wunderbaum div.wb-node-list div.wb-row.wb-dirty,div.wunderbaum div.wb-node-list div.wb-row .wb-col.wb-dirty{font-style:italic;background:repeating-linear-gradient(45deg, #f7fcfe, #f7fcfe 5px, #dedede 5px, #dedede 10px);animation:wb-dirty-animation 2s linear infinite}div.wunderbaum div.wb-node-list div.wb-row.wb-error,div.wunderbaum div.wb-node-list div.wb-row.wb-status-error{color:#b5373b}div.wunderbaum div.wb-header{position:relative;height:22px;border-bottom:1px solid #56534c;padding:0;background-color:#dedede}div.wunderbaum div.wb-header span.wb-col{font-weight:bold}div.wunderbaum span.wb-col{position:absolute;display:inline-block;height:20px;line-height:20px;padding:0 2px;border-right:1px solid #dedede;overflow:visible}div.wunderbaum span.wb-col:last-of-type{border-right:none}div.wunderbaum span.wb-col span.wb-col-title{width:100%;overflow:hidden;text-overflow:ellipsis}div.wunderbaum span.wb-col span.wb-col-resizer{position:absolute;top:0;right:-1px;width:3px;border:none;border-right:2px solid #56534c;height:100%;cursor:col-resize}div.wunderbaum span.wb-node{user-select:none}div.wunderbaum i.wb-checkbox,div.wunderbaum i.wb-expander,div.wunderbaum i.wb-icon,div.wunderbaum i.wb-indent{height:20px;width:20px;padding:2px 2px;display:inline-block}div.wunderbaum i.bi::before{vertical-align:baseline}div.wunderbaum img.wb-icon{width:16px;height:16px;padding:2px 2px}div.wunderbaum i.wb-indent::before{content:"\00a0"}div.wunderbaum i.wb-expander.wb-spin,div.wunderbaum i.wb-icon.wb-spin{height:unset;width:unset;padding:0 3px;animation:wb-spin-animation 2s linear infinite}div.wunderbaum span.wb-title{min-width:1em;display:inline-block;vertical-align:top;overflow-x:hidden;white-space:nowrap;text-overflow:ellipsis}div.wunderbaum.wb-grid div.wb-header div.wb-row span.wb-col:hover{background-color:#c5c5c5}div.wunderbaum.wb-grid.wb-cell-mode div.wb-header div.wb-row span.wb-col.wb-active{background-color:#dceff8}div.wunderbaum.wb-grid div.wb-node-list div.wb-row{border-bottom-color:#dedede}div.wunderbaum.wb-grid div.wb-node-list div.wb-row:hover:not(.wb-active):not(.wb-selected){background-color:#f7fcfe}div.wunderbaum.wb-grid div.wb-node-list div.wb-row.wb-active{border-bottom-color:#70c0e7}div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col{border-right:1px solid #dedede}div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col input.wb-input-edit,div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="color"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="date"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="datetime"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="datetime-local"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="email"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="month"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="number"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="password"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="search"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="tel"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="text"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="time"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="url"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="week"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>select{width:100%}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row{background-color:#fff}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row span.wb-col.wb-active{background-color:#f7fcfe}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row.wb-active{background-color:#f7fcfe}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row.wb-active span.wb-col.wb-active{background-color:#26a0da}div.wunderbaum.wb-grid.wb-cell-mode.wb-cell-edit-mode div.wb-row.wb-active span.wb-col.wb-active{background-color:#b5373b}div.wunderbaum.wb-grid.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected){background-color:#fcfcfc}div.wunderbaum.wb-grid.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected):hover{background-color:#f7fcfe}div.wunderbaum.wb-grid:not(:focus-within) div.wb-node-list div.wb-row,div.wunderbaum.wb-grid:not(:focus) div.wb-node-list div.wb-row{border-bottom-color:#dedede}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row{color:#dedede}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-submatch,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-submatch{color:#868581}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-match,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-match{color:#56534c}div.wunderbaum div.wb-row.wb-drag-source{opacity:0.5}div.wunderbaum div.wb-row.wb-drag-source .wb-node{background-color:#d3d2ce}div.wunderbaum div.wb-row.wb-drop-target{overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node{background-color:#d4ecf8;overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon{position:relative;overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon::after{position:absolute;z-index:1000;content:url(../docs/assets/drop_marker_16x32.png);left:0;top:3px}div.wunderbaum div.wb-row.wb-drop-target.wb-drop-before .wb-node .wb-icon::after{content:url(../docs/assets/drop_marker_insert_16x64.png);left:0;top:-8px}div.wunderbaum div.wb-row.wb-drop-target.wb-drop-after .wb-node .wb-icon::after{content:url(../docs/assets/drop_marker_insert_16x64.png);left:0;top:14px}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+1),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+1){background:#ffffe8}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+2),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+2){background:#f0fff0}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+3),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+3){background:#fff0ff}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+4),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+4){background:#eafdfd}div.wunderbaum.wb-fade-expander i.wb-expander{transition:color 1.5s;color:rgba(86,83,76,0)}div.wunderbaum.wb-fade-expander div.wb-row.wb-loading i.wb-expander,div.wunderbaum.wb-fade-expander:hover i.wb-expander,div.wunderbaum.wb-fade-expander:focus i.wb-expander,div.wunderbaum.wb-fade-expander:focus-within i.wb-expander,div.wunderbaum.wb-fade-expander [class*="wb-statusnode-"] i.wb-expander{transition:color 0.6s;color:#56534c}div.wunderbaum div.wb-row.wb-skeleton span.wb-title,div.wunderbaum div.wb-row.wb-skeleton i.wb-icon{animation:wb-skeleton-animation 1s linear infinite alternate;border-radius:0.25em;color:transparent;opacity:0.7}div.wunderbaum.wb-checkbox-auto-hide i.wb-checkbox{visibility:hidden}div.wunderbaum.wb-checkbox-auto-hide .wb-row:hover i.wb-checkbox,div.wunderbaum.wb-checkbox-auto-hide .wb-row.wb-selected i.wb-checkbox{visibility:unset}div.wunderbaum.wb-checkbox-auto-hide:focus .wb-row.wb-active i.wb-checkbox,div.wunderbaum.wb-checkbox-auto-hide:focus-within .wb-row.wb-active i.wb-checkbox{visibility:unset}.wb-helper-center{text-align:center}.wb-helper-disabled{color:#8c877c}.wb-helper-hidden{display:none}.wb-helper-invalid{color:#b5373b}.wb-helper-lazy-expander{color:#26a0da}.wb-helper-link{cursor:pointer}.wb-helper-start{text-align:left}.wb-helper-end{text-align:right}.wb-rtl .wb-helper-start{text-align:right}.wb-rtl .wb-helper-end{text-align:left}.wb-col input[type="checkbox"]:indeterminate{color:#8c877c;background-color:red}.wb-col input:invalid{color:#b5373b;background-color:#f5ddde}@keyframes wb-spin-animation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes wb-skeleton-animation{0%{background-color:#a3b8c2}100%{background-color:#f0f3f5}}@keyframes wb-dirty-animation{0%{background-position:0 0}100%{background-position:-70px 0}}
5
+ */div.wunderbaum{box-sizing:border-box;height:100%;background-color:#fff;margin:0;padding:0;font-family:Helvetica,sans-serif;font-size:14px;color:#56534c;border:2px solid #56534c;border-radius:4px;background-clip:content-box;overflow-x:auto;overflow-y:scroll}div.wunderbaum:focus,div.wunderbaum:focus-within{border-color:#275dc5}div.wunderbaum.wb-disabled{opacity:0.7;pointer-events:none}div.wunderbaum div.wb-scroll-container{position:relative;min-height:4px}div.wunderbaum div.wb-header{position:sticky;top:0;z-index:2}div.wunderbaum div.wb-header,div.wunderbaum div.wb-scroll-container{overflow:unset}div.wunderbaum.wb-fixed-col div.wb-header span.wb-col:first-of-type{background-color:#dedede}div.wunderbaum.wb-fixed-col span.wb-col:first-of-type{position:sticky;left:0;z-index:1;background-color:#fff}div.wunderbaum div.wb-row{position:absolute;width:100%;height:22px;line-height:22px;border:1px solid transparent}div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active,div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected{background-color:#f0f0f0;border-color:#acacac}div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected:hover,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected:hover{background-color:#eaeaea}div.wunderbaum.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected){background-color:#f7f7f7}div.wunderbaum.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected):hover{background-color:#f3f3f3}div.wunderbaum div.wb-node-list div.wb-row:hover{background-color:#f7fcfe}div.wunderbaum div.wb-node-list div.wb-row.wb-active,div.wunderbaum div.wb-node-list div.wb-row.wb-selected{background-color:#e5f3fb}div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover,div.wunderbaum div.wb-node-list div.wb-row.wb-selected:hover{background-color:#dceff8}div.wunderbaum div.wb-node-list div.wb-row.wb-focus:not(.wb-active){border-style:dotted;border-color:#70c0e7}div.wunderbaum div.wb-node-list div.wb-row.wb-active{border-style:solid;border-color:#70c0e7}div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover{border-color:#26a0da}div.wunderbaum div.wb-node-list div.wb-row.wb-loading{font-style:italic}div.wunderbaum div.wb-node-list div.wb-row.wb-busy,div.wunderbaum div.wb-node-list div.wb-row i.wb-busy,div.wunderbaum div.wb-node-list div.wb-row .wb-col.wb-busy{font-style:italic;background:repeating-linear-gradient(45deg, transparent, transparent 3.88px, #dedede 3.88px, #dedede 7.78px);animation:wb-busy-animation 2s linear infinite}div.wunderbaum div.wb-node-list div.wb-row.wb-error,div.wunderbaum div.wb-node-list div.wb-row.wb-status-error{color:#b5373b}div.wunderbaum div.wb-header{position:sticky;height:22px;border-bottom:1px solid #56534c;padding:0;background-color:#dedede}div.wunderbaum div.wb-header span.wb-col{font-weight:bold}div.wunderbaum span.wb-col{position:absolute;display:inline-block;height:20px;line-height:20px;padding:0 2px;border-right:1px solid #dedede;overflow:visible}div.wunderbaum span.wb-col:last-of-type{border-right:none}div.wunderbaum span.wb-col span.wb-col-title{width:100%;overflow:hidden;text-overflow:ellipsis}div.wunderbaum span.wb-col span.wb-col-resizer{position:absolute;top:0;right:-1px;width:3px;border:none;border-right:2px solid #56534c;height:100%;cursor:col-resize}div.wunderbaum span.wb-node{user-select:none}div.wunderbaum i.wb-checkbox,div.wunderbaum i.wb-expander,div.wunderbaum i.wb-icon,div.wunderbaum i.wb-indent{height:20px;width:20px;padding:2px 2px;display:inline-block}div.wunderbaum i.bi::before{vertical-align:baseline}div.wunderbaum img.wb-icon{width:16px;height:16px;padding:2px 2px}div.wunderbaum i.wb-indent::before{content:"\00a0"}div.wunderbaum i.wb-expander.wb-spin,div.wunderbaum i.wb-icon.wb-spin{height:unset;width:unset;padding:0 3px;animation:wb-spin-animation 2s linear infinite}div.wunderbaum span.wb-title{min-width:1em;vertical-align:top;overflow-x:hidden;white-space:nowrap;text-overflow:ellipsis}div.wunderbaum.wb-grid div.wb-header div.wb-row span.wb-col:hover{background-color:#c5c5c5}div.wunderbaum.wb-grid.wb-cell-mode div.wb-header div.wb-row span.wb-col.wb-active{background-color:#dceff8}div.wunderbaum.wb-grid div.wb-node-list div.wb-row{border-bottom-color:#dedede}div.wunderbaum.wb-grid div.wb-node-list div.wb-row:hover:not(.wb-active):not(.wb-selected){background-color:#f7fcfe}div.wunderbaum.wb-grid div.wb-node-list div.wb-row.wb-active{border-bottom-color:#70c0e7}div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col{border-right:1px solid #dedede}div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col input.wb-input-edit,div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="color"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="date"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="datetime"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="datetime-local"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="email"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="month"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="number"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="password"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="search"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="tel"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="text"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="time"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="url"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>input[type="week"],div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col>select{width:100%;max-height:20px}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row{background-color:#fff}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row span.wb-col.wb-active{background-color:#f7fcfe}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row.wb-active{background-color:#f7fcfe}div.wunderbaum.wb-grid.wb-cell-mode div.wb-row.wb-active span.wb-col.wb-active{background-color:#26a0da}div.wunderbaum.wb-grid.wb-cell-mode.wb-cell-edit-mode div.wb-row.wb-active span.wb-col.wb-active{background-color:#b5373b}div.wunderbaum.wb-grid.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected){background-color:#f7f7f7}div.wunderbaum.wb-grid.wb-alternate div.wb-node-list div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected):hover{background-color:#f3f3f3}div.wunderbaum.wb-grid:not(:focus-within) div.wb-node-list div.wb-row,div.wunderbaum.wb-grid:not(:focus) div.wb-node-list div.wb-row{border-bottom-color:#dedede}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row{color:#dedede}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-submatch,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-submatch{color:#868581}div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-match,div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-match{color:#56534c}div.wunderbaum div.wb-row.wb-drag-source{opacity:0.5}div.wunderbaum div.wb-row.wb-drag-source .wb-node{background-color:#d3d2ce}div.wunderbaum div.wb-row.wb-drop-target{overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node{background-color:#d4ecf8;overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon{position:relative;overflow:visible}div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon::after{position:absolute;z-index:1000;content:url(../docs/assets/drop_marker_16x32.png);left:0;top:3px}div.wunderbaum div.wb-row.wb-drop-target.wb-drop-before .wb-node .wb-icon::after{content:url(../docs/assets/drop_marker_insert_16x64.png);left:0;top:-8px}div.wunderbaum div.wb-row.wb-drop-target.wb-drop-after .wb-node .wb-icon::after{content:url(../docs/assets/drop_marker_insert_16x64.png);left:0;top:14px}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+1),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+1){background:#ffffe8}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+2),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+2){background:#f0fff0}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+3),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+3){background:#fff0ff}div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n+4),div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n+4){background:#eafdfd}div.wunderbaum.wb-fade-expander i.wb-expander{transition:color 1.5s;color:rgba(86,83,76,0)}div.wunderbaum.wb-fade-expander div.wb-row.wb-loading i.wb-expander,div.wunderbaum.wb-fade-expander:hover i.wb-expander,div.wunderbaum.wb-fade-expander:focus i.wb-expander,div.wunderbaum.wb-fade-expander:focus-within i.wb-expander,div.wunderbaum.wb-fade-expander [class*="wb-statusnode-"] i.wb-expander{transition:color 0.6s;color:#56534c}div.wunderbaum div.wb-row.wb-skeleton span.wb-title,div.wunderbaum div.wb-row.wb-skeleton i.wb-icon{animation:wb-skeleton-animation 1s linear infinite alternate;border-radius:0.25em;color:transparent;opacity:0.7}div.wunderbaum.wb-checkbox-auto-hide i.wb-checkbox{visibility:hidden}div.wunderbaum.wb-checkbox-auto-hide .wb-row:hover i.wb-checkbox,div.wunderbaum.wb-checkbox-auto-hide .wb-row.wb-selected i.wb-checkbox{visibility:unset}div.wunderbaum.wb-checkbox-auto-hide:focus .wb-row.wb-active i.wb-checkbox,div.wunderbaum.wb-checkbox-auto-hide:focus-within .wb-row.wb-active i.wb-checkbox{visibility:unset}.wb-helper-center{text-align:center}.wb-helper-disabled{color:#8c877c}.wb-helper-hidden{display:none}.wb-helper-invalid{color:#b5373b}.wb-helper-lazy-expander{color:#26a0da}.wb-helper-link{cursor:pointer}.wb-helper-start,.wb-helper-start>input{text-align:left}.wb-helper-end,.wb-helper-end>input{text-align:right}.wb-rtl .wb-helper-start,.wb-rtl .wb-helper-start>input{text-align:right}.wb-rtl .wb-helper-end,.wb-rtl .wb-helper-end>input{text-align:left}.wb-col input[type="checkbox"]:indeterminate{color:#8c877c;background-color:red}.wb-col input:invalid{color:#b5373b;background-color:#f5ddde}@keyframes wb-spin-animation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes wb-skeleton-animation{0%{background-color:#a3b8c2}100%{background-color:#f0f3f5}}@keyframes wb-busy-animation{0%{background-position:0 0}100%{background-position:0 22px}}
@@ -63,7 +63,7 @@ declare module "util" {
63
63
  *
64
64
  * If a `<span class="wb-col">` is passed, the first child input is used.
65
65
  * Depending on the target element type, `value` is interpreted accordingly.
66
- * For example for a checkbox, a value of true, false, or null is returned if the
66
+ * For example for a checkbox, a value of true, false, or null is returned if
67
67
  * the element is checked, unchecked, or indeterminate.
68
68
  * For datetime input control a numerical value is assumed, etc.
69
69
  *
@@ -198,7 +198,7 @@ declare module "util" {
198
198
  export function getOption(opts: any, name: string, defaultValue?: any): any;
199
199
  /** Convert an Array or space-separated string to a Set. */
200
200
  export function toSet(val: any): Set<string>;
201
- /**Return a canonical string representation for an object's type (e.g. 'array', 'number', ...) */
201
+ /** Return a canonical string representation for an object's type (e.g. 'array', 'number', ...). */
202
202
  export function type(obj: any): string;
203
203
  /**
204
204
  * Return a function that can be called instead of `callback`, but guarantees
@@ -207,12 +207,12 @@ declare module "util" {
207
207
  * previous call.
208
208
  * Example:
209
209
  * ```js
210
- * throttledFoo = util.addaptiveThrottle(foo.bind(this), {});
210
+ * throttledFoo = util.adaptiveThrottle(foo.bind(this), {});
211
211
  * throttledFoo();
212
212
  * throttledFoo();
213
213
  * ```
214
214
  */
215
- export function addaptiveThrottle(this: unknown, callback: (...args: any[]) => void, options: any): (...args: any[]) => void;
215
+ export function adaptiveThrottle(this: unknown, callback: (...args: any[]) => void, options: any): (...args: any[]) => void;
216
216
  }
217
217
  declare module "deferred" {
218
218
  /*!
@@ -433,6 +433,39 @@ declare module "wb_options" {
433
433
  checkbox?: boolean | string;
434
434
  children?: Array<WbNodeData>;
435
435
  }
436
+ export interface ColumnDefinition {
437
+ /** Column ID (pass "*" for the main tree nodes column ) */
438
+ id: string;
439
+ /** Column header (defaults to id) */
440
+ title: string;
441
+ /** Column width or weight.
442
+ * Either an absolute pixel value (e.g. `"50px"`) or a relative weight (e.g. `1`)
443
+ * that is used to calculate the width inside the remaining available space.
444
+ * Default: `"*"`, which is interpreted as `1`.
445
+ */
446
+ width?: string | number;
447
+ /** Only used for columns with a relative weight.
448
+ * Default: `4px`.
449
+ */
450
+ minWidth?: string | number;
451
+ /** Optional class names that are added to all `span.wb-col` elements of that column.*/
452
+ classes?: string;
453
+ /** Optional HTML content that is rendered into all `span.wb-col` elements of that column.*/
454
+ html: string;
455
+ }
456
+ export interface TypeDefinition {
457
+ /** En/disable checkbox for matching nodes.*/
458
+ checkbox?: boolean | BoolOptionResolver;
459
+ /** Optional class names that are added to all `div.wb-row` elements of matching nodes.*/
460
+ classes?: string;
461
+ /**Default icon for matching nodes.*/
462
+ icon?: boolean | string | BoolOptionResolver;
463
+ /**
464
+ * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
465
+ * to evaluate `node.NAME` setting and `tree.types[node.type].NAME`.
466
+ */
467
+ _any: any;
468
+ }
436
469
  /**
437
470
  * Available options for [[Wunderbaum]].
438
471
  *
@@ -489,7 +522,9 @@ declare module "wb_options" {
489
522
  *
490
523
  * Default: `{}`.
491
524
  */
492
- types?: any;
525
+ types?: {
526
+ [key: string]: TypeDefinition;
527
+ };
493
528
  /**
494
529
  * A list of maps that define column headers. If this option is set,
495
530
  * Wunderbaum becomes a treegrid control instead of a plain tree.
@@ -497,7 +532,7 @@ declare module "wb_options" {
497
532
  * response.
498
533
  * Default: `[]` meaning this is a plain tree.
499
534
  */
500
- columns?: Array<any>;
535
+ columns?: Array<ColumnDefinition>;
501
536
  /**
502
537
  * If true, add a `wb-skeleton` class to all nodes, that will result in a
503
538
  * 'glow' effect. Typically used with initial dummy nodes, while loading the
@@ -516,7 +551,7 @@ declare module "wb_options" {
516
551
  debugLevel: number;
517
552
  /**
518
553
  * Number of levels that are forced to be expanded, and have no expander icon.
519
- * Default: 0
554
+ * Default: 0
520
555
  */
521
556
  minExpandLevel?: number;
522
557
  /**
@@ -534,6 +569,11 @@ declare module "wb_options" {
534
569
  * Default: false
535
570
  */
536
571
  autoCollapse?: boolean;
572
+ /**
573
+ * HTMLElement that receives the top nodes breadcrumb.
574
+ * Default: undefined
575
+ */
576
+ attachBreadcrumb?: HTMLElement;
537
577
  /**
538
578
  * Default: NavigationModeOption.startRow
539
579
  */
@@ -554,11 +594,20 @@ declare module "wb_options" {
554
594
  * Default: 200
555
595
  */
556
596
  updateThrottleWait?: number;
597
+ /**
598
+ * Default: true
599
+ */
600
+ enabled?: boolean;
601
+ /**
602
+ * Default: false
603
+ */
604
+ fixedCol?: boolean;
557
605
  /**
558
606
  * Default: true
559
607
  */
560
608
  quicksearch?: boolean;
561
609
  dnd?: DndOptionsType;
610
+ edit: any;
562
611
  filter: any;
563
612
  grid: any;
564
613
  /**
@@ -716,8 +765,8 @@ declare module "wb_node" {
716
765
  type?: string;
717
766
  tooltip?: string;
718
767
  /** Additional classes added to `div.wb-row`.
719
- * @see {@link addClass}, {@link removeClass}, {@link toggleClass}. */
720
- extraClasses: Set<string>;
768
+ * @see {@link hasClass}, {@link setClass}. */
769
+ classes: Set<string> | null;
721
770
  /** Custom data that was passed to the constructor */
722
771
  data: any;
723
772
  statusNodeType?: string;
@@ -773,9 +822,15 @@ declare module "wb_node" {
773
822
  * @see {@link Wunderbaum.applyCommand}
774
823
  */
775
824
  applyCommand(cmd: ApplyCommandType, opts: any): any;
776
- addClass(className: string | string[] | Set<string>): void;
777
- removeClass(className: string | string[] | Set<string>): void;
778
- toggleClass(className: string | string[] | Set<string>, flag: boolean): void;
825
+ /**
826
+ * Add/remove one or more classes to `<div class='wb-row'>`.
827
+ *
828
+ * This also maintains `node.classes`, so the class will survive a re-render.
829
+ *
830
+ * @param className one or more class names. Multiple classes can be passed
831
+ * as space-separated string, array of strings, or set of strings.
832
+ */
833
+ setClass(className: string | string[] | Set<string>, flag?: boolean): void;
779
834
  /** */
780
835
  expandAll(flag?: boolean): Promise<void>;
781
836
  /**Find all nodes that match condition (excluding self).
@@ -832,6 +887,8 @@ declare module "wb_node" {
832
887
  * Return undefined if not sure, i.e. the node is lazy and not yet loaded.
833
888
  */
834
889
  hasChildren(): boolean;
890
+ /** Return true if node has className set. */
891
+ hasClass(className: string): boolean;
835
892
  /** Return true if this node is the currently active tree node. */
836
893
  isActive(): boolean;
837
894
  /** Return true if this node is a *direct* child of `other`.
@@ -1104,6 +1161,7 @@ declare module "common" {
1104
1161
  export type NodeFilterCallback = (node: WunderbaumNode) => NodeFilterResponse;
1105
1162
  export type AddNodeType = "before" | "after" | "prependChild" | "appendChild";
1106
1163
  export type DndModeType = "before" | "after" | "over";
1164
+ /** Possible values for `setModified()`. */
1107
1165
  export enum ChangeType {
1108
1166
  /** Re-render the whole viewport, headers, and all rows. */
1109
1167
  any = "any",
@@ -1120,13 +1178,14 @@ declare module "common" {
1120
1178
  /** Update the 'top' property of all rows. */
1121
1179
  vscroll = "vscroll"
1122
1180
  }
1181
+ /** Possible values for `setStatus()`. */
1123
1182
  export enum NodeStatusType {
1124
1183
  ok = "ok",
1125
1184
  loading = "loading",
1126
1185
  error = "error",
1127
1186
  noData = "noData"
1128
1187
  }
1129
- /**Define the subregion of a node, where an event occurred. */
1188
+ /** Define the subregion of a node, where an event occurred. */
1130
1189
  export enum TargetType {
1131
1190
  unknown = "",
1132
1191
  checkbox = "checkbox",
@@ -1154,27 +1213,44 @@ declare module "common" {
1154
1213
  doc: string;
1155
1214
  };
1156
1215
  export const KEY_NODATA = "__not_found__";
1216
+ /** Initial navigation mode and possible transition. */
1157
1217
  export enum NavigationModeOption {
1158
1218
  startRow = "startRow",
1159
1219
  cell = "cell",
1160
1220
  startCell = "startCell",
1161
1221
  row = "row"
1162
1222
  }
1223
+ /** Tree's current navigation mode (see `tree.setNavigationMode()`). */
1163
1224
  export enum NavigationMode {
1164
1225
  row = "row",
1165
1226
  cellNav = "cellNav",
1166
1227
  cellEdit = "cellEdit"
1167
1228
  }
1229
+ /** Define which keys are handled by embedded <input> control, and should
1230
+ * *not* be passed to tree navigation handler in cell-edit mode. */
1231
+ export const INPUT_KEYS: {
1232
+ text: string[];
1233
+ number: string[];
1234
+ checkbox: any[];
1235
+ link: any[];
1236
+ radiobutton: string[];
1237
+ "select-one": string[];
1238
+ "select-multiple": string[];
1239
+ };
1240
+ /** Key codes that trigger grid navigation, even when inside an input element. */
1241
+ export const NAVIGATE_IN_INPUT_KEYS: Set<string>;
1242
+ /** Possible values for `node.setActive()`. */
1168
1243
  export type SetActiveOptions = {
1169
1244
  /** Generate (de)activate event, even if node already has this status. */
1170
1245
  retrigger?: boolean;
1171
- /** Don not generate (de)activate event. */
1246
+ /** Do not generate (de)activate event. */
1172
1247
  noEvents?: boolean;
1173
- /** Optional original event that will be passed to the (de)activat handler. */
1248
+ /** Optional original event that will be passed to the (de)activate handler. */
1174
1249
  event?: Event;
1175
1250
  /** Call {@link setColumn}. */
1176
1251
  colIdx?: number;
1177
1252
  };
1253
+ /** Possible values for `node.setExpanded()`. */
1178
1254
  export type SetExpandedOptions = {
1179
1255
  /** Ignore {@link minExpandLevel}. @default false */
1180
1256
  force?: boolean;
@@ -1185,32 +1261,20 @@ declare module "common" {
1185
1261
  /** Scroll to bring expanded nodes into viewport. @default false */
1186
1262
  scrollIntoView?: boolean;
1187
1263
  };
1264
+ /** Possible values for `node.setSelected()`. */
1188
1265
  export type SetSelectedOptions = {
1189
1266
  /** Ignore restrictions. @default false */
1190
1267
  force?: boolean;
1191
1268
  /** Do not send events. @default false */
1192
1269
  noEvents?: boolean;
1193
1270
  };
1194
- /** Define which keys are handled by embedded <input> control, and should
1195
- * *not* be passed to tree navigation handler in cell-edit mode: */
1196
- export const INPUT_KEYS: {
1197
- text: string[];
1198
- number: string[];
1199
- checkbox: any[];
1200
- link: any[];
1201
- radiobutton: string[];
1202
- "select-one": string[];
1203
- "select-multiple": string[];
1204
- };
1205
- /** Key codes that trigger grid navigation, even when inside an input element. */
1206
- export const NAVIGATE_IN_INPUT_KEYS: Set<string>;
1207
1271
  /** Map `KeyEvent.key` to navigation action. */
1208
1272
  export const KEY_TO_ACTION_DICT: {
1209
1273
  [key: string]: string;
1210
1274
  };
1211
- /** */
1275
+ /** Return a callback that returns true if the node title contains a substring (case-insensitive). */
1212
1276
  export function makeNodeTitleMatcher(s: string): MatcherType;
1213
- /** */
1277
+ /** Return a callback that returns true if the node title starts with a string (case-insensitive). */
1214
1278
  export function makeNodeTitleStartMatcher(s: string): MatcherType;
1215
1279
  }
1216
1280
  declare module "debounce" {
@@ -1356,6 +1420,7 @@ declare module "wb_ext_filter" {
1356
1420
  lastFilterArgs: IArguments | null;
1357
1421
  constructor(tree: Wunderbaum);
1358
1422
  init(): void;
1423
+ setPluginOption(name: string, value: any): void;
1359
1424
  _applyFilterNoUpdate(filter: string | NodeFilterCallback, branchMode: boolean, _opts: any): void;
1360
1425
  _applyFilterImpl(filter: string | NodeFilterCallback, branchMode: boolean, _opts: any): number;
1361
1426
  /**
@@ -1385,6 +1450,7 @@ declare module "wb_ext_keynav" {
1385
1450
  import { WunderbaumExtension } from "wb_extension_base";
1386
1451
  export class KeynavExtension extends WunderbaumExtension {
1387
1452
  constructor(tree: Wunderbaum);
1453
+ protected _getEmbeddedInputElem(elem: any, setFocus?: boolean): HTMLInputElement | null;
1388
1454
  onKeyEvent(data: any): boolean | undefined;
1389
1455
  }
1390
1456
  }
@@ -1511,18 +1577,19 @@ declare module "wunderbaum" {
1511
1577
  /*!
1512
1578
  * wunderbaum.ts
1513
1579
  *
1514
- * A tree control.
1580
+ * A treegrid control.
1515
1581
  *
1516
1582
  * Copyright (c) 2021-2022, Martin Wendt (https://wwWendt.de).
1517
- * Released under the MIT license.
1583
+ * https://github.com/mar10/wunderbaum
1518
1584
  *
1585
+ * Released under the MIT license.
1519
1586
  * @version @VERSION
1520
1587
  * @date @DATE
1521
1588
  */
1522
1589
  import "./wunderbaum.scss";
1523
1590
  import * as util from "util";
1524
1591
  import { ExtensionsDict, WunderbaumExtension } from "wb_extension_base";
1525
- import { NavigationMode, ChangeType, FilterModeType, MatcherType, NodeStatusType, TargetType as NodeRegion, ApplyCommandType } from "common";
1592
+ import { NavigationMode, ChangeType, FilterModeType, MatcherType, NodeStatusType, TargetType as NodeRegion, ApplyCommandType, SetActiveOptions } from "common";
1526
1593
  import { WunderbaumNode } from "wb_node";
1527
1594
  import { WunderbaumOptions } from "wb_options";
1528
1595
  /**
@@ -1532,6 +1599,7 @@ declare module "wunderbaum" {
1532
1599
  */
1533
1600
  export class Wunderbaum {
1534
1601
  protected static sequence: number;
1602
+ protected enabled: boolean;
1535
1603
  /** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
1536
1604
  static version: string;
1537
1605
  /** The invisible root node, that holds all visible top level nodes. */
@@ -1543,7 +1611,7 @@ declare module "wunderbaum" {
1543
1611
  /** The `div.wb-header` element if any. */
1544
1612
  readonly headerElement: HTMLDivElement | null;
1545
1613
  /** The `div.wb-scroll-container` element that contains the `nodeListElement`. */
1546
- readonly scrollContainer: HTMLDivElement;
1614
+ readonly scrollContainerElement: HTMLDivElement;
1547
1615
  /** The `div.wb-node-list` element that contains all visible div.wb-row child elements. */
1548
1616
  readonly nodeListElement: HTMLDivElement;
1549
1617
  protected readonly _updateViewportThrottled: (...args: any) => void;
@@ -1670,7 +1738,7 @@ declare module "wunderbaum" {
1670
1738
  * Return `tree.option.NAME` (also resolving if this is a callback).
1671
1739
  *
1672
1740
  * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
1673
- * to consider `node.NAME` setting and `tree.types[node.type].NAME`.
1741
+ * to evaluate `node.NAME` setting and `tree.types[node.type].NAME`.
1674
1742
  *
1675
1743
  * @param name option name (use dot notation to access extension option, e.g.
1676
1744
  * `filter.mode`)
@@ -1688,6 +1756,8 @@ declare module "wunderbaum" {
1688
1756
  runWithoutUpdate(func: () => any, hint?: any): void;
1689
1757
  /** Recursively expand all expandable nodes (triggers lazy load id needed). */
1690
1758
  expandAll(flag?: boolean): Promise<void>;
1759
+ /** Recursively select all nodes. */
1760
+ selectAll(flag?: boolean): void;
1691
1761
  /** Return the number of nodes in the data model.*/
1692
1762
  count(visible?: boolean): number;
1693
1763
  /** @internal sanity check. */
@@ -1710,6 +1780,15 @@ declare module "wunderbaum" {
1710
1780
  *
1711
1781
  */
1712
1782
  findFirst(match: string | MatcherType): WunderbaumNode;
1783
+ /**
1784
+ * Find first node that matches condition.
1785
+ *
1786
+ * @param match title string to search for, or a
1787
+ * callback function that returns `true` if a node is matched.
1788
+ * @see {@link WunderbaumNode.findFirst}
1789
+ *
1790
+ */
1791
+ findKey(key: string): WunderbaumNode | undefined;
1713
1792
  /**
1714
1793
  * Find the next visible node that starts with `match`, starting at `startNode`
1715
1794
  * and wrap-around at the end.
@@ -1784,14 +1863,24 @@ declare module "wunderbaum" {
1784
1863
  /** Log to console if opts.debugLevel >= 2 */
1785
1864
  logWarn(...args: any[]): void;
1786
1865
  /**
1787
- * Make sure that this node is scrolled into the viewport.
1866
+ * Make sure that this node is vertically scrolled into the viewport.
1788
1867
  *
1789
- * @param {boolean | PlainObject} [effects=false] animation options.
1790
1868
  * @param {object} [options=null] {topNode: null, effects: ..., parent: ...}
1791
1869
  * this node will remain visible in
1792
1870
  * any case, even if `this` is outside the scroll pane.
1793
1871
  */
1794
1872
  scrollTo(opts: any): void;
1873
+ /**
1874
+ * Make sure that this node is horizontally scrolled into the viewport.
1875
+ *
1876
+ * Used for `fixedCol` mode.
1877
+ *
1878
+ * @param {boolean | PlainObject} [effects=false] animation options.
1879
+ * @param {object} [options=null] {topNode: null, effects: ..., parent: ...}
1880
+ * this node will remain visible in
1881
+ * any case, even if `this` is outside the scroll pane.
1882
+ */
1883
+ scrollToHorz(opts: any): void;
1795
1884
  /**
1796
1885
  * Set column #colIdx to 'active'.
1797
1886
  *
@@ -1800,15 +1889,27 @@ declare module "wunderbaum" {
1800
1889
  */
1801
1890
  setColumn(colIdx: number): void;
1802
1891
  /** Set or remove keybaord focus to the tree container. */
1892
+ setActiveNode(key: string, flag?: boolean, options?: SetActiveOptions): void;
1893
+ /** Set or remove keybaord focus to the tree container. */
1803
1894
  setFocus(flag?: boolean): void;
1804
1895
  /** Schedule an update request to reflect a tree change. */
1805
1896
  setModified(change: ChangeType, options?: any): void;
1806
1897
  /** Schedule an update request to reflect a single node modification. */
1807
1898
  setModified(change: ChangeType, node: WunderbaumNode, options?: any): void;
1899
+ /** Get the tree's navigation mode. */
1900
+ getNavigationMode(): NavigationMode;
1808
1901
  /** Set the tree's navigation mode. */
1809
1902
  setNavigationMode(mode: NavigationMode): void;
1903
+ /** Disable mouse and keyboard interaction (return prev. state). */
1904
+ setEnabled(flag?: boolean): boolean;
1905
+ /** Return false if tree is disabled. */
1906
+ isEnabled(): boolean;
1907
+ /** Return true if tree has one or more data columns in addition to the plain nodes. */
1908
+ isGrid(): boolean;
1810
1909
  /** Display tree status (ok, loading, error, noData) using styles and a dummy root node. */
1811
1910
  setStatus(status: NodeStatusType, message?: string, details?: string): WunderbaumNode | null;
1911
+ /** Add or redefine node type definitions. */
1912
+ setTypes(types: any, replace?: boolean): void;
1812
1913
  /** Update column headers and width. */
1813
1914
  updateColumns(opts?: any): void;
1814
1915
  /** Create/update header markup from `this.columns` definition.
@@ -1825,11 +1926,6 @@ declare module "wunderbaum" {
1825
1926
  * @internal
1826
1927
  */
1827
1928
  protected _updateViewport(): void;
1828
- /**
1829
- * Assert that TR order matches the natural node order
1830
- * @internal
1831
- */
1832
- protected _validateRows(): boolean;
1833
1929
  protected _updateRows(opts?: any): boolean;
1834
1930
  /**
1835
1931
  * Call callback(node) for all nodes in hierarchical order (depth-first).
@@ -1865,10 +1961,10 @@ declare module "wunderbaum" {
1865
1961
  /**
1866
1962
  * Reload the tree with a new source.
1867
1963
  *
1868
- * Previous data is cleared.
1869
- * Pass `options.columns` to define a header (may also be part of `source.columns`).
1964
+ * Previous data is cleared. Note that also column- and type defintions may
1965
+ * be passed with the `source` object.
1870
1966
  */
1871
- load(source: any, options?: any): Promise<void>;
1967
+ load(source: any): Promise<void>;
1872
1968
  /**
1873
1969
  * Disable render requests during operations that would trigger many updates.
1874
1970
  *