@eclipse-scout/core 22.0.0-beta.1 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/eclipse-scout-core-theme-dark.css +135 -46
  2. package/dist/eclipse-scout-core-theme-dark.css.map +1 -1
  3. package/dist/eclipse-scout-core-theme.css +134 -45
  4. package/dist/eclipse-scout-core-theme.css.map +1 -1
  5. package/dist/eclipse-scout-core.js +744 -640
  6. package/dist/eclipse-scout-core.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/App.js +86 -17
  9. package/src/RemoteApp.js +1 -0
  10. package/src/desktop/Desktop.js +3 -3
  11. package/src/desktop/desktoptab/DesktopTab.less +14 -0
  12. package/src/desktop/notification/DesktopNotification.js +33 -8
  13. package/src/desktop/outline/Outline.js +2 -32
  14. package/src/desktop/outline/Outline.less +14 -6
  15. package/src/desktop/outline/OutlineViewButton.js +1 -0
  16. package/src/desktop/viewbutton/ViewButtonBox.js +2 -2
  17. package/src/filechooser/FileChooser.js +2 -1
  18. package/src/form/Form.js +11 -3
  19. package/src/form/fields/groupbox/GroupBox.less +3 -1
  20. package/src/glasspane/DeferredGlassPaneTarget.js +2 -2
  21. package/src/index.js +2 -1
  22. package/src/login/LoginBox.less +8 -1
  23. package/src/main.less +1 -1
  24. package/src/menu/ComboMenu.js +22 -17
  25. package/src/menu/ComboMenu.less +71 -26
  26. package/src/menu/ContextMenuPopup.js +3 -2
  27. package/src/menu/ContextMenuPopup.less +1 -1
  28. package/src/menu/EllipsisMenu.js +4 -0
  29. package/src/menu/Menu.js +24 -11
  30. package/src/menu/menubar/MenuBar.js +2 -19
  31. package/src/menu/menubar/MenuBarBox.js +3 -34
  32. package/src/menu/menubar/MenuBarLayout.js +6 -19
  33. package/src/menu/menubox/MenuBoxLayout.js +1 -1
  34. package/src/menu/menus.js +4 -10
  35. package/src/messagebox/MessageBox.js +3 -22
  36. package/src/modeselector/ModeSelectorLayout.js +11 -6
  37. package/src/notification/Notification.js +15 -14
  38. package/src/popup/Popup.js +3 -20
  39. package/src/session/BusyIndicator.js +2 -1
  40. package/src/session/Session.js +4 -63
  41. package/src/status/Status.js +2 -1
  42. package/src/style/colors-dark.less +3 -1
  43. package/src/style/colors.less +2 -0
  44. package/src/style/sizes.less +5 -3
  45. package/src/table/Table.js +7 -3
  46. package/src/table/Table.less +13 -3
  47. package/src/table/columns/Column.js +4 -0
  48. package/src/tile/fields/htmlfield/TileHtmlField.js +28 -0
  49. package/src/tooltip/Tooltip.less +7 -5
  50. package/src/tree/LazyNodeFilter.js +24 -15
  51. package/src/tree/Tree.js +112 -143
  52. package/src/tree/Tree.less +2 -2
  53. package/src/tree/TreeLayout.js +1 -1
  54. package/src/tree/TreeNode.js +2 -2
  55. package/src/util/Device.js +6 -2
  56. package/src/widget/FilterSupport.js +6 -4
  57. package/src/widget/FilterSupport.less +38 -9
  58. package/src/widget/LoadingSupport.js +1 -1
  59. package/src/widget/Widget.js +41 -36
  60. package/src/widget/WidgetSupport.js +1 -1
package/src/tree/Tree.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2010-2021 BSI Business Systems Integration AG.
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
3
  * All rights reserved. This program and the accompanying materials
4
4
  * are made available under the terms of the Eclipse Public License v1.0
5
5
  * which accompanies this distribution, and is available at
