@eclipse-scout/core 22.0.33 → 22.0.37

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 (41) hide show
  1. package/dist/eclipse-scout-core-990e036967fa14669bd8.min.js +2 -0
  2. package/dist/eclipse-scout-core-990e036967fa14669bd8.min.js.map +1 -0
  3. package/dist/eclipse-scout-core-theme-dark-17a1d77d53510e113a3c.min.css +1 -0
  4. package/dist/eclipse-scout-core-theme-dark.css +28 -4
  5. package/dist/eclipse-scout-core-theme-dark.css.map +1 -1
  6. package/dist/eclipse-scout-core-theme-dfed415a6b7fb17f3f4c.min.css +1 -0
  7. package/dist/eclipse-scout-core-theme.css +28 -4
  8. package/dist/eclipse-scout-core-theme.css.map +1 -1
  9. package/dist/eclipse-scout-core.js +8311 -26955
  10. package/dist/eclipse-scout-core.js.map +1 -1
  11. package/dist/file-list +4 -4
  12. package/dist/texts.json +7 -0
  13. package/package.json +2 -2
  14. package/src/App.js +31 -23
  15. package/src/ErrorHandler.js +3 -2
  16. package/src/RemoteApp.js +6 -13
  17. package/src/datepicker/DatePicker.js +5 -9
  18. package/src/desktop/outline/Outline.js +3 -2
  19. package/src/form/fields/datefield/DateField.js +26 -8
  20. package/src/form/fields/datefield/DateFieldAdapter.js +18 -8
  21. package/src/form/js/JsFormAdapter.js +2 -0
  22. package/src/keystroke/KeyStroke.js +23 -18
  23. package/src/lookup/StaticLookupCall.js +28 -3
  24. package/src/main.less +1 -0
  25. package/src/popup/Popup.js +94 -15
  26. package/src/popup/Popup.less +6 -2
  27. package/src/session/Session.js +10 -5
  28. package/src/style/sizes.less +2 -0
  29. package/src/table/TableFooter.js +4 -4
  30. package/src/table/TableFooter.less +2 -2
  31. package/src/table/controls/TableControl.js +8 -3
  32. package/src/table/keystrokes/AbstractTableNavigationKeyStroke.js +1 -1
  33. package/src/tile/TileGrid.js +21 -9
  34. package/src/timepicker/TimePicker.js +0 -33
  35. package/src/tree/Tree.js +46 -5
  36. package/src/tree/Tree.less +3 -1
  37. package/src/tree/TreeNode.js +4 -3
  38. package/dist/eclipse-scout-core-b11dde8e4ac1367f5a06.min.js +0 -2
  39. package/dist/eclipse-scout-core-b11dde8e4ac1367f5a06.min.js.map +0 -1
  40. package/dist/eclipse-scout-core-theme-dark-0d9d468e5722f73f5075.min.css +0 -1
  41. package/dist/eclipse-scout-core-theme-db0af3fa95956b820bfc.min.css +0 -1
package/dist/file-list CHANGED
@@ -1,9 +1,9 @@
1
- eclipse-scout-core-b11dde8e4ac1367f5a06.min.js
2
- eclipse-scout-core-b11dde8e4ac1367f5a06.min.js.map
3
- eclipse-scout-core-theme-dark-0d9d468e5722f73f5075.min.css
1
+ eclipse-scout-core-990e036967fa14669bd8.min.js
2
+ eclipse-scout-core-990e036967fa14669bd8.min.js.map
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
6
- eclipse-scout-core-theme-db0af3fa95956b820bfc.min.css
6
+ eclipse-scout-core-theme-dfed415a6b7fb17f3f4c.min.css
7
7
  eclipse-scout-core-theme.css
8
8
  eclipse-scout-core-theme.css.map
9
9
  eclipse-scout-core.js
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.33",
3
+ "version": "22.0.37",
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.33",
29
+ "@eclipse-scout/cli": "22.0.37",
30
30
  "@eclipse-scout/releng": "^22.0.0",
