@eclipse-scout/core 22.0.34 → 22.0.39

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/dist/file-list CHANGED
@@ -1,5 +1,5 @@
1
- eclipse-scout-core-0c86d1e671be93def26c.min.js
2
- eclipse-scout-core-0c86d1e671be93def26c.min.js.map
1
+ eclipse-scout-core-990e036967fa14669bd8.min.js
2
+ eclipse-scout-core-990e036967fa14669bd8.min.js.map
3
3
  eclipse-scout-core-theme-dark-17a1d77d53510e113a3c.min.css
4
4
  eclipse-scout-core-theme-dark.css
5
5
  eclipse-scout-core-theme-dark.css.map
package/dist/texts.json CHANGED
@@ -6,6 +6,7 @@
6
6
  "Column": "Column",
7
7
  "ColumnSorting": "Sorting",
8
8
  "ConfirmApplyChanges": "Would you like to apply the changes?",
9
+ "DateIsNotAllowed": "Date is not allowed",
9
10
  "ErrorWhileLoadingData": "Failed to load the data.",
10
11
  "FormEmptyMandatoryFieldsMessage": "The following fields must be filled in:",
11
12
  "FormInvalidFieldsMessage": "The following fields are invalid:",
@@ -186,6 +187,7 @@
186
187
  "Column": "Colonne",
187
188
  "ColumnSorting": "Tri",
188
189
  "ConfirmApplyChanges": "Voulez-vous appliquer les modifications?",
190
+ "DateIsNotAllowed": "Date interdite",
189
191
  "ErrorWhileLoadingData": "Erreur lors du chargement des données",
190
192
  "FormEmptyMandatoryFieldsMessage": "Les champs suivants doivent être remplis:",
191
193
  "FormInvalidFieldsMessage": "Les champs suivants ont une valeur invalide:",
@@ -366,6 +368,7 @@
366
368
  "Column": "Colonna",
367
369
  "ColumnSorting": "Ordinamento",
368
370
  "ConfirmApplyChanges": "Applicare le modifiche?",
371
+ "DateIsNotAllowed": "Data non valida",
369
372
  "ErrorWhileLoadingData": "Caricamento dati fallito",
370
373
  "FormEmptyMandatoryFieldsMessage": "I seguenti campi devono essere compilati:",
371
374
  "FormInvalidFieldsMessage": "I campi seguenti hanno un valore invalido:",
@@ -546,6 +549,7 @@
546
549
  "Column": "Spalte",
547
550
  "ColumnSorting": "Sortierung",
548
551
  "ConfirmApplyChanges": "Möchten Sie die Änderungen übernehmen?",
552
+ "DateIsNotAllowed": "Unzulässiges Datum",
549
553
  "ErrorWhileLoadingData": "Fehler beim Laden der Daten",
550
554
  "FormEmptyMandatoryFieldsMessage": "Folgende Felder müssen ausgefüllt werden:",
551
555
  "FormInvalidFieldsMessage": "Folgende Felder haben einen ungültigen Wert:",
@@ -814,6 +818,7 @@
814
818
  "CloseButton": "Cerrar",
815
819
  "Column": "Columna",
816
820
  "ColumnSorting": "Clasificación",
821
+ "DateIsNotAllowed": "No se permite la fecha",
817
822
  "ErrorWhileLoadingData": "Error al cargar los datos.",
818
823
  "FormEmptyMandatoryFieldsMessage": "Se requieren los siguientes campos:",
819
824
  "FormInvalidFieldsMessage": "Los siguientes campos no son válidos:",
@@ -1005,6 +1010,7 @@
1005
1010
  "CloseButton": "閉じる",
1006
1011
  "Column": "間隙",
1007
1012
  "ColumnSorting": "並び替え",
1013
+ "DateIsNotAllowed": "日付は許可されていません",
1008
1014
  "ErrorWhileLoadingData": "データの読み込みに失敗しました。",
1009
1015
  "FormEmptyMandatoryFieldsMessage": "以下のフィールドが必要です:",
1010
1016
  "FormInvalidFieldsMessage": "以下のフィールドは無効です:",
@@ -1043,6 +1049,7 @@
1043
1049
  "CancelButton": "Annuleer",
1044
1050
  "CloseButton": "Sluit",
1045
1051
  "Column": "Kolom",
1052
+ "DateIsNotAllowed": "Datum is niet toegestaan",
1046
1053
  "ErrorWhileLoadingData": "Laden van gegevens mislukt.",
1047
1054
  "FormEmptyMandatoryFieldsMessage": "Volgende velden zijn verplicht:",
1048
1055
  "FormInvalidFieldsMessage": "Volgende velden zijn ongeldig:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-scout/core",