@@ -128,10 +128,8 @@ export default class Tree extends Widget {
128
128
  this.initialTraversing = true;
129
129
  this._setCheckable(this.checkable);
130
130
  this._ensureTreeNodes(this.nodes);
131
- this.visitNodes(this._initTreeNode.bind(this));
132
- this.visitNodes(this._updateFlatListAndSelectionPath.bind(this));
131
+ this._initNodes(this.nodes);
133
132
  this.initialTraversing = false;
134
- this.selectedNodes = this._nodesByIds(this.selectedNodes);
135
133
  this.menuBar = scout.create('MenuBar', {
136
134
  parent: this,
137
135
  position: MenuBar.Position.BOTTOM,
@@ -145,6 +143,22 @@ export default class Tree extends Widget {
145
143
  this._setMenus(this.menus);
146
144
  }
147
145
 
146
+ /**
147
+ * Initialize nodes, applies filters and updates flat list
148
+ */
149
+ _initNodes(nodes, parentNode) {
150
+ if (!nodes) {
151
+ nodes = this.nodes;
152
+ }
153
+ Tree.visitNodes(this._initTreeNode.bind(this), nodes, parentNode);
154
+ if (typeof this.selectedNodes[0] === 'string') {
155
+ this.selectedNodes = this._nodesByIds(this.selectedNodes);
156
+ }
157
+ this._updateSelectionPath();
158
+ nodes.forEach(node => this.applyFiltersForNode(node));
159
+ Tree.visitNodes((node, parentNode) => this._addToVisibleFlatList(node, false), nodes, parentNode);
160
+ }
161
+
148
162
  /**
149
163
  * Iterates through the given array and converts node-models to instances of TreeNode (or a subclass).
150
164
  * If the array element is already a TreeNode the function leaves the element untouched. This function also
@@ -226,44 +240,23 @@ export default class Tree extends Widget {
226
240
  }
227
241
 
228
242
  isSelectedNode(node) {
229
- if (this.initialTraversing) {
230
- return this.selectedNodes.indexOf(node.id) > -1;
231
- }
232
243
  return this.selectedNodes.indexOf(node) > -1;
233
244
  }
234
245
 
235
- _updateFlatListAndSelectionPath(node, parentNode) {
236
- // if this node is selected all parent nodes have to be added to selectionPath
237
- if (this.isSelectedNode(node) && (node.parentNode && !this.visibleNodesMap[node.parentNode.id] || node.level === 0)) {
238
- let p = node;
239
- while (p) {
240
- this._inSelectionPathList[p.id] = true;
241
- p.filterDirty = true;
242
-
243
- if (p !== node) {
244
- // ensure node is expanded
245
- node.expanded = true;
246
- // if parent was filtered before, try refilter after adding to selection path.
247
- if (p.level === 0) {
248
- this.applyFiltersForNode(p);
249
-
250
- // add visible nodes to visible nodes array when they are initialized
251
- this._addToVisibleFlatList(p, false);
252
-
253
- // process children
254
- this._addChildrenToFlatList(p, this.visibleNodesFlat.length - 1, false, null, true);
255
- }
256
- }
257
- p = p.parentNode;
258
- }
259
- } else if (node.parentNode && this.isSelectedNode(node.parentNode)) {
260
- this._inSelectionPathList[node.id] = true;
246
+ _updateSelectionPath() {
247
+ let selectedNode = this.selectedNodes[0];
248
+ if (!selectedNode) {
249
+ return;
261
250
  }
251
+ this._inSelectionPathList[selectedNode.id] = true;
262
252
 
263
- this.applyFiltersForNode(node);
253
+ selectedNode.childNodes.forEach(child => this._inSelectionPathList[child.id] = true);
264
254
 
265
- // add visible nodes to visible nodes array when they are initialized
266
- this._addToVisibleFlatList(node, false);
255
+ let parentNode = selectedNode.parentNode;
256
+ while (parentNode) {
257
+ this._inSelectionPathList[parentNode.id] = true;
258
+ parentNode = parentNode.parentNode;
259
+ }
267
260
  }
268
261
 
269
262
  _initTreeNode(node, parentNode) {
@@ -303,6 +296,7 @@ export default class Tree extends Widget {
303
296
  this._removeFromFlatList(node, false); // ensure node is not longer in visible nodes list.
304
297
  node.destroy();
305
298
 
299
+ // noinspection JSUnresolvedVariable
306
300
  if (this._onNodeDeleted) { // Necessary for subclasses
307
301
  this._onNodeDeleted(node);
308
302
  }
@@ -366,8 +360,8 @@ export default class Tree extends Widget {
366
360
  }
367
361
 
368
362
  _remove() {
369
- // remove listener
370
363
  this.session.desktop.off('popupOpen', this._popupOpenHandler);
364
+ this.filterSupport.remove();
371
365
 
372
366
  // stop all animations
373
367
  if (this._$animationWrapper) {
@@ -381,9 +375,8 @@ export default class Tree extends Widget {
381
375
  this.$fillBefore = null;
382
376
  this.$fillAfter = null;
383
377
  this.$data = null;
384
- // reset rendered view range because now range is rendered
378
+ // reset rendered view range because no range is rendered
385
379
  this.viewRangeRendered = new Range(0, 0);
386
- this.filterSupport.remove();
387
380
  super._remove();
388
381
  }
389
382
 
@@ -1422,8 +1415,7 @@ export default class Tree extends Widget {
1422
1415
  node.expanded = expanded;
1423
1416
  node.expandedLazy = lazy;
1424
1417
 
1425
- let filterStateChanged = this.applyFiltersForNode(node, false, renderAnimated);
1426
- if (filterStateChanged && renderExpansionOpts.expansionChanged) {
1418
+ if (renderExpansionOpts.expansionChanged) {
1427
1419
  if (node.parentNode) {
1428
1420
  // ensure node is visible under the parent node if there is a parent.
1429
1421
  this._rebuildParent(node.parentNode, opts);
@@ -1433,9 +1425,7 @@ export default class Tree extends Widget {
1433
1425
  this._removeFromFlatList(node, false);
1434
1426
  }
1435
1427
  } else if (renderExpansionOpts.expandLazyChanged) {
1436
- node.childNodes.forEach(child => {
1437
- this.applyFiltersForNode(child, false, renderAnimated);
1438
- });
1428
+ this.applyFiltersForNode(node, false, renderAnimated);
1439
1429
  }
1440
1430
 
1441
1431
  if (this.groupedNodes[node.id]) {
@@ -1443,8 +1433,7 @@ export default class Tree extends Widget {
1443
1433
  }
1444
1434
 
1445
1435
  if (node.expanded) {
1446
- node.ensureLoadChildren().done(
1447
- this._addChildrenToFlatList.bind(this, node, null, renderAnimated, null, true));
1436
+ node.ensureLoadChildren().done(this._addChildrenToFlatList.bind(this, node, null, renderAnimated, null, true /* required that ctrl+shift+add expands all rows of a table-page */));
1448
1437
  } else {
1449
1438
  this._removeChildrenFromFlatList(node, renderAnimated);
1450
1439
  }
