@eclipse-scout/core 22.0.12 → 22.0.22

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 (40) hide show
  1. package/dist/eclipse-scout-core-c4cad26b336b02535421.min.js +2 -0
  2. package/dist/eclipse-scout-core-c4cad26b336b02535421.min.js.map +1 -0
  3. package/dist/eclipse-scout-core-theme-dark-fd0e080c10f65e67b68b.min.css +1 -0
  4. package/dist/eclipse-scout-core-theme-dark.css +20 -5
  5. package/dist/eclipse-scout-core-theme-dark.css.map +1 -1
  6. package/dist/eclipse-scout-core-theme-f3a61fbc12acf8e27fcc.min.css +1 -0
  7. package/dist/eclipse-scout-core-theme.css +20 -5
  8. package/dist/eclipse-scout-core-theme.css.map +1 -1
  9. package/dist/eclipse-scout-core.js +1120 -914
  10. package/dist/eclipse-scout-core.js.map +1 -1
  11. package/dist/file-list +4 -4
  12. package/dist/texts.json +8 -8
  13. package/package.json +2 -2
  14. package/src/App.js +1 -0
  15. package/src/desktop/DesktopDense.less +24 -6
  16. package/src/desktop/OpenUriHandler.js +5 -5
  17. package/src/desktop/outline/pages/Page.js +7 -2
  18. package/src/form/Form.js +15 -3
  19. package/src/form/fields/FormField.js +1 -1
  20. package/src/form/fields/datefield/DateField.js +2 -0
  21. package/src/form/fields/sequencebox/SequenceBox.js +20 -3
  22. package/src/form/fields/stringfield/StringField.js +9 -1
  23. package/src/form/js/JsFormAdapter.js +88 -0
  24. package/src/index.js +2 -1
  25. package/src/scrollbar/scrollbars.js +12 -1
  26. package/src/session/Session.js +21 -18
  27. package/src/table/Table.js +2 -3
  28. package/src/testing/JasmineScoutUtil.js +127 -0
  29. package/src/testing/index.js +7 -3
  30. package/src/tile/TileGrid.js +5 -15
  31. package/src/tile/TileGridLayout.js +21 -11
  32. package/src/tile/accordion/TileAccordion.js +4 -23
  33. package/src/tile/accordion/TileAccordionLayout.js +39 -2
  34. package/src/util/arrays.js +4 -0
  35. package/src/util/objects.js +4 -1
  36. package/src/widget/FilterSupport.js +19 -8
  37. package/dist/eclipse-scout-core-af5ff6abad5f1ff9fd18.min.js +0 -2
  38. package/dist/eclipse-scout-core-af5ff6abad5f1ff9fd18.min.js.map +0 -1
  39. package/dist/eclipse-scout-core-theme-74b63e0d57bed407a729.min.css +0 -1
  40. package/dist/eclipse-scout-core-theme-dark-b82aea152f416e38ce7f.min.css +0 -1
