@eclipse-scout/core 11.0.36 → 11.0.42

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-9d2c34f578874327626d.min.js
2
- eclipse-scout-core-9d2c34f578874327626d.min.js.map
1
+ eclipse-scout-core-f05c37a693e6abaa57dc.min.js
2
+ eclipse-scout-core-f05c37a693e6abaa57dc.min.js.map
3
3
  eclipse-scout-core-theme-d1dee22d4f9b9233a432.min.css
4
4
  eclipse-scout-core-theme-dark-7ead007f849a9c1a6ec1.min.css
5
5
  eclipse-scout-core-theme-dark.css
package/dist/texts.json CHANGED
@@ -127,6 +127,8 @@
127
127
  "ui.PleaseWait_": "Please wait",
128
128
  "ui.PopupBlockerDetected": "Opening a new window automatically was blocked by the browser.",
129
129
  "ui.Reconnecting_": "Reconnecting...",
130
+ "ui.RejectedUpload": "Rejected File Upload",
131
+ "ui.RejectedUploadMsg": "The uploaded file was rejected by the security policy.",
130
132
  "ui.Reload": "Reload",
131
133
  "ui.ReloadData": "Reload data",
132
134
  "ui.RemoveFilter": "Remove filter",
@@ -298,6 +300,8 @@
298
300
  "ui.PleaseWait_": "Veuillez attendre",
299
301
  "ui.PopupBlockerDetected": "L'ouverture d'une nouvelle fenêtre a été empêchée par la navigateur.",
300
302
  "ui.Reconnecting_": "Connexion …",
303
+ "ui.RejectedUpload": "Téléchargement de fichier rejeté",
304
+ "ui.RejectedUploadMsg": "Le fichier téléchargé a été rejeté par la politique de sécurité.",
301
305
  "ui.Reload": "Charger à nouveau",
302
306
  "ui.ReloadData": "Nouveau chargement des données",
303
307
  "ui.RemoveFilter": "Supprimer le filtre",
@@ -469,6 +473,8 @@
469
473
  "ui.PleaseWait_": "Attendere prego",
470
474
  "ui.PopupBlockerDetected": "Apertura automatica di una nuova finestra impedita dal browser.",
471
475
  "ui.Reconnecting_": "Collegamento...",
476
+ "ui.RejectedUpload": "Caricamento file rifiutato",
477
+ "ui.RejectedUploadMsg": "Il file caricato è stato rifiutato dalla politica di sicurezza.",
472
478
  "ui.Reload": "Ricarica",
473
479
  "ui.ReloadData": "Ricarica dati",
474
480
  "ui.RemoveFilter": "Rimuovere filtro",
@@ -645,6 +651,8 @@
645
651
  "ui.PleaseWait_": "Bitte warten",
646
652
  "ui.PopupBlockerDetected": "Das automatische Öffnen eines neuen Fensters wurde durch den Browser verhindert.",
647
653
  "ui.Reconnecting_": "Verbinde...",
654
+ "ui.RejectedUpload": "Abgelehnte Datei",
655
+ "ui.RejectedUploadMsg": "Die hochgeladene Datei wurde durch die Sicherheitsrichtlinie abgelehnt.",
648
656
  "ui.Reload": "Neu laden",
649
657
  "ui.ReloadData": "Daten neu laden",
650
658
  "ui.RemoveFilter": "Filter entfernen",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-scout/core",
3
- "version": "11.0.36",
3
+ "version": "11.0.42",
4
4
  "description": "Eclipse Scout runtime",
5
5
  "author": "BSI Business Systems Integration AG",
6
6
  "homepage": "https://www.eclipse.org/scout",
@@ -40,7 +40,7 @@
40
40
  "release-postdependency": "releng-scripts release-publish-dependency"
41
41
  },