3
- "version": "22.0.34",
3
+ "version": "22.0.39",
4
4
  "description": "Eclipse Scout runtime",
5
5
  "author": "BSI Business Systems Integration AG",
6
6
  "homepage": "https://www.eclipse.org/scout",
@@ -26,7 +26,7 @@
26
26
  "src"
27
27
  ],
28
28
  "devDependencies": {
29
- "@eclipse-scout/cli": "22.0.34",
29
+ "@eclipse-scout/cli": "22.0.39",
30
30
  "@eclipse-scout/releng": "^22.0.0",
31
31
  "jasmine-core": "3.10.1",
32
32
  "jasmine-ajax": "4.0.0",
@@ -23,7 +23,7 @@ export default class DatePicker extends Widget {
23
23
  this.selectedDate = null;
24
24
  this.dateFormat = null;
25
25
  this.viewDate = null;
26
- this.allowedDates = null;
26
+ this.allowedDates = [];
27
27
  this.currentMonth = null;
28
28
  this.$scrollable = null;
29
29
  // Contains the months to be rendered.
@@ -342,7 +342,7 @@ export default class DatePicker extends Widget {
342
342
  let date = this.preselectedDate;
343
343
 
344
344
  if (this.selectedDate) {
345
- if (this.allowedDates) {
345
+ if (this.allowedDates.length > 0) {
346
346
  date = this._findNextAllowedDate(years, months, days);
347
347
  } else {
348
348
  date = dates.shift(this.selectedDate, years, months, days);
@@ -391,16 +391,12 @@ export default class DatePicker extends Widget {
391
391
 
392
392
  _isDateAllowed(date) {
393
393
  // when allowedDates is empty or not set, any date is allowed
394
- if (!this.allowedDates || this.allowedDates.length === 0) {
394
+ if (this.allowedDates.length === 0) {
395
395
  return true;
396
396
  }
397
397
  // when allowedDates is set, only dates contained in this array are allowed
398
- let allowedDateAsTimestamp,
399
- dateAsTimestamp = date.getTime();
400
- return this.allowedDates.some(allowedDate => {
401
- allowedDateAsTimestamp = allowedDate.getTime();
402
- return allowedDateAsTimestamp === dateAsTimestamp;
403
- });
398
+ let dateAsTimestamp = dates.trunc(date).getTime();
399
+ return this.allowedDates.some(allowedDate => allowedDate.getTime() === dateAsTimestamp);
404
400
  }
405
401
 
406
402
  _build$DateBox(viewDate) {
@@ -16,6 +16,7 @@ export default class DateField extends ValueField {
16
16
  constructor() {
17
17
  super();
18
18
 
19
+ this.allowedDates = [];
19
20
  this.popup = null;
20
21
  this.autoDate = null;
21
22
  this.dateDisplayText = null;
@@ -438,6 +439,11 @@ export default class DateField extends ValueField {
438
439
  if (!(value instanceof Date)) {
439
440
  throw this.session.text(this.invalidValueMessageKey);
440
441
  }
442
+
443
+ if (!this.isDateAllowed(value)) {
444
+ throw this.session.text('DateIsNotAllowed');
445
+ }
446
+
441
447
  if (!this.hasDate && !this.value) {
442
448
  // truncate to 01.01.1970 if no date was entered before. Otherwise preserve date part (important for toggling hasDate on the fly)
443
449
  value = dates.combineDateTime(null, value);
@@ -445,6 +451,14 @@ export default class DateField extends ValueField {
445
451
  return value;
446
452
  }
447
453
 
454
+ isDateAllowed(date) {
455
+ if (!date || this.allowedDates.length === 0 || this.embedded) { // in embedded mode, main date field must take care of validation, otherwise error status won't be shown
456
+ return true;
457
+ }
458
+ let dateAsTimestamp = dates.trunc(date).getTime();
459
+ return this.allowedDates.some(allowedDate => allowedDate.getTime() === dateAsTimestamp);
460
+ }
461
+
448
462
  _valueEquals(valueA, valueB) {
449
463
  return dates.equals(valueA, valueB);
450
464
  }
@@ -458,15 +472,19 @@ export default class DateField extends ValueField {
458
472
  this._setProperty('autoDate', autoDate);
459
473
  }
460
474
 
475
+ setAllowedDates(allowedDates) {
476
+ this.setProperty('allowedDates', allowedDates);
477
+ }
478
+
461
479
  _setAllowedDates(allowedDates) {
462
- if (Array.isArray(allowedDates)) {
463
- allowedDates = allowedDates.map(date => {
464
- return dates.ensure(date);
465
- });
466
- this._setProperty('allowedDates', allowedDates);
467
- } else {
468
- this._setProperty('allowedDates', null);
469
- }
480
+ let truncDates = [];
481
+ arrays.ensure(allowedDates).forEach(date => {
482
+ if (date) {
483
+ truncDates.push(dates.trunc(dates.ensure(date)));
484
+ }
485
+ });
486
+ truncDates = truncDates.sort(dates.compare);
487
+ this._setProperty('allowedDates', truncDates);
470
488
  }
471
489
 
472
490
  /**
@@ -8,7 +8,7 @@
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
10
10
  */
11
- import {arrays, dates, ParsingFailedStatus, ValueFieldAdapter} from '../../../index';
11
+ import {App, arrays, DateField, dates, objects, ParsingFailedStatus, ValueFieldAdapter} from '../../../index';
12
12
 
13
13
  export default class DateFieldAdapter extends ValueFieldAdapter {
14
14
 
@@ -18,13 +18,6 @@ export default class DateFieldAdapter extends ValueFieldAdapter {
18
18
 
19
19
  static PROPERTIES_ORDER = ['hasTime', 'hasDate'];
20
20
 
21
- /**
22
- * @override
23
- */
24
- _initProperties(model) {
25
- super._initProperties(model);
26
- }
27
-
28
21
  /**
29
22
  * @override
30
23
  */
@@ -64,4 +57,21 @@ export default class DateFieldAdapter extends ValueFieldAdapter {
64
57
  return Object.keys(newProperties).sort(this._createPropertySortFunc(DateFieldAdapter.PROPERTIES_ORDER));
65
58
  }
66
59
 
60
+ static isDateAllowedRemote(date) {
61
+ if (!this.modelAdapter) {
62
+ return this.isDateAllowedOrig(date);
63
+ }
64
+ // Server will take care of it
65
+ return true;
66
+ }
67
+
68
+ static modifyPrototype() {
69
+ if (!App.get().remote) {
70
+ return;
71
+ }
72
+
73
+ objects.replacePrototypeFunction(DateField, 'isDateAllowed', DateFieldAdapter.isDateAllowedRemote, true);
74
+ }
67
75
  }
76
+
77
+ App.addListener('bootstrap', DateFieldAdapter.modifyPrototype);
@@ -15,6 +15,7 @@ import {FormAdapter} from '../../index';
15
15
  * @property {object} parent
16
16
  * @property {object} owner
17
17
  * @property {object} displayParent
18
+ * @property {string} displayHint
18
19
  * @property {object} inputData
19
20
  * @property {string} jsFormObjectType
20
21
  * @property {object} jsFormModel
@@ -41,6 +42,7 @@ export default class JsFormAdapter extends FormAdapter {
41
42
  owner: model.owner,
42
43
  objectType: model.jsFormObjectType,
43
44
  displayParent: model.displayParent,
45
+ displayHint: model.displayHint,
44
46
  data: model.inputData
45
47
  };
46
48
 
@@ -120,14 +120,39 @@ export default class StaticLookupCall extends LookupCall {
120
120
  }
121
121
 
122
122
  _lookupRowsByText(text) {
123
- let datas = this.data.filter(data => {
124
- return strings.startsWith(data[1].toLowerCase(), text.toLowerCase());
125
- });
123
+ let regex = this._createSearchPattern(text);
124
+ let datas = this.data.filter(data => regex.test(data[1].toLowerCase()));
126
125
  return datas
127
126
  .map(this._dataToLookupRow, this)
128
127
  .filter(this._filterActiveLookupRow, this);
129
128
  }
130
129
 
130
+ _createSearchPattern(text) {
131
+ // Implementation copied from LocalLookupRow.java
132
+
133
+ const WILDCARD = '*';
134
+ const WILDCARD_PLACEHOLDER = '@wildcard@';
135
+
136
+ text = strings.nvl(text);
137
+ text = text.toLowerCase();
138
+ text = text.replace(new RegExp(strings.quote(WILDCARD), 'g'), WILDCARD_PLACEHOLDER);
139
+ text = strings.quote(text);
140
+
141
+ // replace repeating wildcards to prevent regex DoS
142
+ let duplicateWildcards = WILDCARD_PLACEHOLDER + WILDCARD_PLACEHOLDER;
143
+ while (strings.contains(text, duplicateWildcards)) {
144
+ text = text.replace(duplicateWildcards, WILDCARD_PLACEHOLDER);
145
+ }
146
+
147
+ if (!strings.endsWith(WILDCARD_PLACEHOLDER)) {
148
+ text += WILDCARD_PLACEHOLDER;
149
+ }
150
+
151
+ text = text.replace(new RegExp(strings.quote(WILDCARD_PLACEHOLDER), 'g'), '.*');
152
+
153
+ return new RegExp('^' + text + '$', 's'); // s = DOT_ALL
154
+ }
155
+
131
156
  _getByKey(key) {
132
157
  let deferred = $.Deferred();
133
158
  setTimeout(this._queryByKey.bind(this, deferred, key), this.delay);
@@ -51,6 +51,7 @@ export default class TileGrid extends Widget {
51
51
  this.virtual = false;
52
52
  this.virtualScrolling = null;
53
53
  this.withPlaceholders = false;
54
+ this.placeholderProducer = null;
54
55
 
55
56
  this.$filterFieldContainer = null;
56
57
  this.textFilterEnabled = false;
@@ -610,6 +611,10 @@ export default class TileGrid extends Widget {
610
611
  this.invalidateLayoutTree();
611
612
  }
612
613
 
614
+ setPlaceholderProducer(placeholderProducer) {
615
+ this.setProperty('placeholderProducer', placeholderProducer);
616
+ }
617
+
613
618
  fillUpWithPlaceholders() {
614
619
  if (!this.withPlaceholders) {
615
620
  this._deleteAllPlaceholders();
@@ -623,9 +628,7 @@ export default class TileGrid extends Widget {
623
628
  if (!this.withPlaceholders) {
624
629
  return this.tiles;
625
630
  }
626
- return this.tiles.filter(tile => {
627
- return !(tile instanceof PlaceholderTile);
628
- });
631
+ return this.tiles.filter(tile => !(tile instanceof PlaceholderTile));
629
632
  }
630
633
 
631
634
  _createPlaceholders() {
@@ -656,9 +659,17 @@ export default class TileGrid extends Widget {
656
659
  }
657
660
 
658
661
  _createPlaceholder() {
659
- return scout.create('PlaceholderTile', {
660
- parent: this
661
- });
662
+ let placeholder = (this.placeholderProducer && this.placeholderProducer()) || {};
663
+ if (placeholder instanceof PlaceholderTile) {
664
+ return placeholder;
665
+ }
666
+ if (objects.isPlainObject(placeholder)) {
667
+ return scout.create($.extend(true, {}, {
668
+ objectType: 'PlaceholderTile',
669
+ parent: this
670
+ }, placeholder));
671
+ }
672
+ throw new Error('Placeholder producer returned unexpected result.');
662
673
  }
663
674
 
664
675
  _deleteObsoletePlaceholders() {
@@ -1001,7 +1012,7 @@ export default class TileGrid extends Widget {
1001
1012
  }
1002
1013
 
1003
1014
  _applyFilters(tiles, fullReset) {
1004
- return this.filterSupport.applyFilters(tiles, fullReset);
1015
+ return this.filterSupport.applyFilters(tiles.filter(tile => !(tile instanceof PlaceholderTile)), fullReset);
1005
1016
  }
1006
1017
 
1007
1018
  /**
@@ -1011,7 +1022,7 @@ export default class TileGrid extends Widget {
1011
1022
  return new FilterSupport({
1012
1023
  widget: this,
1013
1024
  $container: () => this.$filterFieldContainer,
1014
- getElementsForFiltering: () => this.tiles,
1025
+ getElementsForFiltering: this.tilesWithoutPlaceholders.bind(this),
1015
1026
  createTextFilter: this._createTextFilter.bind(this),
1016
1027
  updateTextFilterText: this._updateTextFilterText.bind(this)
1017
1028
  });
@@ -204,39 +204,6 @@ export default class TimePicker extends Widget {
204
204
 
205
205
  }
206
206
 
207
- _findNextAllowedDate(years, months, days) {
208
- let i, date,
209
- sum = years + months + days,
210
- dir = sum > 0 ? 1 : -1,
211
- now = this.selectedDate || dates.trunc(new Date());
212
-
213
- // if we shift by year or month, shift the 'now' date and then use that date as starting point
214
- // to find the next allowed date.
215
- if (years !== 0) {
216
- now = dates.shift(now, years, 0, 0);
217
- } else if (months !== 0) {
218
- now = dates.shift(now, 0, months, 0);
219
- }
220
-
221
- if (dir === 1) { // find next allowed date, starting from currently selected date
222
- for (i = 0; i < this.allowedDates.length; i++) {
223
- date = this.allowedDates[i];
224
- if (dates.compare(now, date) < 0) {
225
- return date;
226
- }
227
- }
228
- } else if (dir === -1) { // find previous allowed date, starting from currently selected date
229
- for (i = this.allowedDates.length - 1; i >= 0; i--) {
230
- date = this.allowedDates[i];
231
- if (dates.compare(now, date) > 0) {
232
- return date;
233
- }
234
- }
235
- }
236
-
237
- return null;
238
- }
239
-
240
207
  _onNavigationMouseDown(event) {
241
208
  let $target = $(event.currentTarget);
242
209
  let diff = $target.data('shift');