@@ -0,0 +1,127 @@
1
+ /*
2
+ * Copyright (c) 2010-2022 BSI Business Systems Integration AG.
3
+ * All rights reserved. This program and the accompanying materials
4
+ * are made available under the terms of the Eclipse Public License v1.0
5
+ * which accompanies this distribution, and is available at
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
+ *
8
+ * Contributors:
9
+ * BSI Business Systems Integration AG - initial API and implementation
10
+ */
11
+ import {arrays, scout, strings} from '../index';
12
+ import $ from 'jquery';
13
+
14
+ let _jsonResourceCache = {};
15
+
16
+ /**
17
+ * Utility functions for jasmine tests.
18
+ */
19
+ export const JasmineScoutUtil = {
20
+
21
+ /**
22
+ * @param {string} jsonResourceUrl
23
+ * @param {object} [options]
24
+ * @param {boolean} [options.useCache=true]
25
+ * @return {Promise<object>} - the loaded JSON data structure
26
+ */
27
+ loadJsonResource(jsonResourceUrl, options = {}) {
28
+ scout.assertParameter('jsonResourceUrl', jsonResourceUrl);
29
+
30
+ if (scout.nvl(options.useCache, true)) {
31
+ let json = _jsonResourceCache[jsonResourceUrl];
32
+ if (json) {
33
+ return $.resolvedPromise(json);
34
+ }
35
+ }
36
+
37
+ return $.ajax({
38
+ async: false,
39
+ type: 'GET',
40
+ dataType: 'json',
41
+ contentType: 'application/json; charset=UTF-8',
42
+ cache: false,
43
+ url: jsonResourceUrl
44
+ })
45
+ .done(json => {
46
+ if (scout.nvl(options.useCache, true)) {
47
+ _jsonResourceCache[jsonResourceUrl] = json;
48
+ }
49
+ return $.resolvedPromise(json);
50
+ })
51
+ .fail((jqXHR, textStatus, errorThrown) => {
52
+ throw new Error('Could not load resource from url: ' + jsonResourceUrl);
53
+ });
54
+ },
55
+
56
+ /**
57
+ * @param {string} resourceUrlToMock
58
+ * @param {string} jsonResourceUrl
59
+ * @param {object} [options]
60
+ * @param {boolean} [options.useCache=true]
61
+ * @param {*} [options.restriction]
62
+ * @param {string} [options.method]
63
+ */
64
+ loadJsonResourceAndMockRestCall(resourceUrlToMock, jsonResourceUrl, options = {}) {
65
+ scout.assertParameter('resourceUrlToMock', resourceUrlToMock);
66
+
67
+ this.loadJsonResource(jsonResourceUrl, options)
68
+ .then(json => this.mockRestCall(resourceUrlToMock, json, options));
69
+ },
70
+
71
+ /**
72
+ * @param {string} resourceUrlToMock
73
+ * @param {array} lookupRows
74
+ * @param {*} [parentRestriction]
75
+ */
76
+ mockRestLookupCall(resourceUrlToMock, lookupRows, parentRestriction) {
77
+ scout.assertParameter('resourceUrlToMock', resourceUrlToMock);
78
+
79
+ // Normalize lookup rows
80
+ lookupRows = arrays.ensure(lookupRows).map(lookupRow => $.extend({
81
+ active: true,
82
+ enabled: true,
83
+ parentId: null
84
+ }, lookupRow));
85
+
86
+ // getAll()
87
+ this.mockRestCall(resourceUrlToMock, {
88
+ rows: lookupRows
89
+ }, {
90
+ restriction: parentRestriction
91
+ });
92
+
93
+ // getKey()
94
+ lookupRows.forEach(lookupRow => {
95
+ this.mockRestCall(resourceUrlToMock, {
96
+ rows: [lookupRow]
97
+ }, {
98
+ restriction: lookupRow.id
99
+ });
100
+ });
101
+ },
102
+
103
+ /**
104
+ * @param {string} resourceUrlToMock
105
+ * @param {*} responseData
106
+ * @param {object} [options]
107
+ * @param {*} [options.restriction]
108
+ * @param {string} [options.method]
109
+ */
110
+ mockRestCall(resourceUrlToMock, responseData, options = {}) {
111
+ let url = new RegExp('.*' + strings.quote(resourceUrlToMock) + '.*');
112
+ let data = options.restriction ? new RegExp('.*' + strings.quote(options.restriction) + '.*') : undefined;
113
+ jasmine.Ajax.stubRequest(url, data, options.method).andReturn({
114
+ status: 200,
115
+ responseText: JSON.stringify(responseData)
116
+ });
117
+ },
118
+
119
+ /**
120
+ * If a ajax call is not mocked, this fallback will be triggered to show information about which url is not mocked.
121
+ */
122
+ captureNotMockedCalls() {
123
+ jasmine.Ajax.stubRequest(/.*/).andCallFunction((stub, mockAjax) => {
124
+ fail('Ajax call not mocked for url: ' + mockAjax.url + ', method: ' + mockAjax.method);
125
+ });
126
+ }
127
+ };
@@ -8,8 +8,14 @@
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
10
10
  */
11
+
12
+ // /////////////////////////////////////////////////////////////////
13
+ // TEST SUPPORT - DO NOT USE IN PRODUCTION CODE
14
+ // /////////////////////////////////////////////////////////////////
15
+
11
16
  export {default as TestingApp} from './TestingApp';
12
17
  export {default as JasmineScout} from './JasmineScout';
18
+ export {JasmineScoutUtil} from './JasmineScoutUtil';
13
19
  export {default as LocaleSpecHelper} from './text/LocaleSpecHelper';