42
42
  "devDependencies": {
43
- "@eclipse-scout/cli": "11.0.36",
43
+ "@eclipse-scout/cli": "11.0.42",
44
44
  "@eclipse-scout/releng": "^10.0.0",
45
45
  "jasmine-core": "3.6.0",
46
46
  "jasmine-ajax": "4.0.0",
@@ -80,9 +80,6 @@ export default class ProposalField extends SmartField {
80
80
  if (this.trimText) {
81
81
  validValue = validValue.trim();
82
82
  }
83
- if (validValue.length > this.maxLength) {
84
- validValue = validValue.substring(0, this.maxLength);
85
- }
86
83
  if (validValue === '') {
87
84
  validValue = null;
88
85
  }
@@ -207,10 +204,6 @@ export default class ProposalField extends SmartField {
207
204
  this.setProperty('trimText', trimText);
208
205
  }
209
206
 
210
- setMaxLength(maxLength) {
211
- this.setProperty('maxLength', maxLength);
212
- }
213
-
214
207
  /**
215
208
  * @override ValueField.js
216
209
  */
@@ -63,6 +63,8 @@ export default class SmartField extends ValueField {
63
63
  // only when the result is up-to-date, we can use the selected lookup row
64
64
  this.initActiveFilter = null;
65
65
  this.disabledCopyOverlay = true;
66
+ this.maxLength = 500;
67
+ this.maxLengthHandler = scout.create('MaxLengthHandler', {target: this});
66
68
 
67
69
  this._addCloneProperties(['lookupRow', 'codeType', 'lookupCall', 'activeFilter', 'activeFilterEnabled', 'activeFilterLabels',
68
70
  'browseHierarchy', 'browseMaxRowCount', 'browseAutoExpandAll', 'browseLoadIncremental', 'searchRequired', 'columnDescriptors',
@@ -150,6 +152,7 @@ export default class SmartField extends ValueField {
150
152
  .on('input', this._onFieldInput.bind(this));
151
153
  }
152
154
  this.addField($field);
155
+ this.maxLengthHandler.install($field);
153
156
 
154
157
  if (!this.embedded) {
155
158
  this.addMandatoryIndicator();
@@ -159,6 +162,11 @@ export default class SmartField extends ValueField {
159
162
  this.addStatus();
160
163
  }
161
164
 
165
+ _renderProperties() {
166
+ super._renderProperties();
167
+ this._renderMaxLength();
168
+ }
169
+
162
170
  _renderGridData() {
163
171
  super._renderGridData();
164
172
  this.updateInnerAlignment({
@@ -588,6 +596,14 @@ export default class SmartField extends ValueField {
588
596
  this.$field.setTabbable(this.enabledComputed);
589
597
  }
590
598
 
599
+ setMaxLength(maxLength) {
600
+ this.setProperty('maxLength', maxLength);
601
+ }
602
+
603
+ _renderMaxLength() {
604
+ this.maxLengthHandler.render();
605
+ }
606
+
591
607
  setLookupCall(lookupCall) {
592
608
  this.setProperty('lookupCall', lookupCall);
593
609
  }
@@ -8,20 +8,7 @@
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
10
10
  */
11
- import {
12
- arrays,
13
- BasicField,
14
- fields,
15
- InputFieldKeyStrokeContext,
16
- objects,
17
- scout,
18
- Status,
19
- StringFieldCtrlEnterKeyStroke,
20
- StringFieldEnterKeyStroke,
21
- StringFieldLayout,
22
- strings,
23
- texts
24
- } from '../../../index';
11
+ import {BasicField, fields, InputFieldKeyStrokeContext, objects, scout, Status, StringFieldCtrlEnterKeyStroke, StringFieldEnterKeyStroke, StringFieldLayout, strings, texts} from '../../../index';
25
12
 
26
13
  export default class StringField extends BasicField {
27
14
  constructor() {
@@ -32,6 +19,7 @@ export default class StringField extends BasicField {
32
19
  this.inputMasked = false;
33
20
  this.inputObfuscated = false;
34
21
  this.maxLength = 4000;
22
+ this.maxLengthHandler = scout.create('MaxLengthHandler', {target: this});
35
23
  this.multilineText = false;
36
24
  this.selectionStart = 0;
37
25
  this.selectionEnd = 0;
@@ -90,9 +78,9 @@ export default class StringField extends BasicField {
90
78
  } else {
91
79
  $field = fields.makeTextField(this.$parent);
92
80
  }
93
- $field.on('paste', this._onFieldPaste.bind(this));
94
81
 
95
82
  this.addField($field);
83
+ this.maxLengthHandler.install($field);
96
84
  this.addStatus();
97
85
  }
98
86
 
@@ -185,35 +173,6 @@ export default class StringField extends BasicField {
185
173
  return super.isClearable() && !this.multilineText;
186
174
  }
187
175
 
188
- setMaxLength(maxLength) {
189
- this.setProperty('maxLength', maxLength);
190
- }
191
-
192
- _renderMaxLength() {
193
- // Check if "maxLength" attribute is supported by browser
194
- if (this.$field[0].maxLength) {
195
- this.$field.attr('maxlength', this.maxLength);
196
- } else {
197
- // Fallback for IE9
198
- this.$field.on('keyup paste', e => {
199
- setTimeout(truncate.bind(this), 0);
200
- });
201
- }
202
-
203
- // Make sure current text does not exceed max length
204
- truncate.call(this);
205
- if (!this.rendering) {
206
- this.parseAndSetValue(this._readDisplayText());
207
- }
208
-
209
- function truncate() {
210
- let text = this.$field.val();
211
- if (text.length > this.maxLength) {
212
- this.$field.val(text.slice(0, this.maxLength));
213
- }
214
- }
215
- }
216
-
217
176
  setSelectionStart(selectionStart) {
218
177
  this.setProperty('selectionStart', selectionStart);
219
178
  }
@@ -432,6 +391,14 @@ export default class StringField extends BasicField {
432
391
  });
433
392
  }
434
393
 
394
+ setMaxLength(maxLength) {
395
+ this.setProperty('maxLength', maxLength);
396
+ }
397
+
398
+ _renderMaxLength() {
399
+ this.maxLengthHandler.render();
400
+ }
401
+
435
402
  _onIconClick(event) {
436
403
  this.acceptInput();
437
404
  this.$field.focus();
@@ -561,51 +528,6 @@ export default class StringField extends BasicField {
561
528
  }
562
529
  }
563
530
 
564
- /**
565
- * Get clipboard data, different strategies for browsers.
566
- * Must use a callback because this is required by Chrome's clipboard API.
567
- */
568
- _getClipboardData(event, doneHandler) {
569
- let data = event.originalEvent.clipboardData || this.$container.window(true).clipboardData;
570
- if (data) {
571
- // Chrome, Firefox
572
- if (data.items && data.items.length) {
573
- let item = arrays.find(data.items, item => {
574
- return item.type === 'text/plain';
575
- });
576
- if (item) {
577
- item.getAsString(doneHandler);
578
- }
579
- return;
580
- }
581
-
582
- // IE, Safari
583
- if (data.getData) {
584
- doneHandler(data.getData('Text'));
585
- }
586
- }
587
-
588
- // Can't access clipboard -> don't call done handler
589
- }
590
-
591
- _onFieldPaste(event) {
592
- // must store text and selection because when the callback is executed, the clipboard content has already been applied to the input field
593
- let text = this.$field.val();
594
- let selection = this._getSelection();
595
-
596
- this._getClipboardData(event, pastedText => {
597
- if (!pastedText) {
598
- return;
599
- }
600
-
601
- // Make sure the user is notified about pasted text which is cut off because of maxlength constraints
602
- text = this._applyTextToSelection(text, pastedText, selection);
603
- if (text.length > this.maxLength) {
604
- this._showNotification('ui.PastedTextTooLong');
605
- }
606
- });
607
- }
608
-
609
531
  _showNotification(textKey) {
610
532
  scout.create('DesktopNotification', {
611
533
  parent: this,
@@ -10,9 +10,9 @@
10
10
  */
11
11
  import {
12
12
  arrays,
13
+ fields,
13
14
  HtmlComponent,
14
15
  InputFieldKeyStrokeContext,
15
- fields,
16
16
  keys,
17
17
  LookupCall,
18
18
  scout,
@@ -38,6 +38,8 @@ export default class TagField extends ValueField {
38
38
  this.lookupCall = null;
39
39
  this._currentLookupCall = null;
40
40
  this.tagBar = null;
41
+ this.maxLength = 500;
42
+ this.maxLengthHandler = scout.create('MaxLengthHandler', {target: this});
41
43
  }
42
44
 
43
45
  _init(model) {
@@ -85,12 +87,14 @@ export default class TagField extends ValueField {
85
87
  .on('input', this._onFieldInput.bind(this));
86
88
  this.addFieldContainer($fieldContainer);
87
89
  this.addField($field);
90
+ this.maxLengthHandler.install($field);
88
91
  this.addStatus();
89
92
  }
90
93
 
91
94
  _renderProperties() {
92
95
  super._renderProperties();
93
96
  this._renderValue();
97
+ this._renderMaxLength();
94
98
  }
95
99
 
96
100
  _renderValue() {
@@ -155,6 +159,14 @@ export default class TagField extends ValueField {
155
159
  }
156
160
  }
157
161
 
162
+ setMaxLength(maxLength) {
163
+ this.setProperty('maxLength', maxLength);
164
+ }
165
+
166
+ _renderMaxLength() {
167
+ this.maxLengthHandler.render();
168
+ }
169
+
158
170
  _updateInputVisible() {
159
171
  let visible, oldVisible = !this.$field.isVisible();
160
172
  if (this.enabledComputed) {
package/src/index.js CHANGED
@@ -42,6 +42,7 @@ export {default as fonts} from './util/fonts';
42
42
  export {default as icons} from './util/icons';
43
43
  export {default as inspector} from './util/inspector';
44
44
  export {default as locales} from './util/locales';
45
+ export {default as MaxLengthHandler} from './util/MaxLengthHandler';
45
46
  export {default as logging} from './logging/logging';
46
47
  export {default as NullLogger} from './logging/NullLogger';
47
48
  export {default as mimeTypes} from './util/mimeTypes';
@@ -8,9 +8,38 @@
8
8
  * Contributors:
9
9
  * BSI Business Systems Integration AG - initial API and implementation
10
10
  */
11
- import {arrays, LookupCall, scout} from '../index';
11
+ import {arrays, LookupCall, objects, scout} from '../index';
12
12
  import $ from 'jquery';
13
13
 
14
+ /**
15
+ * A lookup call that can load lookup rows from a REST service.
16
+ *
17
+ * API:
18
+ * ----
19
+ * By default, the REST service is expected to listen for POST requests at the URL defined by
20
+ * this.resourceUrl. It receives a restriction object and must return a list of matching lookup rows.
21
+ * The serialization format is JSON.
22
+ *
23
+ * Lookup rows:
24
+ * ------------
25
+ * The standard lookup row properties defined by Scout are usually sufficient (see AbstractLookupRowDo.java).
26
+ *
27
+ * Restriction:
28
+ * ------------
29
+ * The restriction object consists of a number of 'well-known' properties (e.g. 'text' in QueryBy.TEXT
30
+ * mode, see AbstractLookupRestrictionDo.java for details) and additional, service-dependent properties
31
+ * that can either be predefined in the model or added programmatically at runtime. Since all of those
32
+ * properties are sent in the same restriction object, some care must be taken to prevent accidental
33
+ * overwriting of properties.
34
+ *
35
+ * Order of precedence (lowest to highest):
36
+ * 1. Restrictions automatically applied to all clones after their creation in the respective cloneFor method.
37
+ * These are: 'active' (ALL, TEXT, REC) and 'maxRowCount' (ALL, TEXT, REC)
38
+ * 2. Restrictions predefined in the model property 'restriction', shared by all clones.
39
+ * 3. Restrictions applied to clones programmatically, e.g. during a 'prepareLookupCall' event.
40
+ * 4. Hard-coded properties that are fundamental to the respective queryBy mode (cannot be overridden).
41
+ * These are: 'ids' (KEY, KEYS) and 'text' (TEXT)
42
+ */
14
43
  export default class RestLookupCall extends LookupCall {
15
44
 
16
45
  constructor() {
@@ -42,6 +71,17 @@ export default class RestLookupCall extends LookupCall {
42
71
  this._restriction[key] = value;
43
72
  }
44
73
 
74
+ /**
75
+ * Adds the given key-value pair to 'this._restriction', but only if there is no predefined
76
+ * value for this key in 'this.restriction'. This prevents unintentional overriding of
77
+ * user-defined model restrictions.
78
+ */
79
+ _addRestrictionIfAbsent(key, value) {
80
+ if (!this.restriction || objects.isNullOrUndefined(this.restriction[key])) {
81
+ this.addRestriction(key, value);
82
+ }
83
+ }
84
+
45
85
  _getAll() {
46
86
  return this._call();
47
87
  }
@@ -63,22 +103,22 @@ export default class RestLookupCall extends LookupCall {
63
103
 
64
104
  cloneForAll() {
65
105
  let clone = super.cloneForAll();
66
- clone.addRestriction('active', true);
67
- clone.addRestriction('maxRowCount', this.maxRowCount);
106
+ clone._addRestrictionIfAbsent('active', true);
107
+ clone._addRestrictionIfAbsent('maxRowCount', this.maxRowCount);
68
108
  return clone;
69
109
  }
70
110
 
71
111
  cloneForText(text) {
72
112
  let clone = super.cloneForText(text);
73
- clone.addRestriction('active', true);
74
- clone.addRestriction('maxRowCount', this.maxRowCount);
113
+ clone._addRestrictionIfAbsent('active', true);
114
+ clone._addRestrictionIfAbsent('maxRowCount', this.maxRowCount);
75
115
  return clone;
76
116
  }
77
117
 
78
118
  cloneForRec(parentKey) {
79
119
  let clone = super.cloneForRec(parentKey);
80
- clone.addRestriction('active', true);
81
- clone.addRestriction('maxRowCount', this.maxRowCount);
120
+ clone._addRestrictionIfAbsent('active', true);
121
+ clone._addRestrictionIfAbsent('maxRowCount', this.maxRowCount);
82
122
  return clone;
83
123
  }
84
124
 
@@ -167,7 +207,7 @@ export default class RestLookupCall extends LookupCall {
167
207
  return value;
168
208
  };
169
209
 
170
- let newRestrictions = {};
210
+ let resolvedRestriction = {};
171
211
  let restriction = $.extend({}, this.restriction, this._restriction);
172
212
  Object.keys(restriction).forEach(key => {
173
213
  let value = restriction[key];
@@ -180,11 +220,11 @@ export default class RestLookupCall extends LookupCall {
180
220
  newValue = resolveValue(value);
181
221
  }
182
222
  // Only add non-null restrictions
183
- if (newValue) {
184
- newRestrictions[key] = newValue;
223
+ if (!objects.isNullOrUndefined(newValue)) {
224
+ resolvedRestriction[key] = newValue;
185
225
  }
186
226
  });
187
- return newRestrictions;
227
+ return resolvedRestriction;
188
228
  }
189
229
 
190
230
  _createAjaxCall() {
@@ -122,6 +122,7 @@ export default class Session {
122
122
  SESSION_TIMEOUT: 10,
123
123
  UI_PROCESSING: 20,
124
124
  UNSAFE_UPLOAD: 30,
125
+ REJECTED_UPLOAD: 31,
125
126
  VERSION_MISMATCH: 40
126
127
  };
127
128
 
@@ -1048,6 +1049,12 @@ export default class Session {
1048
1049
  boxOptions.yesButtonText = this.optText('ui.Ok', 'Ok');
1049
1050
  boxOptions.yesButtonAction = () => {
1050
1051
  };
1052
+ } else if (jsonError.code === Session.JsonResponseError.REJECTED_UPLOAD) {
1053
+ boxOptions.header = this.optText('ui.RejectedUpload', boxOptions.header);
1054
+ boxOptions.body = this.optText('ui.RejectedUploadMsg', boxOptions.body);
1055
+ boxOptions.yesButtonText = this.optText('ui.Ok', 'Ok');
1056
+ boxOptions.yesButtonAction = () => {
1057
+ };
1051
1058
  }
1052
1059
  this.showFatalMessage(boxOptions, jsonError.code);
1053
1060
  }
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright (c) 2010-2021 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
+ * http://www.eclipse.org/legal/epl-v10.html
7
+ *
8
+ * Contributors:
9
+ * BSI Business Systems Integration AG - initial API and implementation
10
+ */
11
+ import {arrays, objects, scout, Status} from '../index';
12
+ import $ from 'jquery';
13
+ import {assertValue} from '../scout';
14
+
15
+ export default class MaxLengthHandler {
16
+
17
+ constructor(options) {
18
+ options = options || {};
19
+ assertValue(options.target, 'target is mandatory');
20
+
21
+ this.$textInputField = null;
22
+ this.onInputFieldPaste = this._onInputFieldPaste.bind(this);
23
+ $.extend(this, options);
24
+ }
25
+
26
+ install($textInputField) {
27
+ this.uninstall();
28
+ if (!$textInputField || (!$textInputField.is('input:text') && !$textInputField.is('textarea'))) {
29
+ return;
30
+ }
31
+ if ($textInputField) {
32
+ this.$textInputField = $textInputField;
33
+ this.$textInputField.on('paste', this.onInputFieldPaste);
34
+ }
35
+ }
36
+
37
+ uninstall() {
38
+ if (this.$textInputField) {
39
+ this.$textInputField.off('paste', this.onInputFieldPaste);
40
+ }
41
+ }
42
+
43
+ render() {
44
+ if (!this.$textInputField || objects.isNullOrUndefined(this.target.maxLength)) {
45
+ return;
46
+ }
47
+ this.$textInputField.attr('maxlength', this.target.maxLength);
48
+
49
+ // Make sure current text does not exceed max length
50
+ let text = this.$textInputField.val();
51
+ if (text.length > this.target.maxLength) {
52
+ this.$textInputField.val(text.slice(0, this.target.maxLength));
53
+ }
54
+ if (!this.target.rendering) {
55
+ this.target.parseAndSetValue(this.target._readDisplayText());
56
+ }
57
+ }
58
+
59
+ _onInputFieldPaste(event) {
60
+ if (!this.$textInputField || objects.isNullOrUndefined(this.target.maxLength)) {
61
+ return;
62
+ }
63
+ // must read out the text and selection size now because when the callback is executed, the clipboard content has already been applied to the input field
64
+ let textSize = this.$textInputField.val().length - this._getSelectionSize();
65
+
66
+ this._getClipboardData(event, pastedText => {
67
+ if (!pastedText) {
68
+ return;
69
+ }
70
+ if ((textSize + pastedText.length) > this.target.maxLength) {
71
+ this._showNotification('ui.PastedTextTooLong');
72
+ }
73
+ });
74
+ }
75
+
76
+ _getSelectionSize() {
77
+ let start = scout.nvl(this.$textInputField[0].selectionStart, null);
78
+ let end = scout.nvl(this.$textInputField[0].selectionEnd, null);
79
+ if (start === null || end === null) {
80
+ return 0;
81
+ }
82
+ return end - start;
83
+ }
84
+
85
+ /**
86
+ * Get clipboard data, different strategies for browsers.
87
+ * Must use a callback because this is required by Chrome's clipboard API.
88
+ */
89
+ _getClipboardData(event, doneHandler) {
90
+ let data = event.originalEvent.clipboardData || this.target.$container.window(true).clipboardData;
91
+ if (data) {
92
+ // Chrome, Firefox
93
+ if (data.items && data.items.length) {
94
+ let item = arrays.find(data.items, item => {
95
+ return item.type === 'text/plain';
96
+ });
97
+ if (item) {
98
+ item.getAsString(doneHandler);
99
+ }
100
+ return;
101
+ }
102
+
103
+ // IE, Safari
104
+ if (data.getData) {
105
+ doneHandler(data.getData('Text'));
106
+ }
107
+ }
108
+
109
+ // Can't access clipboard -> don't call done handler
110
+ }
111
+
112
+ _showNotification(textKey) {
113
+ scout.create('DesktopNotification', {
114
+ parent: this.target,
115
+ severity: Status.Severity.WARNING,
116
+ message: this.target.session.text(textKey)
117
+ }).show();
118
+ }
119
+ }