31
31
  "jasmine-core": "3.10.1",
32
32
  "jasmine-ajax": "4.0.0",
package/src/App.js CHANGED
@@ -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
@@ -341,8 +341,9 @@ export default class App {
341
341
  // Bluebird has a polyfill -> can it be ported to jQuery?
342
342
  }
343
343
 
344
- _createErrorHandler() {
345
- return scout.create('ErrorHandler');
344
+ _createErrorHandler(opts) {
345
+ opts = $.extend({}, opts);
346
+ return scout.create('ErrorHandler', opts);
346
347
  }
347
348
 
348
349
  /**
@@ -459,16 +460,33 @@ export default class App {
459
460
  $.log.error('App initialization failed.');
460
461
  this.setLoading(false);
461
462
 
462
- return this.errorHandler.handle(error, ...args)
463
- .then(errorInfo => {
464
- let $error = $('body').appendDiv('startup-error');
465
- $error.appendDiv('startup-error-title').text('The application could not be started');
466
- if (errorInfo.message) {
467
- $error.appendDiv('startup-error-message').text(errorInfo.message);
468
- }
469
- // Reject with original rejection arguments
470
- return $.rejectedPromise(error, ...args);
471
- });
463
+ let promises = [];
464
+ if (this.sessions.length === 0) {
465
+ promises.push(this.errorHandler.handle(error, ...args)
466
+ .then(errorInfo => {
467
+ this._appendStartupError($('body'), errorInfo.message);
468
+ }));
469
+ } else {
470
+ // Session.js may already display a fatal message box
471
+ // -> don't handle the error again and display multiple error messages
472
+ this.sessions
473
+ .filter(session => !session.ready && !session.isFatalMessageShown())
474
+ .forEach(session => {
475
+ session.$entryPoint.empty();
476
+ promises.push(this._createErrorHandler({session: session}).handle(error));
477
+ });
478
+ }
479
+
480
+ // Reject with original rejection arguments
481
+ return $.promiseAll(promises).then(errorInfo => $.rejectedPromise(error, ...args));
482
+ }
483
+
484
+ _appendStartupError($parent, message) {
485
+ let $error = $parent.appendDiv('startup-error');
486
+ $error.appendDiv('startup-error-title').text('The application could not be started');
487
+ if (message) {
488
+ $error.appendDiv('startup-error-message').text(message);
489
+ }
472
490
  }
473
491
 
474
492
  /**
@@ -517,13 +535,3 @@ export default class App {
517
535
  return this.events.when(type);
518
536
  }
519
537
  }
520
- /*
521
- * Copyright (c) 2010-2019 BSI Business Systems Integration AG.
522
- * All rights reserved. This program and the accompanying materials
523
- * are made available under the terms of the Eclipse Public License v1.0
524
- * which accompanies this distribution, and is available at
525
- * http://www.eclipse.org/legal/epl-v10.html
526
- *
527
- * Contributors:
528
- * BSI Business Systems Integration AG - initial API and implementation
529
- */
@@ -19,6 +19,7 @@ export default class ErrorHandler {
19
19
  this.displayError = true;
20
20
  this.sendError = false;
21
21
  this.windowErrorHandler = this._onWindowError.bind(this);
22
+ this.session = null;
22
23
  }
23
24
 
24
25
  /**
@@ -264,8 +265,8 @@ export default class ErrorHandler {
264
265
  // Note: The error handler is installed globally and we cannot tell in which scout session the error happened.
265
266
  // We simply use the first scout session to display the message box and log the error. This is not ideal in the
266
267
  // multi-session-case (portlet), but currently there is no other way. Besides, this feature is not in use yet.
267
- if (App.get().sessions.length > 0) {
268
- let session = App.get().sessions[0];
268
+ let session = this.session || App.get().sessions[0];
269
+ if (session) {
269
270
  if (this.displayError && errorInfo.level === logging.Level.ERROR) {
270
271
  this._showMessageBox(session, errorInfo.message, errorInfo.code, errorInfo.log);
271
272
  }
package/src/RemoteApp.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /*
2
- * Copyright (c) 2014-2018 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
@@ -31,10 +31,11 @@ export default class RemoteApp extends App {
31
31
  defaultValues.bootstrap();
32
32
  }
33
33
 
34
- _createErrorHandler() {
35
- return scout.create('ErrorHandler', {
34
+ _createErrorHandler(opts) {
35
+ opts = $.extend({
36
36
  sendError: true
37
- });
37
+ }, opts);
38
+ return super._createErrorHandler(opts);
38
39
  }
39
40
 
40
41
  /**
@@ -47,12 +48,4 @@ export default class RemoteApp extends App {
47
48
  App.get().sessions.push(session);
48
49
  return session.start();
49
50
  }
50
-
51
- _fail(options, error, ...args) {
52
- $.log.error('App initialization failed', error);
53
- this.setLoading(false);
54
- // Session.js already handled the error -> don't show a message here
55
- // Reject with original rejection arguments
56
- return $.rejectedPromise(error, ...args);
57
- }
58
51
  }
@@ -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) {
@@ -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
@@ -482,6 +482,7 @@ export default class Outline extends Tree {
482
482
  }
483
483
  this._setProperty('defaultDetailForm', defaultDetailForm);
484
484
  if (this.defaultDetailForm) {
485
+ this.defaultDetailForm.setClosable(false);
485
486
  this.defaultDetailForm.detailForm = true;
486
487
  }
487
488
  if (this.initialized) {
@@ -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
 
@@ -8,7 +8,7 @@
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
10
10
  */
11
- import {Action, HAlign, Key, keys, scout} from '../index';
11
+ import {Action, HAlign, Key, keys, scout, Widget} from '../index';
12
12
  import $ from 'jquery';
13
13
 
14
14
  export default class KeyStroke {
@@ -134,24 +134,29 @@ export default class KeyStroke {
134
134
  _isEnabled() {
135
135
  // Hint: do not check for which.length because there are keystrokes without a which, e.g. RangeKeyStroke.js
136
136
 
137
- if (this.field) {
138
- // Check visibility
139
- if (this.field.visible !== undefined && !this.field.visible) {
140
- return false;
141
- }
142
- // Check enabled state (if inheritAccessibility is true)
143
- if (!this.inheritAccessibility) {
144
- return true;
145
- }
146
- if (this.field.enabledComputed !== undefined) {
147
- return this.field.enabledComputed;
148
- }
149
- if (this.field.enabled !== undefined) {
150
- // This should actually not happen because this.field should always be a hypothetical case if this.field is not a widget
151
- return this.field.enabled;
152
- }
137
+ if (!this.field) {
138
+ return true;
139
+ }
140
+ if (this.field instanceof Widget && this.field.isRemovalPending()) {
141
+ // Prevent possible exceptions or unexpected behavior if a keystroke is executed while a widget is being removed.
142
+ return false;
143
+ }
144
+ // Check visibility
145
+ if (this.field.visible !== undefined && !this.field.visible) {
146
+ return false;
147
+ }
148
+ // Check enabled state (if inheritAccessibility is true)
149
+ if (!this.inheritAccessibility) {
150
+ return true;
151
+ }
152
+ if (this.field.enabledComputed !== undefined) {
153
+ return this.field.enabledComputed;
154
+ }
155
+ if (this.field.enabled !== undefined) {
156
+ // This should actually not happen because this.field should always be a widget
157
+ return this.field.enabled;
153
158
  }
154
- return true;
159
+ return false;
155
160
  }
156
161
 
157
162
  /**
@@ -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);
package/src/main.less CHANGED
@@ -501,6 +501,7 @@ a,
501
501
  padding: 20px;
502
502
  border: 1px solid @error-border-color;
503
503
  background-color: @error-background-color;
504
+ border-radius: @border-radius-large;
504
505
  }
505
506
 
506
507
  .startup-error-title {