14
20
  export {default as MenuSpecHelper} from './menu/MenuSpecHelper';
15
21
  export {default as TreeSpecHelper} from './tree/TreeSpecHelper';
@@ -31,6 +37,4 @@ export {default as GroupBoxSpecHelper} from './form/fields/groupbox/GroupBoxSpec
31
37
  import * as self from './index.js';
32
38
 
33
39
  export default self;
34
- if (window) {
35
- window.scout = Object.assign(window.scout || {}, self);
36
- }
40
+ window.scout = Object.assign(window.scout || {}, self);
@@ -1,9 +1,9 @@
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
6
- * http://www.eclipse.org/legal/epl-v10.html
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
7
  *
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
@@ -42,8 +42,6 @@ export default class TileGrid extends Widget {
42
42
  this.selectedTiles = [];
43
43
  this.selectionHandler = new TileGridSelectionHandler(this);
44
44
  this.scrollable = true;
45
- this.scrolling = false;
46
- this.scrollTopDirty = false;
47
45
  this.startupAnimationDone = false;
48
46
  this.startupAnimationEnabled = false;
49
47
  this.tiles = [];
@@ -594,18 +592,14 @@ export default class TileGrid extends Widget {
594
592
  let scrollTop = this.$container[0].scrollTop;
595
593
  let scrollLeft = this.$container[0].scrollLeft;
596
594
  if (this.scrollTop !== scrollTop && this.virtual) {
597
- this.scrolling = true;
598
- this.revalidateLayout();
599
- this.scrolling = false;
595
+ this.htmlComp.layout.updateViewPort();
600
596
  }
601
597
  this.scrollTop = scrollTop;
602
598
  this.scrollLeft = scrollLeft;
603
599
  }
604
600
 
605
601
  _onScrollParentScroll(event) {
606
- this.scrolling = true;
607
- this.revalidateLayoutTree(false);
608
- this.scrolling = false;
602
+ this.htmlComp.layout.updateViewPort();
609
603
  }
610
604
 
611
605
  setWithPlaceholders(withPlaceholders) {
@@ -961,12 +955,8 @@ export default class TileGrid extends Widget {
961
955
  this.ensureTileRendered(tile);
962
956
  // If tile was not rendered it is not yet positioned correctly -> make sure layout is valid before trying to scroll
963
957
  // Layout must not render the viewport because scroll position is not correct yet -> just make sure tiles are at the correct position
964
- this.scrolling = true;
965
- this.scrollTopDirty = true;
966
- this.validateLayoutTree();
967
- this.scrolling = false;
958
+ this.htmlComp.layout.updateViewPort(true);
968
959
  tile.reveal(options);
969
- this.scrollTopDirty = false;
970
960
  }
971
961
 
972
962
  revealSelection() {
@@ -3,7 +3,7 @@
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
6
- * http://www.eclipse.org/legal/epl-v10.html
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
7
  *
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
@@ -44,19 +44,29 @@ export default class TileGridLayout extends LogicalGridLayout {
44
44
  this.maxWidth = -1;
45
45
  }
46
46
 
47
- layout($container) {
48
- let htmlComp = this.widget.htmlComp;
49
- if (this.widget.scrolling) {
50
- // Try to layout only as much as needed while scrolling in virtual mode
51
- // Scroll top may be dirty when layout is validated before scrolling to a specific tile (see tileGrid.scrollTo)
52
- if (!this.widget.scrollTopDirty) {
53
- this.widget._renderViewPort();
54
- }
55
- this._layout($container);
56
- this.widget.trigger('layoutAnimationDone');
47
+ /**
48
+ *
49
+ * @param {boolean} [scrollTopDirty] If the scroll top position should be considered dirty while updating the view port.
50
+ * If true, the view port is not rendered, as the scroll positions are not reliable anyway. Then only the layout of the TileGrid is updated.
51
+ */
52
+ updateViewPort(scrollTopDirty) {
53
+ let tileGrid = this.widget;
54
+ if (!tileGrid.rendered) {
57
55
  return;
58
56
  }
59
57
 
58
+ // Try to layout only as much as needed while scrolling in virtual mode
59
+ // Scroll top may be dirty when layout is validated before scrolling to a specific tile (see tileGrid.scrollTo)
60
+ if (!scout.nvl(scrollTopDirty, false)) {
61
+ tileGrid._renderViewPort();
62
+ }
63
+ this._layout(tileGrid.$container);
64
+ tileGrid.trigger('layoutAnimationDone');
65
+ }
66
+
67
+ layout($container) {
68
+ let htmlComp = this.widget.htmlComp;
69
+
60
70
  // Animate only once on startup (if enabled) but animate every time on resize
61
71
  let animated = htmlComp.layouted || (this.widget.startupAnimationEnabled && !this.widget.startupAnimationDone) || this.widget.renderAnimationEnabled;
62
72
  this.tiles = this.widget.renderedTiles();
@@ -3,7 +3,7 @@
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
6
- * http://www.eclipse.org/legal/epl-v10.html
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
7
  *
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
@@ -350,24 +350,7 @@ export default class TileAccordion extends Accordion {
350
350
  }
351
351
 
352
352
  _filter() {
353
- this.groups.forEach(group => {
354
- group.body.filter();
355
-
356
- // If the layout has not been invalidated as part of the filtering above, it even though must be validated here.
357
- // This is because groups above might have fewer visible Tiles now which makes room for this group.
358
- // The revalidateLayout() with scrolling=true here ensures TileGrid._renderViewPort() is called to ensure these Tiles become visible as there is space available now.
359
- // It is executed as postValidateFunction because the groups above must have completed their layouting so that
360
- // TileGrid._renderViewPort() knows that there is more space available now.
361
- if (group.body.htmlComp && group.body.htmlComp.valid && !group.body._accordionLayoutHandler /* skip if already registered */) {
362
- group.body._accordionLayoutHandler = () => {
363
- group.body.scrolling = true;
364
- group.body.revalidateLayout();
365
- group.body.scrolling = false;
366
- group.body._accordionLayoutHandler = null;
367
- };
368
- this.session.layoutValidator.schedulePostValidateFunction(group.body._accordionLayoutHandler);
369
- }
370
- });
353
+ this.groups.forEach(group => group.body.filter());
371
354
  }
372
355
 
373
356
  /**
@@ -700,10 +683,8 @@ export default class TileAccordion extends Accordion {
700
683
  // Btw: another group may be doing it as well at the same time (e.g. because of exclusiveExpand)
701
684
  return;
702
685
  }
703
- if (group.body.virtual) {
704
- group.body.scrolling = true;
705
- group.body.revalidateLayout();
706
- group.body.scrolling = false;
686
+ if (group.body.virtual && group.body.htmlComp) {
687
+ group.body.htmlComp.layout.updateViewPort();
707
688
  }
708
689
  });
709
690
  }
@@ -1,9 +1,9 @@
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
6
- * http://www.eclipse.org/legal/epl-v10.html
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
7
  *
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
@@ -19,8 +19,45 @@ export default class TileAccordionLayout extends AccordionLayout {
19
19
  }
20
20
 
21
21
  layout($container) {
22
+ let previousGroupHeights = this.tileAccordion.groups
23
+ .map(group => group.body)
24
+ .map(tileGrid => this._getTileGridHeight(tileGrid));
25
+
22
26
  super.layout($container);
23
27
  this._updateFilterFieldMaxWidth($container);
28
+
29
+ this.tileAccordion.groups
30
+ .map(group => group.body)
31
+ .forEach((tileGrid, index) => this._updateTileGridViewPort(tileGrid, previousGroupHeights[index]));
32
+ }
33
+
34
+ _updateTileGridViewPort(tileGrid, previousHeight) {
35
+ if (!tileGrid.rendered || !tileGrid.htmlComp || previousHeight <= 0) {
36
+ return;
37
+ }
38
+
39
+ let newHeight = this._getTileGridHeight(tileGrid);
40
+ if (previousHeight === newHeight && tileGrid.virtual) {
41
+ // The viewPort of the virtual tileGrid has not been updated as no layout update was done for the grid because its height is unchanged.
42
+ // But as there might be more space available in the accordion now (its height might have changed), enforce a viewPort update to ensure all necessary tiles are rendered.
43
+ tileGrid.setViewRangeSize(tileGrid.calculateViewRangeSize(), false);
44
+ tileGrid.htmlComp.layout.updateViewPort();
45
+ }
46
+ }
47
+
48
+ _getTileGridHeight(tileGrid) {
49
+ if (!tileGrid) {
50
+ return 0;
51
+ }
52
+ let htmlComp = tileGrid.htmlComp;
53
+ if (!htmlComp) {
54
+ return 0;
55
+ }
56
+ let size = tileGrid.htmlComp.sizeCached;
57
+ if (!size) {
58
+ return 0;
59
+ }
60
+ return size.height;
24
61
  }
25
62
 
26
63
  _updateFilterFieldMaxWidth($container) {
@@ -12,6 +12,10 @@ import {objects, strings} from '../index';
12
12
 
13
13
  /**
14
14
  * Ensures the given parameter is an array
15
+ *
16
+ * @template T
17
+ * @param {T[]|T|null} array
18
+ * @return T[]
15
19
  */
16
20
  export function ensure(array) {
17
21
  if (array === undefined || array === null) {
@@ -127,6 +127,9 @@ export function someProperties(obj, properties) {
127
127
  });
128
128
  }
129
129
 
130
+ /**
131
+ * @return {*}
132
+ */
130
133
  export function valueCopy(obj) {
131
134
  // Nothing to be done for immutable things
132
135
  if (obj === undefined || obj === null || typeof obj !== 'object') {
@@ -220,7 +223,7 @@ export function findChildObjectByKey(parentObj, property, propertyValue) {
220
223
  * @return Object Returns the selected object.
221
224
  * @throws Throws an error, if the provided parameters are malformed, or a property could not be found/a id property filter does not find any elements.
222
225
  */
223
- function getByPath(object, path) {
226
+ export function getByPath(object, path) {
224
227
  scout.assertParameter('object', object, Object);
225
228
  scout.assertParameter('path', path);
226
229
 
@@ -3,7 +3,7 @@
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
6
- * http://www.eclipse.org/legal/epl-v10.html
6
+ * https://www.eclipse.org/legal/epl-v10.html
7
7
  *
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
@@ -125,13 +125,11 @@ export default class FilterSupport extends WidgetSupport {
125
125
 
126
126
  this._filterField.$field.attr('tabIndex', -1);
127
127
 
128
- let color = styles.getFirstOpaqueBackgroundColor(this._filterField.$container),
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 + ')';
132
- this._filterField.$container.css('--filter-field-background-color', color);
133
- this._filterField.$container.css('--filter-field-transparent-50-background-color', transparent50Color);
134
- this._filterField.$container.css('--filter-field-transparent-80-background-color', transparent80Color);
128
+ if (!this.widget.rendered) {
129
+ this.widget.session.layoutValidator.schedulePostValidateFunction(this._updateFilterFieldBackgroundColor.bind(this));
130
+ } else {
131
+ this._updateFilterFieldBackgroundColor();
132
+ }
135
133
 
136
134
  this._textFilter = this._createTextFilter();
137
135
  this._textFilter.synthetic = true;
@@ -164,6 +162,19 @@ export default class FilterSupport extends WidgetSupport {
164
162
  this._filterField.keyStrokeContext.registerKeyStroke(this._exitFilterFieldKeyStroke);
165
163
  }
166
164
 
165
+ _updateFilterFieldBackgroundColor() {
166
+ if (!this._filterField || !this._filterField.rendered) {
167
+ return;
168
+ }
169
+ let color = styles.getFirstOpaqueBackgroundColor(this._filterField.$container),
170
+ colorRgba = $.extend(true, {red: 0, green: 0, blue: 0, alpha: 1}, styles.rgb(color)),
171
+ transparent50Color = 'rgba(' + colorRgba.red + ', ' + colorRgba.green + ', ' + colorRgba.blue + ', ' + 0.5 + ')',
172
+ transparent80Color = 'rgba(' + colorRgba.red + ', ' + colorRgba.green + ', ' + colorRgba.blue + ', ' + 0.8 + ')';
173
+ this._filterField.$container.css('--filter-field-background-color', color);
174
+ this._filterField.$container.css('--filter-field-transparent-50-background-color', transparent50Color);
175
+ this._filterField.$container.css('--filter-field-transparent-80-background-color', transparent80Color);
176
+ }
177
+
167
178
  _onFilterFieldDisplayTextChanged(event) {
168
179
  if (this._filterField && this._filterField.rendered) {
169
180
  this._filterField.$container.toggleClass('empty', !event.newValue);