@eclipse-scout/core 22.0.0-beta.1 → 22.0.0-beta.5
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/eclipse-scout-core-theme-dark.css +71 -20
- package/dist/eclipse-scout-core-theme-dark.css.map +1 -1
- package/dist/eclipse-scout-core-theme.css +70 -19
- package/dist/eclipse-scout-core-theme.css.map +1 -1
- package/dist/eclipse-scout-core.js +295 -242
- package/dist/eclipse-scout-core.js.map +1 -1
- package/package.json +2 -2
- package/src/App.js +71 -9
- package/src/RemoteApp.js +1 -0
- package/src/desktop/Desktop.js +3 -3
- package/src/desktop/notification/DesktopNotification.js +33 -8
- package/src/desktop/outline/Outline.js +2 -2
- package/src/desktop/outline/Outline.less +14 -6
- package/src/desktop/outline/OutlineViewButton.js +1 -0
- package/src/filechooser/FileChooser.js +2 -1
- package/src/form/Form.js +11 -3
- package/src/glasspane/DeferredGlassPaneTarget.js +2 -2
- package/src/login/LoginBox.less +8 -1
- package/src/main.less +1 -1
- package/src/menu/ComboMenu.js +22 -17
- package/src/menu/ComboMenu.less +71 -26
- package/src/menu/ContextMenuPopup.js +3 -2
- package/src/menu/ContextMenuPopup.less +1 -1
- package/src/menu/EllipsisMenu.js +4 -0
- package/src/menu/Menu.js +24 -11
- package/src/menu/menubar/MenuBar.js +2 -19
- package/src/menu/menubar/MenuBarBox.js +3 -34
- package/src/menu/menubar/MenuBarLayout.js +6 -19
- package/src/menu/menubox/MenuBoxLayout.js +1 -1
- package/src/menu/menus.js +4 -10
- package/src/messagebox/MessageBox.js +3 -22
- package/src/modeselector/ModeSelectorLayout.js +11 -6
- package/src/notification/Notification.js +15 -14
- package/src/popup/Popup.js +3 -20
- package/src/session/BusyIndicator.js +2 -1
- package/src/session/Session.js +0 -62
- package/src/status/Status.js +2 -1
- package/src/style/colors-dark.less +3 -1
- package/src/style/colors.less +2 -0
- package/src/style/sizes.less +1 -0
- package/src/table/columns/Column.js +4 -0
- package/src/tree/Tree.js +2 -2
- package/src/widget/LoadingSupport.js +1 -1
- package/src/widget/Widget.js +28 -32
- package/src/widget/WidgetSupport.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eclipse-scout/core",
|
|
3
|
-
"version": "22.0.0-beta.
|
|
3
|
+
"version": "22.0.0-beta.5",
|
|
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.0-beta.
|
|
29
|
+
"@eclipse-scout/cli": "22.0.0-beta.5",
|
|
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
|
@@ -38,6 +38,7 @@ export default class App {
|
|
|
38
38
|
this.events = this._createEventSupport();
|
|
39
39
|
this.initialized = false;
|
|
40
40
|
this.sessions = [];
|
|
41
|
+
this._loadingTimeoutId = null;
|
|
41
42
|
|
|
42
43
|
// register the listeners which were added to scout before the app is created
|
|
43
44
|
listeners.forEach(function(listener) {
|
|
@@ -195,8 +196,11 @@ export default class App {
|
|
|
195
196
|
*/
|
|
196
197
|
_init(options) {
|
|
197
198
|
options = options || {};
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
this.setLoading(true)
|
|
200
|
+
let compatibilityPromise = this._checkBrowserCompatibility(options);
|
|
201
|
+
if (compatibilityPromise) {
|
|
202
|
+
this.setLoading(false);
|
|
203
|
+
return compatibilityPromise.then(newOptions => this._init(newOptions));
|
|
200
204
|
}
|
|
201
205
|
|
|
202
206
|
this._initVersion(options);
|
|
@@ -224,23 +228,79 @@ export default class App {
|
|
|
224
228
|
$.log.isInfoEnabled() && $.log.info('Detected browser ' + device.browser + ' version ' + device.browserVersion);
|
|
225
229
|
if (!scout.nvl(options.checkBrowserCompatibility, true) || device.isSupportedBrowser()) {
|
|
226
230
|
// No check requested or browser is supported
|
|
227
|
-
return
|
|
231
|
+
return;
|
|
228
232
|
}
|
|
229
233
|
|
|
234
|
+
let deferred = $.Deferred();
|
|
235
|
+
let newOptions = objects.valueCopy(options);
|
|
236
|
+
newOptions.checkBrowserCompatibility = false;
|
|
230
237
|
$('.scout').each(function() {
|
|
231
|
-
let $entryPoint = $(this)
|
|
232
|
-
|
|
233
|
-
newOptions = objects.valueCopy(options);
|
|
238
|
+
let $entryPoint = $(this);
|
|
239
|
+
let $box = $entryPoint.appendDiv();
|
|
234
240
|
|
|
235
|
-
newOptions.checkBrowserCompatibility = false;
|
|
236
241
|
$box.load('unsupported-browser.html', () => {
|
|
237
242
|
$box.find('button').on('click', () => {
|
|
238
243
|
$box.remove();
|
|
239
|
-
|
|
244
|
+
deferred.resolve(newOptions);
|
|
240
245
|
});
|
|
241
246
|
});
|
|
242
247
|
});
|
|
243
|
-
return
|
|
248
|
+
return deferred.promise();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
setLoading(loading) {
|
|
252
|
+
if (loading) {
|
|
253
|
+
this._loadingTimeoutId = setTimeout(() => {
|
|
254
|
+
// Don't start loading if a desktop is already rendered to prevent flickering when the loading will be set to false after app initialization finishes
|
|
255
|
+
if (!this.sessions.some(session => session.desktop && session.desktop.rendered)) {
|
|
256
|
+
this._renderLoading();
|
|
257
|
+
}
|
|
258
|
+
}, 200);
|
|
259
|
+
} else {
|
|
260
|
+
clearTimeout(this._loadingTimeoutId);
|
|
261
|
+
this._loadingTimeoutId = null;
|
|
262
|
+
this._removeLoading();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_renderLoading() {
|
|
267
|
+
let $body = $('body'),
|
|
268
|
+
$loadingRoot = $body.children('.application-loading-root');
|
|
269
|
+
if (!$loadingRoot.length) {
|
|
270
|
+
$loadingRoot = $body.appendDiv('application-loading-root')
|
|
271
|
+
.addClass('application-loading-root')
|
|
272
|
+
.fadeIn();
|
|
273
|
+
}
|
|
274
|
+
this._renderLoadingElement($loadingRoot, 'application-loading01');
|
|
275
|
+
this._renderLoadingElement($loadingRoot, 'application-loading02');
|
|
276
|
+
this._renderLoadingElement($loadingRoot, 'application-loading03');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
_renderLoadingElement($loadingRoot, cssClass) {
|
|
280
|
+
if ($loadingRoot.children('.' + cssClass).length) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
// noinspection JSValidateTypes
|
|
284
|
+
$loadingRoot.appendDiv(cssClass).hide()
|
|
285
|
+
.fadeIn();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
_removeLoading() {
|
|
289
|
+
let $loadingRoot = $('body').children('.application-loading-root');
|
|
290
|
+
// the fadeout animation only contains a to-value and no from-value
|
|
291
|
+
// therefore set the current value to the elements style
|
|
292
|
+
$loadingRoot.css('opacity', $loadingRoot.css('opacity'));
|
|
293
|
+
// Add animation listener before adding the classes to ensure the listener will always be triggered even while debugging
|
|
294
|
+
$loadingRoot.oneAnimationEnd(() => $loadingRoot.remove());
|
|
295
|
+
if ($loadingRoot.css('opacity') == 1) {
|
|
296
|
+
$loadingRoot.addClass('fadeout and-more');
|
|
297
|
+
} else {
|
|
298
|
+
$loadingRoot.addClass('fadeout');
|
|
299
|
+
}
|
|
300
|
+
if (!Device.get().supportsCssAnimation()) {
|
|
301
|
+
// fallback for old browsers that do not support the animation-end event
|
|
302
|
+
$loadingRoot.remove();
|
|
303
|
+
}
|
|
244
304
|
}
|
|
245
305
|
|
|
246
306
|
_initVersion(options) {
|
|
@@ -380,6 +440,7 @@ export default class App {
|
|
|
380
440
|
|
|
381
441
|
_initDone(options) {
|
|
382
442
|
this.initialized = true;
|
|
443
|
+
this.setLoading(false);
|
|
383
444
|
this.trigger('init', {
|
|
384
445
|
options: options
|
|
385
446
|
});
|
|
@@ -388,6 +449,7 @@ export default class App {
|
|
|
388
449
|
|
|
389
450
|
_fail(options, error, ...args) {
|
|
390
451
|
$.log.error('App initialization failed.');
|
|
452
|
+
this.setLoading(false);
|
|
391
453
|
|
|
392
454
|
return this.errorHandler.handle(error, ...args)
|
|
393
455
|
.then(errorInfo => {
|
package/src/RemoteApp.js
CHANGED
|
@@ -50,6 +50,7 @@ export default class RemoteApp extends App {
|
|
|
50
50
|
|
|
51
51
|
_fail(options, error, ...args) {
|
|
52
52
|
$.log.error('App initialization failed', error);
|
|
53
|
+
this.setLoading(false);
|
|
53
54
|
// Session.js already handled the error -> don't show a message here
|
|
54
55
|
// Reject with original rejection arguments
|
|
55
56
|
return $.rejectedPromise(error, ...args);
|
package/src/desktop/Desktop.js
CHANGED
|
@@ -895,11 +895,11 @@ export default class Desktop extends Widget {
|
|
|
895
895
|
}
|
|
896
896
|
|
|
897
897
|
/**
|
|
898
|
-
*
|
|
898
|
+
* Removes every popup which is a descendant of the given widget.
|
|
899
899
|
*/
|
|
900
|
-
|
|
900
|
+
removePopupsFor(widget) {
|
|
901
901
|
this.getPopupsFor(widget).forEach(popup => {
|
|
902
|
-
popup.
|
|
902
|
+
popup.remove();
|
|
903
903
|
});
|
|
904
904
|
}
|
|
905
905
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c) 2010-
|
|
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
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Contributors:
|
|
9
9
|
* BSI Business Systems Integration AG - initial API and implementation
|
|
10
10
|
*/
|
|
11
|
-
import {Device, Notification as ScoutNotification, strings} from '../../index';
|
|
11
|
+
import {Device, Notification as ScoutNotification, scout, Status, strings} from '../../index';
|
|
12
12
|
|
|
13
13
|
export default class DesktopNotification extends ScoutNotification {
|
|
14
14
|
|
|
@@ -20,7 +20,7 @@ export default class DesktopNotification extends ScoutNotification {
|
|
|
20
20
|
this._removing = false;
|
|
21
21
|
this.nativeOnly = false;
|
|
22
22
|
this.nativeNotificationTitle = null;
|
|
23
|
-
this.
|
|
23
|
+
this.nativeNotificationStatus = null; // holds native message & native icon
|
|
24
24
|
this.nativeNotificationVisibility = DesktopNotification.NativeNotificationVisibility.NONE;
|
|
25
25
|
this.nativeNotification = null;
|
|
26
26
|
this.nativeNotificationShown = false;
|
|
@@ -58,7 +58,13 @@ export default class DesktopNotification extends ScoutNotification {
|
|
|
58
58
|
let defaults = this.session.desktop.nativeNotificationDefaults;
|
|
59
59
|
if (defaults) {
|
|
60
60
|
this.nativeNotificationTitle = model.nativeNotificationTitle !== undefined ? model.nativeNotificationTitle : defaults.title;
|
|
61
|
-
this.
|
|
61
|
+
if (this.nativeNotificationStatus) {
|
|
62
|
+
this.nativeNotificationStatus.iconId = this.nativeNotificationStatus.iconId !== undefined ? this.nativeNotificationStatus.iconId : defaults.iconId;
|
|
63
|
+
} else {
|
|
64
|
+
this.nativeNotificationStatus = new Status({
|
|
65
|
+
iconId: defaults.iconId
|
|
66
|
+
});
|
|
67
|
+
}
|
|
62
68
|
this.nativeNotificationVisibility = scout.nvl(model.nativeNotificationVisibility !== undefined ? model.nativeNotificationVisibility : defaults.visibility, DesktopNotification.NativeNotificationVisibility.NONE);
|
|
63
69
|
}
|
|
64
70
|
this.resolveTextKeys(['nativeNotificationTitle']);
|
|
@@ -108,10 +114,24 @@ export default class DesktopNotification extends ScoutNotification {
|
|
|
108
114
|
return;
|
|
109
115
|
}
|
|
110
116
|
let title = scout.nvl(this.nativeNotificationTitle, '');
|
|
111
|
-
let body =
|
|
117
|
+
let body = (this.nativeNotificationStatus || {}).message;
|
|
118
|
+
if (strings.empty(body)) {
|
|
119
|
+
body = (this.status || {}).message;
|
|
120
|
+
}
|
|
121
|
+
if (!body) {
|
|
122
|
+
body = '';
|
|
123
|
+
}
|
|
124
|
+
if (this.htmlEnabled) {
|
|
125
|
+
body = strings.plainText(body, {removeFontIcons: true});
|
|
126
|
+
}
|
|
127
|
+
let iconId = (this.nativeNotificationStatus || {}).iconId;
|
|
128
|
+
if (strings.empty(iconId)) {
|
|
129
|
+
// icon must not be null or empty. If no icon it must be undefined
|
|
130
|
+
iconId = undefined;
|
|
131
|
+
}
|
|
112
132
|
this.nativeNotification = new Notification(title, {
|
|
113
133
|
body: body,
|
|
114
|
-
icon:
|
|
134
|
+
icon: iconId
|
|
115
135
|
});
|
|
116
136
|
|
|
117
137
|
this.nativeNotification.addEventListener('show', event => {
|
|
@@ -240,8 +260,13 @@ export default class DesktopNotification extends ScoutNotification {
|
|
|
240
260
|
this.setProperty('nativeNotificationTitle', title);
|
|
241
261
|
}
|
|
242
262
|
|
|
243
|
-
|
|
244
|
-
this.setProperty('
|
|
263
|
+
setNativeNotificationStatus(status) {
|
|
264
|
+
this.setProperty('nativeNotificationStatus', status);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
_setNativeNotificationStatus(status) {
|
|
268
|
+
status = Status.ensure(status);
|
|
269
|
+
this._setProperty('nativeNotificationStatus', status);
|
|
245
270
|
}
|
|
246
271
|
|
|
247
272
|
setNativeNotificationVisibility(visibility) {
|
|
@@ -1064,10 +1064,10 @@ export default class Outline extends Tree {
|
|
|
1064
1064
|
this.setProperty('nodeMenuBarVisible', visible);
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
|
-
glassPaneTargets() {
|
|
1067
|
+
glassPaneTargets(element) {
|
|
1068
1068
|
// MessageBoxes are often created with Outlines as displayParent. The default implementation of this function
|
|
1069
1069
|
// would not render any glass panes when the outline is collapsed, thus we need to override this behavior.
|
|
1070
|
-
return this._glassPaneTargets();
|
|
1070
|
+
return this._glassPaneTargets(element);
|
|
1071
1071
|
}
|
|
1072
1072
|
|
|
1073
1073
|
_glassPaneTargets(element) {
|
|
@@ -9,12 +9,6 @@
|
|
|
9
9
|
* BSI Business Systems Integration AG - initial API and implementation
|
|
10
10
|
*/
|
|
11
11
|
.outline.tree {
|
|
12
|
-
|
|
13
|
-
&.in-background > .tree-data > .tree-node.selected {
|
|
14
|
-
background-color: @outline-in-background-selection-background-color;
|
|
15
|
-
color: @outline-in-background-selection-color;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
12
|
& > .tree-data {
|
|
19
13
|
padding-top: @outline-data-padding-top;
|
|
20
14
|
|
|
@@ -91,6 +85,20 @@
|
|
|
91
85
|
}
|
|
92
86
|
}
|
|
93
87
|
}
|
|
88
|
+
|
|
89
|
+
&.in-background > .tree-data {
|
|
90
|
+
& > .tree-node,
|
|
91
|
+
& > .animation-wrapper > .tree-node {
|
|
92
|
+
&.group {
|
|
93
|
+
background-color: @outline-in-background-group-background-color;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&.selected {
|
|
97
|
+
background-color: @outline-in-background-selection-background-color;
|
|
98
|
+
color: @outline-in-background-selection-color;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
.outline-title {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c) 2010-
|
|
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
|
|
@@ -21,6 +21,7 @@ export default class FileChooser extends Widget {
|
|
|
21
21
|
this.boxButtons = null;
|
|
22
22
|
this.uploadButton = null;
|
|
23
23
|
this.cancelButton = null;
|
|
24
|
+
this.inheritAccessibility = false; // inherit not necessary. if the FileChooser can be opened, it must be editable. Opening a disabled chooser makes no sense.
|
|
24
25
|
this._addWidgetProperties(['boxButtons', 'uploadButton', 'cancelButton']);
|
|
25
26
|
}
|
|
26
27
|
|
package/src/form/Form.js
CHANGED
|
@@ -294,7 +294,9 @@ export default class Form extends Widget {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/**
|
|
297
|
-
* Method may be implemented to load the data.
|
|
297
|
+
* Method may be implemented to load the data. <br>
|
|
298
|
+
* By default, a resolved promise containing the provided this.data is returned.
|
|
299
|
+
* @returns {Promise}
|
|
298
300
|
*/
|
|
299
301
|
_load() {
|
|
300
302
|
return $.resolvedPromise().then(() => {
|
|
@@ -319,6 +321,9 @@ export default class Form extends Widget {
|
|
|
319
321
|
return $.resolvedPromise();
|
|
320
322
|
}
|
|
321
323
|
|
|
324
|
+
/**
|
|
325
|
+
* @param {any} data
|
|
326
|
+
*/
|
|
322
327
|
setData(data) {
|
|
323
328
|
this.setProperty('data', data);
|
|
324
329
|
}
|
|
@@ -327,8 +332,11 @@ export default class Form extends Widget {
|
|
|
327
332
|
// NOP
|
|
328
333
|
}
|
|
329
334
|
|
|
335
|
+
/**
|
|
336
|
+
* @returns {any}
|
|
337
|
+
*/
|
|
330
338
|
exportData() {
|
|
331
|
-
|
|
339
|
+
return null;
|
|
332
340
|
}
|
|
333
341
|
|
|
334
342
|
/**
|
|
@@ -382,7 +390,7 @@ export default class Form extends Widget {
|
|
|
382
390
|
|
|
383
391
|
/**
|
|
384
392
|
* This function is called by the lifecycle, when the 'save' function is called.<p>
|
|
385
|
-
* The data given to this function is the result of
|
|
393
|
+
* The data given to this function is the result of {@link exportData} which was called in advance.
|
|
386
394
|
*
|
|
387
395
|
* @returns {Promise} promise which may contain a Status specifying if the save operation was successful. The promise may be empty which means the save operation was successful.
|
|
388
396
|
*/
|
package/src/login/LoginBox.less
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c) 2010-
|
|
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
|
|
@@ -84,3 +84,10 @@
|
|
|
84
84
|
height: 18px;
|
|
85
85
|
vertical-align: middle;
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
.login-body,
|
|
89
|
+
.logout-body {
|
|
90
|
+
& > .box-background-elements.box-background-elements-fadeout {
|
|
91
|
+
#scout.animation(nop 0.05s);
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/main.less
CHANGED
|
@@ -408,7 +408,7 @@ button::-moz-focus-inner {
|
|
|
408
408
|
pointer-events: none;
|
|
409
409
|
|
|
410
410
|
&.fadeout {
|
|
411
|
-
#scout.animation(application-loading-fade-out @loading-fade-duration linear 1);
|
|
411
|
+
#scout.animation(application-loading-fade-out @loading-fade-duration linear 1 forwards);
|
|
412
412
|
}
|
|
413
413
|
}
|
|
414
414
|
|
package/src/menu/ComboMenu.js
CHANGED
|
@@ -8,21 +8,13 @@
|
|
|
8
8
|
* Contributors:
|
|
9
9
|
* BSI Business Systems Integration AG - initial API and implementation
|
|
10
10
|
*/
|
|
11
|
-
import {HtmlComponent, Menu} from '../index';
|
|
11
|
+
import {HtmlComponent, Menu, widgets} from '../index';
|
|
12
12
|
|
|
13
13
|
export default class ComboMenu extends Menu {
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
16
|
super();
|
|
17
|
-
this.
|
|
18
|
-
this._childSelectedHandler = this._onChildSelected.bind(this);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
_setChildActions(childActions) {
|
|
22
|
-
this.childActions.forEach(child => child.off('propertyChange:selected', this._childSelectedHandler));
|
|
23
|
-
super._setChildActions(childActions);
|
|
24
|
-
this.childActions.forEach(child => child.on('propertyChange:selected', this._childSelectedHandler));
|
|
25
|
-
this._updateChildSelected();
|
|
17
|
+
this._childVisibleChangeHandler = this._onChildVisibleChange.bind(this);
|
|
26
18
|
}
|
|
27
19
|
|
|
28
20
|
_render() {
|
|
@@ -36,10 +28,15 @@ export default class ComboMenu extends Menu {
|
|
|
36
28
|
|
|
37
29
|
_renderProperties() {
|
|
38
30
|
super._renderProperties();
|
|
39
|
-
this._renderChildSelected();
|
|
40
31
|
this._renderChildActions();
|
|
41
32
|
}
|
|
42
33
|
|
|
34
|
+
_setChildActions(childActions) {
|
|
35
|
+
this.childActions.forEach(child => child.off('propertyChange:visible', this._childVisibleChangeHandler));
|
|
36
|
+
super._setChildActions(childActions);
|
|
37
|
+
this.childActions.forEach(child => child.on('propertyChange:visible', this._childVisibleChangeHandler));
|
|
38
|
+
}
|
|
39
|
+
|
|
43
40
|
_renderChildActions() {
|
|
44
41
|
super._renderChildActions();
|
|
45
42
|
|
|
@@ -47,6 +44,7 @@ export default class ComboMenu extends Menu {
|
|
|
47
44
|
childAction.addCssClass('combo-menu-child');
|
|
48
45
|
childAction.render();
|
|
49
46
|
});
|
|
47
|
+
widgets.updateFirstLastMarker(this.childActions);
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
// @override
|
|
@@ -54,15 +52,22 @@ export default class ComboMenu extends Menu {
|
|
|
54
52
|
return false;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
this.
|
|
55
|
+
_onChildVisibleChange(event) {
|
|
56
|
+
if (this.rendered) {
|
|
57
|
+
widgets.updateFirstLastMarker(this.childActions);
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
_doActionTogglesPopup() {
|
|
62
|
+
return false;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
isToggleAction() {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isTabTarget() {
|
|
70
|
+
// To make children tabbable, combo menu must never be a tab target, even if its a default menu
|
|
71
|
+
return false;
|
|
67
72
|
}
|
|
68
73
|
}
|
package/src/menu/ComboMenu.less
CHANGED
|
@@ -18,25 +18,32 @@
|
|
|
18
18
|
background-color: transparent;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
& > .menu-item
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
& > .menu-item {
|
|
22
|
+
&:not(.first) {
|
|
23
|
+
margin-left: 3px;
|
|
24
|
+
|
|
25
|
+
&::before {
|
|
26
|
+
content: '';
|
|
27
|
+
position: absolute;
|
|
28
|
+
left: -1px;
|
|
29
|
+
top: 7px;
|
|
30
|
+
height: calc(100% - 14px);
|
|
31
|
+
width: 1px;
|
|
32
|
+
background-color: @border-color;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
|
-
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
&:not(.disabled):hover {
|
|
37
|
-
& > .menu-item:not(:first-child)::before {
|
|
36
|
+
&:focus::before {
|
|
38
37
|
display: none;
|
|
39
38
|
}
|
|
39
|
+
|
|
40
|
+
&:not(.disabled):hover,
|
|
41
|
+
&.selected {
|
|
42
|
+
&::before,
|
|
43
|
+
& ~ .menu-item::before {
|
|
44
|
+
display: none;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -45,14 +52,19 @@
|
|
|
45
52
|
|
|
46
53
|
& > .menu-item {
|
|
47
54
|
border: 1px solid @button-border-color;
|
|
55
|
+
flex-grow: 1;
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
&.menu-icononly:not(.first.last) { // Rule must not be applied if combo menu contains only one item
|
|
58
|
+
flex-grow: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&:not(.last) {
|
|
50
62
|
border-top-right-radius: 0;
|
|
51
63
|
border-bottom-right-radius: 0;
|
|
52
64
|
border-right: 0;
|
|
53
65
|
}
|
|
54
66
|
|
|
55
|
-
&:not(
|
|
67
|
+
&:not(.first) {
|
|
56
68
|
border-top-left-radius: 0;
|
|
57
69
|
border-bottom-left-radius: 0;
|
|
58
70
|
border-left: 0;
|
|
@@ -62,31 +74,64 @@
|
|
|
62
74
|
.disabled& {
|
|
63
75
|
border-color: @button-disabled-color;
|
|
64
76
|
}
|
|
77
|
+
|
|
78
|
+
&:focus {
|
|
79
|
+
z-index: 1; // Allows box-shadow to draw over the right menu-item
|
|
80
|
+
}
|
|
65
81
|
}
|
|
66
82
|
|
|
67
83
|
&.default {
|
|
68
84
|
& > .menu-item {
|
|
69
85
|
.button.default();
|
|
70
86
|
|
|
87
|
+
&::before {
|
|
88
|
+
background-color: @default-combo-menu-separator-color;
|
|
89
|
+
}
|
|
90
|
+
|
|
71
91
|
&.selected {
|
|
72
92
|
background-color: @default-button-selected-background-color;
|
|
73
93
|
border-color: @default-button-selected-background-color;
|
|
74
94
|
}
|
|
95
|
+
|
|
96
|
+
&.disabled {
|
|
97
|
+
color: @disabled-inverted-color;
|
|
98
|
+
|
|
99
|
+
&:hover, &.active, &:active, &.selected {
|
|
100
|
+
background-color: @default-button-background-color;
|
|
101
|
+
border-color: @default-button-background-color;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
75
104
|
}
|
|
76
105
|
}
|
|
77
106
|
}
|
|
78
107
|
|
|
79
|
-
.context-menu {
|
|
80
|
-
|
|
81
|
-
padding: 0;
|
|
108
|
+
.context-menu > .combo-menu {
|
|
109
|
+
padding: 0;
|
|
82
110
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
& > .menu-item {
|
|
112
|
+
color: @context-menu-item-color;
|
|
113
|
+
padding: @context-menu-item-padding-y @context-menu-item-padding-right @context-menu-item-padding-y @context-menu-item-padding-left;
|
|
114
|
+
flex-grow: 1;
|
|
115
|
+
justify-content: start;
|
|
116
|
+
border-radius: 0;
|
|
117
|
+
|
|
118
|
+
& > .font-icon {
|
|
119
|
+
color: @context-menu-item-icon-color;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.menu-textandicon > .icon {
|
|
123
|
+
margin-right: @context-menu-item-icon-margin-right;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&.menu-icononly:not(.first.last) { // Rule must not be applied if combo menu contains only one item
|
|
127
|
+
flex-grow: 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&.disabled {
|
|
131
|
+
color: @menu-item-disabled-color;
|
|
87
132
|
|
|
88
|
-
|
|
89
|
-
|
|
133
|
+
& > .font-icon {
|
|
134
|
+
color: @menu-item-disabled-color;
|
|
90
135
|
}
|
|
91
136
|
}
|
|
92
137
|
}
|
|
@@ -367,8 +367,9 @@ export default class ContextMenuPopup extends Popup {
|
|
|
367
367
|
|
|
368
368
|
// prevent loosing original parent
|
|
369
369
|
let originalParent = menu.parent;
|
|
370
|
-
|
|
371
|
-
|
|
370
|
+
// Clone menu items but only clone once unless it is for a different context menu (e.g. a context menu of a combo menu inside a context menu)
|
|
371
|
+
// Clone will recursively also clone all child actions.
|
|
372
|
+
if (this.cloneMenuItems && !menu.cloneOf || !this.has(menu)) {
|
|
372
373
|
menu = menu.clone({
|
|
373
374
|
parent: this,
|
|
374
375
|
textPosition: Action.TextPosition.DEFAULT
|