@@ -1477,7 +1466,7 @@ export default class Tree extends Widget {
1477
1466
  return;
1478
1467
  }
1479
1468
  if (node.expanded || node.expandedLazy) {
1480
- this._addChildrenToFlatList(node, null, false, null, true);
1469
+ this._addChildrenToFlatList(node, null, true, null, true /* required so that double clicking a table-page-row expands the clicked child row */);
1481
1470
  } else {
1482
1471
  this._removeChildrenFromFlatList(node, false);
1483
1472
  }
@@ -1580,7 +1569,6 @@ export default class Tree extends Widget {
1580
1569
  }
1581
1570
 
1582
1571
  _removeFromFlatList(node, animatedRemove) {
1583
- let removedNodes = [];
1584
1572
  if (this.visibleNodesMap[node.id]) {
1585
1573
  let index = this.visibleNodesFlat.indexOf(node);
1586
1574
  this._removeChildrenFromFlatList(node, false);
@@ -1591,12 +1579,10 @@ export default class Tree extends Widget {
1591
1579
  this.nodeWidthDirty = true;
1592
1580
  }
1593
1581
  }
1594
- removedNodes = arrays.ensure(this.visibleNodesFlat.splice(index, 1));
1582
+ this.visibleNodesFlat.splice(index, 1);
1595
1583
  delete this.visibleNodesMap[node.id];
1596
1584
  this.hideNode(node, animatedRemove);
1597
1585
  }
1598
- removedNodes.push(node);
1599
- return removedNodes;
1600
1586
  }
1601
1587
 
1602
1588
  /**
@@ -1605,8 +1591,8 @@ export default class Tree extends Widget {
1605
1591
  _addToVisibleFlatList(node, renderingAnimated) {
1606
1592
  // if node already is in visible list don't do anything. If no parentNode is available this node is on toplevel, if a parent is available
1607
1593
  // it has to be in visible list and also be expanded
1608
- if (!this.visibleNodesMap[node.id] && node.isFilterAccepted() && (!node.parentNode ||
1609
- node.parentNode.expanded && this.visibleNodesMap[node.parentNode.id])) {
1594
+ if (!this.visibleNodesMap[node.id] && node.filterAccepted
1595
+ && (!node.parentNode || node.parentNode.expanded && this.visibleNodesMap[node.parentNode.id])) {
1610
1596
  if (this.initialTraversing) {
1611
1597
  // for faster index calculation
1612
1598
  this._addToVisibleFlatListNoCheck(node, this.visibleNodesFlat.length, renderingAnimated);
@@ -1653,11 +1639,10 @@ export default class Tree extends Widget {
1653
1639
  let insertIndex, isAlreadyAdded = this.visibleNodesMap[node.id];
1654
1640
  if (isAlreadyAdded) {
1655
1641
  this.insertBatchInVisibleNodes(insertBatch, this._showNodes(insertBatch), animatedRendering);
1656
- this.checkAndHandleBatchAnimationWrapper(parentNode, animatedRendering, insertBatch);
1642
+ // Animate rendering is always false because it would generate a bunch of animation wrappers which stay forever without really starting an animation...
1643
+ this.checkAndHandleBatchAnimationWrapper(parentNode, false, insertBatch);
1657
1644
  insertBatch = this.newInsertBatch(insertBatch.nextBatchInsertIndex());
1658
1645
  insertBatch = this._addChildrenToFlatListIfExpanded(1, node, insertIndex, animatedRendering, insertBatch, forceFilter);
1659
- // do not animate following
1660
- animatedRendering = false;
1661
1646
  } else {
1662
1647
  insertBatch.insertNodes.push(node);
1663
1648
  this.visibleNodesMap[node.id] = true;
@@ -2201,9 +2186,7 @@ export default class Tree extends Widget {
2201
2186
  parentNode.childNodes.push(entry);
2202
2187
  });
2203
2188
  }
2204
- // initialize node and add to visible list if node is visible
2205
- Tree.visitNodes(this._initTreeNode.bind(this), nodes, parentNode);
2206
- Tree.visitNodes(this._updateFlatListAndSelectionPath.bind(this), nodes, parentNode);
2189
+ this._initNodes(nodes, parentNode);
2207
2190
  if (this.groupedNodes[parentNode.id]) {
2208
2191
  this._updateItemPath(false, parentNode);
2209
2192
  }
@@ -2226,9 +2209,7 @@ export default class Tree extends Widget {
2226
2209
  } else {
2227
2210
  arrays.pushAll(this.nodes, nodes);
2228
2211
  }
2229
- // initialize node and add to visible list if node is visible
2230
- Tree.visitNodes(this._initTreeNode.bind(this), nodes, parentNode);
2231
- Tree.visitNodes(this._updateFlatListAndSelectionPath.bind(this), nodes, parentNode);
2212
+ this._initNodes(nodes, parentNode);
2232
2213
  }
2233
2214
  if (this.rendered) {
2234
2215
  this.viewRangeDirty = true;
@@ -2352,9 +2333,7 @@ export default class Tree extends Widget {
2352
2333
  }, this);
2353
2334
 
2354
2335
  // update child node indices
2355
- parentNodesToReindex.forEach(function(p) {
2356
- this._updateChildNodeIndex(p.childNodes);
2357
- }, this);
2336
+ parentNodesToReindex.forEach(p => this._updateChildNodeIndex(p.childNodes));
2358
2337
  this._updateChildNodeIndex(topLevelNodesToReindex);
2359
2338
 
2360
2339
  this.deselectNodes(deletedNodes, {collectChildren: true});
@@ -2748,10 +2727,8 @@ export default class Tree extends Widget {
2748
2727
  // Filter nodes
2749
2728
  this.nodes.forEach(node => {
2750
2729
  let result = this.applyFiltersForNode(node, false, this.filterAnimated);
2751
- arrays.removeAll(newlyHidden, result.newlyShown);
2752
- arrays.removeAll(newlyShown, result.newlyHidden);
2753
- result.newlyHidden.forEach(hidden => arrays.pushSet(newlyHidden, hidden));
2754
- result.newlyShown.forEach(shown => arrays.pushSet(newlyShown, shown));
2730
+ newlyHidden.push(...result.newlyHidden);
2731
+ newlyShown.push(...result.newlyShown);
2755
2732
  });
2756
2733
  return {
2757
2734
  newlyHidden: newlyHidden,
@@ -2764,28 +2741,30 @@ export default class Tree extends Widget {
2764
2741
  return;
2765
2742
  }
2766
2743
  if (opts.textFilterText) {
2767
- result.newlyShown.forEach(node => this._expandAllParentNodes(node));
2744
+ this._nodesByIds(Object.keys(this.nodesMap))
2745
+ .filter(it => it.filterAccepted)
2746
+ .forEach(node => this._expandAllParentNodes(node));
2768
2747
  }
2769
2748
  result.newlyShown.forEach(node => this._addToVisibleFlatList(node, this.filterAnimated));
2770
- this._nodesFiltered(result.newlyHidden.flatMap(node => this._removeFromFlatList(node, this.filterAnimated)));
2749
+ result.newlyHidden.forEach(node => this._removeFromFlatList(node, this.filterAnimated));
2771
2750
  this.filteredElementsDirty = false;
2772
2751
  }
2773
2752
 
2774
2753
  filterVisibleNodes(animated) {
2775
2754
  // Filter nodes
2776
2755
  let newlyHidden = [];
2777
- for (let i = 0; i < this.visibleNodesFlat.length; i++) {
2756
+ // iterate from end to beginning (child nodes first) so that the state of the children has already been updated
2757
+ for (let i = this.visibleNodesFlat.length - 1; i >= 0; i--) {
2778
2758
  let node = this.visibleNodesFlat[i];
2779
- let result = this.applyFiltersForNode(node, false, animated);
2759
+ let result = this._applyFiltersForNodeRec(node, true, animated);
2780
2760
  if (result.newlyHidden.length) {
2781
2761
  if (!node.isFilterAccepted()) {
2782
- i--;
2783
- arrays.pushAll(newlyHidden, this._removeFromFlatList(node, animated));
2762
+ newlyHidden.push(...result.newlyHidden);
2784
2763
  }
2785
2764
  this.viewRangeDirty = true;
2786
2765
  }
2787
2766
  }
2788
-
2767
+ newlyHidden.forEach(h => this._removeFromFlatList(h, animated));
2789
2768
  this._nodesFiltered(newlyHidden);
2790
2769
  }
2791
2770
 
@@ -2795,88 +2774,78 @@ export default class Tree extends Widget {
2795
2774
  }
2796
2775
 
2797
2776
  applyFiltersForNode(node, applyNewHiddenShownNodes = true, animated = false) {
2798
- let newlyHidden = [],
2799
- newlyShown = [];
2800
- animated = animated && this.filterAnimated;
2801
- node.filterDirty = true;
2802
- let changed = this._applyFiltersForNode(node);
2803
- if (changed) {
2804
- let parents = [];
2805
- let parent = node.parentNode;
2777
+ let result = this._applyFiltersForNodeRec(node, true, animated);
2806
2778
 
2807
- // collect all parents that need to be updated
2808
- // show: if node.filterAccepted === true, all parents with parent.filterAccepted === false need to be updated
2809
- // hide: if node.filterAccepted === false, all parents with parent.filterAccepted === true need to be updated...
2810
- // ...EXCEPT there are other childNodes of parent with childNode.filterAccepted === true OR the parent is directly accepted by all filters
2811
- while (parent && parent.filterAccepted !== node.filterAccepted && (node.filterAccepted || (parent.childNodes.filter(child => parents.indexOf(child) === -1).every(child => !child.filterAccepted) && !this.filterSupport.elementAcceptedByFilters(parent)))) {
2812
- arrays.insert(parents, parent, 0);
2813
- parent = parent.parentNode;
2814
- }
2779
+ // the result so far only includes the node and all its children.
2780
+ // always include the parent nodes as well so that the filter has an effect
2781
+ let parent = node.parentNode;
2782
+ while (parent) {
2783
+ let parentResult = this._applyFiltersForNodeRec(parent, false, animated);
2784
+ result.newlyHidden.unshift(...parentResult.newlyHidden);
2785
+ result.newlyShown.unshift(...parentResult.newlyShown);
2786
+ parent = parent.parentNode;
2787
+ }
2788
+ this._nodesFiltered(result.newlyHidden);
2815
2789
 
2816
- let removeFrom = node.filterAccepted ? newlyHidden : newlyShown,
2817
- pushTo = node.filterAccepted ? newlyShown : newlyHidden;
2790
+ if (applyNewHiddenShownNodes) {
2791
+ result.newlyShown.forEach(node => this._addToVisibleFlatList(node, animated));
2792
+ result.newlyHidden.forEach(node => this._removeFromFlatList(node, animated));
2793
+ }
2794
+ return result;
2795
+ }
2818
2796
 
2819
- parents.forEach(p => {
2820
- p.setFilterAccepted(node.filterAccepted);
2821
- arrays.remove(removeFrom, p);
2822
- arrays.pushSet(pushTo, p);
2823
- });
2824
- arrays.pushSet(pushTo, node);
2797
+ _applyFiltersForNodeRec(node, recursive, animated = false) {
2798
+ let newlyHidden = [], newlyShown = [];
2799
+ animated = animated && this.filterAnimated;
2825
2800
 
2826
- if (this.rendered) {
2827
- this.viewRangeDirty = true;
2828
- }
2829
- } else {
2830
- // this else branch is required when the filter-state of a node has not changed
2831
- // for instance Node "Telefon mit Sabrina" is visible for filter "tel" and also
2832
- // for filter "abr". However, it is possible that the node is _not_ attached, when
2833
- // we switch from one filter to another, because the node was not in the view-range
2834
- // with the previous filter. That's why we must make sure, the node is attached to
2835
- // the DOM, even though the filter state hasn't changed. Otherwise we'd have a
2836
- // problem when we insert nodes in this._insertNodeInDOMAtPlace.
2837
- if (!node.attached) {
2838
- this.showNode(node, animated);
2839
- if (node.attached) {
2840
- // If sibling nodes are hiding at the same time, the nodes to be shown should be added after these nodes to make the animation look correctly -> move them
2841
- node.$node.insertAfter(node.$node.nextAll('.hiding:last'));
2842
- }
2801
+ let changed = this._applyFiltersForNode(node);
2802
+ let hasChildrenWithFilterAccepted = false;
2803
+ if (node.level < 32 /* see org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree.expandAllRec */) {
2804
+ if (recursive) {
2805
+ node.childNodes.forEach(childNode => {
2806
+ let result = this._applyFiltersForNodeRec(childNode, true, animated);
2807
+ newlyHidden.push(...result.newlyHidden);
2808
+ newlyShown.push(...result.newlyShown);
2809
+ hasChildrenWithFilterAccepted = hasChildrenWithFilterAccepted || childNode.filterAccepted;
2810
+ });
2811
+ } else if (!node.filterAccepted) {
2812
+ // Check children only if filterAccepted is false because only then hasChildrenWithFilterAccepted is used (see below).
2813
+ // This has great impact on performance when there are many nodes
2814
+ hasChildrenWithFilterAccepted = node.childNodes.some(childNode => childNode.filterAccepted);
2843
2815
  }
2844
2816
  }
2845
2817
 
2846
- if (node.level < 32) {
2847
- node.childNodes.forEach(childNode => {
2848
- let result = this.applyFiltersForNode(childNode, false, animated);
2849
- arrays.removeAll(newlyHidden, result.newlyShown);
2850
- arrays.removeAll(newlyShown, result.newlyHidden);
2851
- result.newlyHidden.forEach(hidden => arrays.pushSet(newlyHidden, hidden));
2852
- result.newlyShown.forEach(shown => arrays.pushSet(newlyShown, shown));
2853
- });
2818
+ // set filter accepted on this node if it has children with filter accepted (so that the children are visible)
2819
+ if (!node.filterAccepted && hasChildrenWithFilterAccepted) {
2820
+ node.setFilterAccepted(true);
2821
+ changed = !changed;
2854
2822
  }
2855
2823
 
2856
- if (applyNewHiddenShownNodes) {
2857
- newlyShown.forEach(node => this._addToVisibleFlatList(node, animated));
2858
- this._nodesFiltered(newlyHidden.flatMap(node => this._removeFromFlatList(node, animated)));
2824
+ // remember changed node
2825
+ if (changed) {
2826
+ let pushTo = node.filterAccepted ? newlyShown : newlyHidden;
2827
+ pushTo.unshift(node);
2828
+
2829
+ if (this.rendered) {
2830
+ this.viewRangeDirty = true;
2831
+ }
2859
2832
  }
2860
2833
 
2861
- return {
2862
- newlyHidden: newlyHidden,
2863
- newlyShown: newlyShown
2864
- };
2834
+ return {newlyHidden: newlyHidden, newlyShown: newlyShown};
2865
2835
  }
2866
2836
 
2867
2837
  /**
2868
2838
  * @returns {Boolean} true if node state has changed, false if not
2869
2839
  */
2870
2840
  _applyFiltersForNode(node) {
2871
- let changed = this.filterSupport.applyFiltersForElement(node) || node.filterDirty;
2872
- if (changed) {
2841
+ let changed = this.filterSupport.applyFiltersForElement(node);
2842
+ if (changed || node.filterDirty) {
2873
2843
  node.filterDirty = false;
2874
2844
  node.childNodes.forEach(childNode => {
2875
2845
  childNode.filterDirty = true;
2876
2846
  });
2877
- return true;
2878
2847
  }
2879
- return false;
2848
+ return changed;
2880
2849
  }
2881
2850
 
2882
2851
  /**
@@ -2912,7 +2881,7 @@ export default class Tree extends Widget {
2912
2881
  }
2913
2882
  nodes = nodes.filter(function(node) {
2914
2883
  let index = indexHint === undefined ? this.visibleNodesFlat.indexOf(node) : indexHint;
2915
- if (index === -1 || !(this.viewRangeRendered.from + this.viewRangeSize >= index && this.viewRangeRendered.from <= index && this.viewRangeRendered.size() > 0) || node.attached) {
2884
+ if (index === -1 || !(this.viewRangeRendered.from + this.viewRangeSize >= index && this.viewRangeRendered.from <= index && this.viewRangeSize > 0) || node.attached) {
2916
2885
  // node is not visible
2917
2886
  return false;
2918
2887
  }
@@ -3073,6 +3042,10 @@ export default class Tree extends Widget {
3073
3042
  that.runningAnimationsFinishFunc();
3074
3043
  $node.removeClass('hiding');
3075
3044
  if (!$node.hasClass('showing')) {
3045
+ // JQuery sets display to none which we don't need because node will be detached.
3046
+ // If node is added using another method than slideDown (used by show node), it would be invisible.
3047
+ // Example: parent is collapsed while nodes are hiding -> remove filter, expand parent -> invisible nodes
3048
+ $node.css('display', '');
3076
3049
  $node.detach();
3077
3050
  node.attached = false;
3078
3051
  }
@@ -3086,15 +3059,11 @@ export default class Tree extends Widget {
3086
3059
  }
3087
3060
 
3088
3061
  _nodesToIds(nodes) {
3089
- return nodes.map(node => {
3090
- return node.id;
3091
- });
3062
+ return nodes.map(node => node.id);
3092
3063
  }
3093
3064
 
3094
3065
  _nodesByIds(ids) {
3095
- return ids.map(id => {
3096
- return this.nodesMap[id];
3097
- });
3066
+ return ids.map(id => this.nodesMap[id]);
3098
3067
  }
3099
3068
 
3100
3069
  _nodeById(id) {
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2010-2021 BSI Business Systems Integration AG.
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
3
  * All rights reserved. This program and the accompanying materials
4
4
  * are made available under the terms of the Eclipse Public License v1.0
5
5
  * which accompanies this distribution, and is available at
@@ -28,7 +28,7 @@
28
28
  }
29
29
 
30
30
  & > .filter-field {
31
- --filter-field-max-bottom: calc(~'50% - ' (@filter-field-height + var(--menubar-height)) / 2);
31
+ --filter-field-max-bottom: calc(~'50% - ' (var(--filter-field-height) + var(--menubar-height)) / 2);
32
32
  bottom: calc(min(var(--filter-field-bottom), var(--filter-field-max-bottom)) + var(--menubar-height));
33
33
 
34
34
  &:not(.focused).empty {
@@ -34,7 +34,7 @@ export default class TreeLayout extends AbstractLayout {
34
34
  })
35
35
  .subtract(htmlContainer.insets());
36
36
 
37
- if (this.tree.toggleBreadcrumbStyleEnabled) {
37
+ if (this.tree.toggleBreadcrumbStyleEnabled && this._sizeChanged(htmlContainer)) {
38
38
  this.tree.setBreadcrumbStyleActive(Math.floor(containerSize.width) <= this.tree.breadcrumbTogglingThreshold);
39
39
  }
40
40
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2010-2021 BSI Business Systems Integration AG.
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
3
  * All rights reserved. This program and the accompanying materials
4
4
  * are made available under the terms of the Eclipse Public License v1.0
5
5
  * which accompanies this distribution, and is available at
@@ -147,7 +147,7 @@ export default class TreeNode {
147
147
 
148
148
  isFilterAccepted(forceFilter) {
149
149
  if (this.filterDirty || forceFilter) {
150
- this.getTree().applyFiltersForNode(this, false);
150
+ this.getTree().applyFiltersForNode(this);
151
151
  }
152
152
  return this.filterAccepted;
153
153
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2010-2021 BSI Business Systems Integration AG.
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
3
  * All rights reserved. This program and the accompanying materials
4
4
  * are made available under the terms of the Eclipse Public License v1.0
5
5
  * which accompanies this distribution, and is available at
@@ -267,7 +267,7 @@ export default class Device {
267
267
  let browsers = Device.Browser;
268
268
  return (browser === browsers.CHROME && version >= 69)
269
269
  || (browser === browsers.FIREFOX && version >= 62)
270
- || (browser === browsers.SAFARI && version >= 12.1);
270
+ || (browser === browsers.SAFARI && version >= 12);
271
271
  }
272
272
 
273
273
  /**
@@ -364,6 +364,10 @@ export default class Device {
364
364
  } else if (this.browser === browsers.EDGE) {
365
365
  versionRegex = /Edge\/([0-9]+\.?[0-9]*)/;
366
366
  } else if (this.browser === browsers.SAFARI) {
367
+ if (this.isIos() && userAgent.indexOf('Version/') < 0) {
368
+ this.browserVersion = this.systemVersion;
369
+ return;
370
+ }
367
371
  versionRegex = /Version\/([0-9]+\.?[0-9]*)/;
368
372
  } else if (this.browser === browsers.FIREFOX) {
369
373
  versionRegex = /Firefox\/([0-9]+\.?[0-9]*)/;
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2010-2021 BSI Business Systems Integration AG.
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
3
  * All rights reserved. This program and the accompanying materials
4
4
  * are made available under the terms of the Eclipse Public License v1.0
5
5
  * which accompanies this distribution, and is available at
@@ -126,10 +126,12 @@ export default class FilterSupport extends WidgetSupport {
126
126
  this._filterField.$field.attr('tabIndex', -1);
127
127
 
128
128
  let color = styles.getFirstOpaqueBackgroundColor(this._filterField.$container),
129
- transparentColorRgba = $.extend(true, {}, styles.rgb(color), {alpha: 0.5}),
130
- transparentColor = 'rgba(' + transparentColorRgba.red + ', ' + transparentColorRgba.green + ', ' + transparentColorRgba.blue + ', ' + transparentColorRgba.alpha + ')';
129
+ colorRgba = $.extend(true, {red: 0, green: 0, blue: 0, alpha: 1}, styles.rgb(color)),
130
+ transparent50Color = 'rgba(' + colorRgba.red + ', ' + colorRgba.green + ', ' + colorRgba.blue + ', ' + 0.5 + ')',
131
+ transparent80Color = 'rgba(' + colorRgba.red + ', ' + colorRgba.green + ', ' + colorRgba.blue + ', ' + 0.8 + ')';
131
132
  this._filterField.$container.css('--filter-field-background-color', color);
132
- this._filterField.$container.css('--filter-field-transparent-background-color', transparentColor);
133
+ this._filterField.$container.css('--filter-field-transparent-50-background-color', transparent50Color);
134
+ this._filterField.$container.css('--filter-field-transparent-80-background-color', transparent80Color);
133
135
 
134
136
  this._textFilter = this._createTextFilter();
135
137
  this._textFilter.synthetic = true;