@sapui5/sap.suite.ui.generic.template 1.127.2 → 1.127.4
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/package.json +1 -1
- package/src/sap/suite/ui/generic/template/.library +1 -1
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/controller/VisualFilterDialogController.js +1 -1
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ObjectPage/templateSpecificPreparationHelper.js +90 -42
- package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/designtime/ObjectPage.designtime.js +6 -0
- package/src/sap/suite/ui/generic/template/fragments/SmartControlContextMenu.fragment.xml +6 -0
- package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
- package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +31 -1
- package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +6 -1
- package/src/sap/suite/ui/generic/template/lib/ComponentUtils.js +6 -1
- package/src/sap/suite/ui/generic/template/lib/ContextMenuHandler.js +23 -67
- package/src/sap/suite/ui/generic/template/lib/FlexibleColumnLayoutHandler.js +2 -1
- package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +99 -5
- package/src/sap/suite/ui/generic/template/library.js +1 -1
- package/src/sap/suite/ui/generic/template/listTemplates/fragments/DetailSmartTable.fragment.xml +3 -1
package/package.json
CHANGED
|
@@ -424,7 +424,7 @@ sap.ui.define([
|
|
|
424
424
|
oVisualFilterDialogModelClone.setProperty('/filterCompList/' + idx + '/searchVisible', bVisible);
|
|
425
425
|
oVisualFilterDialogModel.setData(oVisualFilterDialogModelClone.getData());
|
|
426
426
|
//update config object when VFConfig model is updated
|
|
427
|
-
this.oConfig = oVisualFilterDialogModel.
|
|
427
|
+
this.oConfig = oVisualFilterDialogModel.getData();
|
|
428
428
|
//to enable Restore button on change of chart type, sort order, measure field and show in filter bar changes
|
|
429
429
|
this.oState.oSmartFilterbar._oVariantManagement.currentVariantSetModified(true);
|
|
430
430
|
},
|
|
@@ -331,62 +331,110 @@ sap.ui.define([
|
|
|
331
331
|
fnSetTargetEntity(oEntitySet);
|
|
332
332
|
|
|
333
333
|
var bToolbarButtonVisible = fnGetTableToolbarButtonVisibility(oSettings, oEntitySet, oResult.type);
|
|
334
|
-
var oPathforRestriction = fnGetRestrictionForPasteButton(oEntitySet);
|
|
335
334
|
/* Workaround fix for non draft apps with no section settings defined in the manifest. In UI5v1.93, the export to excel button is displayed by default because of a code gap in
|
|
336
335
|
FE which later got fixed with a change related to paste button in UI5v1.96 wherein the export button is not displayed by default. This looks like a regression issue to customers
|
|
337
336
|
for which we have provided this temporary solution which shall get removed soon. */
|
|
338
337
|
oResult.bExportToExcel = (!oComponentUtils.isDraftEnabled() && !oSettings.sections) || bToolbarButtonVisible;
|
|
339
|
-
|
|
340
|
-
var sPathforRestriction = "";
|
|
341
|
-
if (oPathforRestriction.insertable) {
|
|
342
|
-
sPathforRestriction = "${" + oPathforRestriction.insertable + "}";
|
|
343
|
-
}
|
|
344
|
-
if (oPathforRestriction.updatable) {
|
|
345
|
-
sPathforRestriction = sPathforRestriction ? sPathforRestriction + " || ${" + oPathforRestriction.updatable + "}" : "${" + oPathforRestriction.updatable + "}";
|
|
346
|
-
}
|
|
347
|
-
sPathforRestriction = sPathforRestriction && "(" + sPathforRestriction + ")";
|
|
348
|
-
oResult.vShowPasteButton = bToolbarButtonVisible ? "{= ${ui>/editable} && " + sPathforRestriction + "}" : false;
|
|
349
|
-
} else {
|
|
350
|
-
oResult.vShowPasteButton = bToolbarButtonVisible ? "{ui>/editable}" : false;
|
|
351
|
-
}
|
|
352
|
-
|
|
338
|
+
oResult.vShowPasteButton = fnGetPasteButtonVisibility(oEntitySet);
|
|
353
339
|
oResult.commandExecution = fnGetTableLevelStandardActions();
|
|
354
340
|
oResult.persistencyKeyState = fnGetPersistencyKeyState(oSettings.tableSettings);
|
|
355
341
|
|
|
356
342
|
return oResult;
|
|
357
343
|
}
|
|
358
|
-
|
|
359
|
-
// fnGetRestrictionForPasteButton return object contains updatable and insertable restriction for the given Entity Set.
|
|
360
|
-
function fnGetRestrictionForPasteButton(oEntitySet) {
|
|
361
|
-
var oLeadingEntitySet = oMetaModel.getODataEntitySet(sLeadingEntitySet);
|
|
362
|
-
var oInsertableAnnotation, oUpdatableAnnotation;
|
|
363
|
-
|
|
364
|
-
var oInsertRestrictionSetViaNavRestrictions = AnnotationHelper.handleNavigationRestrictions(oMetaModel, oLeadingEntitySet, oEntitySet, 'Insertable');
|
|
365
|
-
if (oInsertRestrictionSetViaNavRestrictions) {
|
|
366
|
-
oInsertableAnnotation = oInsertRestrictionSetViaNavRestrictions['Insertable'];
|
|
367
|
-
} else {
|
|
368
|
-
var oSectionInsertRestriction = oEntitySet['Org.OData.Capabilities.V1.InsertRestrictions'];
|
|
369
|
-
oInsertableAnnotation = oSectionInsertRestriction && oSectionInsertRestriction['Insertable'];
|
|
370
|
-
}
|
|
371
344
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
345
|
+
/**
|
|
346
|
+
* Finds out the paste button visibility. It can be visible when,
|
|
347
|
+
* 1. The object page is editable AND
|
|
348
|
+
* 2. Either the table should be insertable OR updatable
|
|
349
|
+
* @param {object} oEntitySet Table's entity set info
|
|
350
|
+
* @returns {boolean|string} Returns a boolean value for visibility or binding expression
|
|
351
|
+
*/
|
|
352
|
+
function fnGetPasteButtonVisibility (oEntitySet) {
|
|
353
|
+
var vInsertRestriction = fnGetRestrictionForPaste(oEntitySet, "Insertable");
|
|
354
|
+
var vUpdateRestriction = fnGetRestrictionForPaste(oEntitySet, "Updatable");
|
|
355
|
+
|
|
356
|
+
// If both the restrictions are boolean and falsy, paste button should be hidden.
|
|
357
|
+
// Hence, immediately return false
|
|
358
|
+
if (!(vInsertRestriction || vUpdateRestriction)) {
|
|
359
|
+
return false;
|
|
378
360
|
}
|
|
379
361
|
|
|
380
|
-
|
|
381
|
-
|
|
362
|
+
// As we are going to combine insertable and updatable by OR condition, if there's any boolean value "true" found, it will be always evaluated to true
|
|
363
|
+
// Hence, no need to include them in the binding and just return the binding expression "ui>/editable"
|
|
364
|
+
var bAnyBooleanTrue = [vInsertRestriction, vUpdateRestriction].some(function (vRestriction) {
|
|
365
|
+
return vRestriction === true;
|
|
366
|
+
});
|
|
367
|
+
if (bAnyBooleanTrue) {
|
|
368
|
+
return "{ui>/editable}";
|
|
369
|
+
}
|
|
382
370
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
371
|
+
// Now the remaining cases are either
|
|
372
|
+
// 1. Both are path expressions or
|
|
373
|
+
// 2. One path expression and one boolean value "false"
|
|
374
|
+
//
|
|
375
|
+
// While building OR expression, "${expression} || false" will always be evaluated to "${expression}"
|
|
376
|
+
// Hence, we can omit the "false" values and build binding expression with "Path" values
|
|
377
|
+
var sPathRestriction = [vInsertRestriction, vUpdateRestriction].filter(function (vRestriction) {
|
|
378
|
+
return (typeof vRestriction === "string");
|
|
379
|
+
}).map(function (sPath) {
|
|
380
|
+
return "${" + sPath + "}";
|
|
381
|
+
}).join(" || ");
|
|
382
|
+
|
|
383
|
+
// Add "editable" with "path" expression
|
|
384
|
+
return "{= ${ui>/editable} && ( " + sPathRestriction + " )}";
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Checks the navigation restriction on the parent entity set or current entity set
|
|
389
|
+
* and returns the boolean value or path for the restriction
|
|
390
|
+
*
|
|
391
|
+
* 1. If NavigationRestriction is available on parent entity set
|
|
392
|
+
* a. Restricted by boolean value - returns the boolean value
|
|
393
|
+
* b. Restricted by path - Checks the data type of path and returns it
|
|
394
|
+
*
|
|
395
|
+
* 2. If Restriction is available on table's entity set
|
|
396
|
+
* a. Restricted by boolean value - returns the boolean value
|
|
397
|
+
* b. Restricted by path - ignores it
|
|
398
|
+
* Important: Reason for ignoring the path. As path value refers to the individual records on the table, it can't control the whole table's paste functionality
|
|
399
|
+
*
|
|
400
|
+
* 3. If no restriction available, returns true
|
|
401
|
+
*
|
|
402
|
+
* @param {object} oEntitySet Table's entity set info
|
|
403
|
+
* @param {string} sRestrictionType "Insertable" or "Updatable"
|
|
404
|
+
* @returns {boolean|string} Boolean value or path for the restriction
|
|
405
|
+
*/
|
|
406
|
+
function fnGetRestrictionForPaste (oEntitySet, sRestrictionType) {
|
|
407
|
+
var mAnnotation = {
|
|
408
|
+
Insertable: "Org.OData.Capabilities.V1.InsertRestrictions",
|
|
409
|
+
Updatable: "Org.OData.Capabilities.V1.UpdateRestrictions"
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Navigation restriction on parent entity set
|
|
413
|
+
var oLeadingEntitySet = oMetaModel.getODataEntitySet(sLeadingEntitySet);
|
|
414
|
+
var oNavRestriction = AnnotationHelper.handleNavigationRestrictions(oMetaModel, oLeadingEntitySet, oEntitySet, sRestrictionType);
|
|
415
|
+
var oNavRestrictionAnnotation = oNavRestriction && oNavRestriction[sRestrictionType];
|
|
416
|
+
|
|
417
|
+
// Restriction on table entity set
|
|
418
|
+
var oSectionRestriction = oEntitySet[mAnnotation[sRestrictionType]];
|
|
419
|
+
var oSectionRestrictionAnnotation = oSectionRestriction && oSectionRestriction[sRestrictionType];
|
|
420
|
+
|
|
421
|
+
// Check for navigation restriction
|
|
422
|
+
if (oNavRestrictionAnnotation) {
|
|
423
|
+
if (oNavRestrictionAnnotation.Bool) {
|
|
424
|
+
return oNavRestrictionAnnotation.Bool !== "false";
|
|
425
|
+
} else if (oNavRestrictionAnnotation.Path) {
|
|
426
|
+
var bIsBooleanPath = AnnotationHelper._isPropertyPathBoolean(oMetaModel, oLeadingEntitySet.entityType, oNavRestrictionAnnotation.Path);
|
|
427
|
+
if (!bIsBooleanPath) {
|
|
428
|
+
oLogger.error("Service Broken: Restrictions annotations for entity type " + sLeadingEntitySet + " for section '" + sRestrictionType + "' are invalid.");
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
return oNavRestrictionAnnotation.Path;
|
|
432
|
+
}
|
|
433
|
+
} else if (oSectionRestrictionAnnotation && oSectionRestrictionAnnotation.Bool) {
|
|
434
|
+
return oSectionRestrictionAnnotation.Bool !== "false";
|
|
388
435
|
}
|
|
389
|
-
return
|
|
436
|
+
// If no annotation found, return true
|
|
437
|
+
return true;
|
|
390
438
|
}
|
|
391
439
|
|
|
392
440
|
// used in the process of determining the visibility of export to excel and paste button depending on certain restrictions/conditions.
|
|
@@ -141,6 +141,12 @@ sap.ui.define(["sap/suite/ui/generic/template/designtime/utils/designtimeHelper"
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
|
+
"sap.ui.layout.VerticalLayout": {
|
|
145
|
+
actions: ["remove"]
|
|
146
|
+
},
|
|
147
|
+
"sap.ui.layout.HorizontalLayout": {
|
|
148
|
+
actions: ["remove"]
|
|
149
|
+
},
|
|
144
150
|
"sap.uxap.ObjectPageHeaderActionButton": {
|
|
145
151
|
actions: ["remove", "reveal"]
|
|
146
152
|
},
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
press="._templateEventHandlers.onContextMenu($event, '{smartControlId>id}')"/>
|
|
13
13
|
</items>
|
|
14
14
|
</MenuItem>
|
|
15
|
+
<template:if test="{parts: [{path: 'listEntitySet>name'}, {path: 'parameter>/settings/subPages/'}, {path: 'facet>Target/AnnotationPath'}], formatter: 'AH.getDisplayNavigationIntent'}">
|
|
16
|
+
<customData>
|
|
17
|
+
<core:CustomData key="CrossNavigation"
|
|
18
|
+
value="{parts: [{path: 'listEntitySet>name'}, {path: 'parameter>/settings/subPages/'}, {path: 'facet>Target/AnnotationPath'}], formatter: 'AH.getDisplayNavigationIntent'}" />
|
|
19
|
+
</customData>
|
|
20
|
+
</template:if>
|
|
15
21
|
</Menu>
|
|
16
22
|
</template:with>
|
|
17
23
|
</core:FragmentDefinition>
|
|
@@ -943,7 +943,7 @@ sap.ui.define([
|
|
|
943
943
|
* @public
|
|
944
944
|
* @extends sap.ui.core.UIComponent
|
|
945
945
|
* @author SAP SE
|
|
946
|
-
* @version 1.127.
|
|
946
|
+
* @version 1.127.4
|
|
947
947
|
* @name sap.suite.ui.generic.template.lib.AppComponent
|
|
948
948
|
*/
|
|
949
949
|
var oAppComponent = UIComponent.extend("sap.suite.ui.generic.template.lib.AppComponent", {
|
|
@@ -2696,6 +2696,35 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
2696
2696
|
oComponentUtils.getBusyHelper().setBusy(oAIFilterQueryHandlerPromise);
|
|
2697
2697
|
}
|
|
2698
2698
|
|
|
2699
|
+
/**
|
|
2700
|
+
* Performs intent based navigation and opens the given line item context in a new tab.
|
|
2701
|
+
*
|
|
2702
|
+
* @param {object} oOutbound The target outbound intent (contains semantic object and action)
|
|
2703
|
+
* @param {sap.ui.model.Context} oLineItemContext The line item context to be opened in new tab
|
|
2704
|
+
* @param {sap.ui.comp.smartfilterbar.SmartFilterBar} oSmartFilterBar The filter bar
|
|
2705
|
+
* @param {Function} fnHandleError The error handling function
|
|
2706
|
+
*/
|
|
2707
|
+
function fnNavigateIntentOnNewTab(oOutbound, oLineItemContext, oSmartFilterBar, fnHandleError) {
|
|
2708
|
+
var sSelectionVariant,
|
|
2709
|
+
oSelectionVariant,
|
|
2710
|
+
sNavMode = "explace"; // "explace" is the navigation mode for opening in new tab
|
|
2711
|
+
// Get selection variant from filter bar
|
|
2712
|
+
if (oSmartFilterBar) {
|
|
2713
|
+
sSelectionVariant = oSmartFilterBar.getUiState().getSelectionVariant();
|
|
2714
|
+
if (typeof sSelectionVariant !== "string"){
|
|
2715
|
+
sSelectionVariant = JSON.stringify(sSelectionVariant);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
// Build the selection variant from line item context, page context and the selection variant of filter bar
|
|
2719
|
+
oSelectionVariant = fnBuildSelectionVariantForNavigation(oOutbound, [oLineItemContext], oController.getView().getBindingContext(), sSelectionVariant);
|
|
2720
|
+
var oObjectInfo = {
|
|
2721
|
+
semanticObject: oOutbound.semanticObject,
|
|
2722
|
+
action: oOutbound.action
|
|
2723
|
+
};
|
|
2724
|
+
oController.adaptNavigationParameterExtension(oSelectionVariant, oObjectInfo);
|
|
2725
|
+
oServices.oApplication.getNavigationHandler().navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, fnHandleError, null, sNavMode);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2699
2728
|
/* eslint-disable */
|
|
2700
2729
|
var fnBuildSelectionVariantForNavigation = testableHelper.testable(fnBuildSelectionVariantForNavigation, "fnBuildSelectionVariantForNavigation");
|
|
2701
2730
|
var fnEvaluateParameters = testableHelper.testable(fnEvaluateParameters, "fnEvaluateParameters");
|
|
@@ -2747,7 +2776,8 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
2747
2776
|
onSmartFieldModeToggled: onSmartFieldModeToggled,
|
|
2748
2777
|
onRenderTeamsContactCollabOptions: fnRenderTeamsContactCollabOptions,
|
|
2749
2778
|
hideTableCells: fnHideTableCells,
|
|
2750
|
-
onEasyFilterChange: fnHandleEasyFilterChange
|
|
2779
|
+
onEasyFilterChange: fnHandleEasyFilterChange,
|
|
2780
|
+
navigateIntentOnNewTab: fnNavigateIntentOnNewTab
|
|
2751
2781
|
};
|
|
2752
2782
|
}
|
|
2753
2783
|
|
|
@@ -728,6 +728,10 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
728
728
|
oComponentUtils.navigateAccordingToContext(oContext, iDisplayMode, bReplace);
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
+
function fnOpenContextInNewTabFromListItem (oContext) {
|
|
732
|
+
oComponentUtils.openContextInNewTab(oContext);
|
|
733
|
+
}
|
|
734
|
+
|
|
731
735
|
// Fix for BCP 1770053414 where error message is displayed instead of error code
|
|
732
736
|
function fnHandleError(oError) {
|
|
733
737
|
if (oError instanceof sap.fe.navigation.NavError) {
|
|
@@ -1992,7 +1996,8 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
1992
1996
|
getControlStateWrapperById: oControlStateWrapperFactory.getControlStateWrapperById,
|
|
1993
1997
|
handleError: fnHandleError,
|
|
1994
1998
|
transformTechnicalPropsOnExportedFile: fnTransformTechnicalPropsOnExportedFile,
|
|
1995
|
-
includeEntitySetParametersToExportedFile: fnIncludeEntitySetParametersToExportedFile
|
|
1999
|
+
includeEntitySetParametersToExportedFile: fnIncludeEntitySetParametersToExportedFile,
|
|
2000
|
+
openContextInNewTabFromListItem: fnOpenContextInNewTabFromListItem
|
|
1996
2001
|
};
|
|
1997
2002
|
}
|
|
1998
2003
|
|
|
@@ -1075,6 +1075,10 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
1075
1075
|
var oTemplatePrivateGlobalModel = getTemplatePrivateGlobalModel();
|
|
1076
1076
|
return oTemplatePrivateGlobalModel.getProperty("/generic/ui5VersionInfo");
|
|
1077
1077
|
}
|
|
1078
|
+
|
|
1079
|
+
function fnOpenContextInNewTab (oNavigationContext) {
|
|
1080
|
+
oComponentRegistryEntry.oTemplateContract.oNavigationControllerProxy.openContextInNewTab(oTreeNode, oNavigationContext);
|
|
1081
|
+
}
|
|
1078
1082
|
|
|
1079
1083
|
return {
|
|
1080
1084
|
getBusyHelper: function() {
|
|
@@ -1156,7 +1160,8 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
1156
1160
|
getToolbarDataFieldForIBNCommandDetails: oCommandComponentUtils.getToolbarDataFieldForIBNCommandDetails,
|
|
1157
1161
|
isStateHandlingSuspended: fnIsStateHandlingSuspended,
|
|
1158
1162
|
adjustCopyButtonSettings: fnAdjustCopyButtonSettings,
|
|
1159
|
-
getUI5VersionInfo: fnGetUI5VersionInfo
|
|
1163
|
+
getUI5VersionInfo: fnGetUI5VersionInfo,
|
|
1164
|
+
openContextInNewTab: fnOpenContextInNewTab
|
|
1160
1165
|
};
|
|
1161
1166
|
}
|
|
1162
1167
|
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
sap.ui.define([
|
|
2
2
|
"sap/base/util/extend",
|
|
3
3
|
"sap/base/util/ObjectPath",
|
|
4
|
-
"sap/f/library",
|
|
5
4
|
"sap/m/MessageBox",
|
|
6
5
|
"sap/suite/ui/generic/template/genericUtilities/controlHelper",
|
|
7
6
|
"sap/suite/ui/generic/template/genericUtilities/FeLogger",
|
|
8
7
|
"sap/ui/base/Object",
|
|
9
|
-
"sap/ui/base/Event"
|
|
10
|
-
|
|
11
|
-
], function (extend, ObjectPath, fioriLibrary, MessageBox, controlHelper, FeLogger, BaseObject, Event, openWindow) {
|
|
8
|
+
"sap/ui/base/Event"
|
|
9
|
+
], function (extend, ObjectPath, MessageBox, controlHelper, FeLogger, BaseObject, Event) {
|
|
12
10
|
"use strict";
|
|
13
11
|
|
|
14
12
|
/* This class provides generic functionality for handling of the context menu for one smart control (oSourceControl).
|
|
@@ -16,9 +14,7 @@ sap.ui.define([
|
|
|
16
14
|
* oConfiguration is an object which contains logic which is specific to the floorplan using this functionality.
|
|
17
15
|
*/
|
|
18
16
|
var oLogger = new FeLogger("lib.ContextMenuHandler").getLogger();
|
|
19
|
-
|
|
20
|
-
var LayoutType = fioriLibrary.LayoutType;
|
|
21
|
-
|
|
17
|
+
|
|
22
18
|
// Constants
|
|
23
19
|
var MAX_RECORDS_OPEN_IN_NEW_TAB = 10;
|
|
24
20
|
var aToolbarContentsToBeOmitted = ["btnPersonalisation", "btnExcelExport"];
|
|
@@ -65,7 +61,9 @@ sap.ui.define([
|
|
|
65
61
|
var bNavigationSupported = oComponentUtils.canNavigateToSubEntitySet(oSourceControl.getEntitySet());
|
|
66
62
|
var mHandlers; // maps keys of context menu entries to handler functions for the corresponding entry
|
|
67
63
|
var iCreatedMenuItemsCounter = 0; // increased whenever a new MenuItem is being created In fnAddMenuItem). Used to generate a key for mHandlers.
|
|
68
|
-
|
|
64
|
+
// Store the outbound navigation target
|
|
65
|
+
var sOutboundNavigationTarget = oSourceControl.getTable().getContextMenu().data("CrossNavigation");
|
|
66
|
+
var oOutbound = sOutboundNavigationTarget && fnGetOutboundInfoFromManifest(sOutboundNavigationTarget);
|
|
69
67
|
/**
|
|
70
68
|
* The method does the following
|
|
71
69
|
* - Adds an entry (menu item) to the context menu.
|
|
@@ -306,51 +304,14 @@ sap.ui.define([
|
|
|
306
304
|
return !bIsEmptyRow;
|
|
307
305
|
}
|
|
308
306
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
*
|
|
314
|
-
* Note: All the URL parameters from source are retained in the target except the "FCLLayout".
|
|
315
|
-
* The target "FCLLayout" is calculated by the below logic:
|
|
316
|
-
*
|
|
317
|
-
* If the app supports FCL.
|
|
318
|
-
* - If the current page is LR (iViewLevel = 0), the target layout is "MidColumnFullScreen"
|
|
319
|
-
* - If the current page is OP (iViewLevel > 0), the target layout is "EndColumnFullScreen"
|
|
320
|
-
*
|
|
321
|
-
* @returns {string} target path
|
|
322
|
-
*/
|
|
323
|
-
function fnConstructTargetAppSpecificRoute (oContext, oAppComponent, sSrcAppSpecificRoute) {
|
|
324
|
-
var sUrlParams = sSrcAppSpecificRoute.includes("?") ? sSrcAppSpecificRoute.substring(sSrcAppSpecificRoute.indexOf("?")) : "";
|
|
325
|
-
var oUrlParams = new URLSearchParams(sUrlParams);
|
|
326
|
-
var sDeepPath = oContext.getDeepPath();
|
|
327
|
-
var sTargetPathPrefix = sDeepPath.startsWith("/") ? "&" : "&/";
|
|
328
|
-
// If the app supports FCL, the object page should be opened in full screen mode
|
|
329
|
-
if (oAppComponent.getFlexibleColumnLayout()) {
|
|
330
|
-
var iViewLevel = oComponentUtils.getViewLevel();
|
|
331
|
-
var sTargetFCLLayout = iViewLevel === 0 ? LayoutType.MidColumnFullScreen : LayoutType.EndColumnFullScreen;
|
|
332
|
-
// Update "FCLLayout"
|
|
333
|
-
oUrlParams.set("FCLLayout", sTargetFCLLayout);
|
|
334
|
-
}
|
|
335
|
-
return sTargetPathPrefix + sDeepPath + "?" + oUrlParams.toString();
|
|
307
|
+
// Fetches the outbound target from manifest
|
|
308
|
+
function fnGetOutboundInfoFromManifest (sOutboundNavigationTarget) {
|
|
309
|
+
var oManifestEntry = oController.getOwnerComponent().getAppComponent().getManifestEntry("sap.app");
|
|
310
|
+
return oManifestEntry.crossNavigation.outbounds[sOutboundNavigationTarget];
|
|
336
311
|
}
|
|
337
312
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
// Construct URL object from FLP URL
|
|
341
|
-
var oFLPUrl = new URL(sFLPUrl);
|
|
342
|
-
// Get the hash from URL object
|
|
343
|
-
var sHash = oFLPUrl.hash;
|
|
344
|
-
// Parse the hash and update "appSpecificRoute" with the calculated target path.
|
|
345
|
-
// Then, reconstruct the hash with updated value.
|
|
346
|
-
var oHash = oUrlParser.parseShellHash(sHash);
|
|
347
|
-
oHash.appSpecificRoute = fnConstructTargetAppSpecificRoute(oContext, oAppComponent, oHash.appSpecificRoute);
|
|
348
|
-
sHash = oUrlParser.constructShellHash(oHash);
|
|
349
|
-
// Update the hash on the FLP URL and reconstruct the URL
|
|
350
|
-
oFLPUrl.hash = sHash;
|
|
351
|
-
var sTargetUrl = oFLPUrl.toString();
|
|
352
|
-
//Open the new window with the target URL
|
|
353
|
-
openWindow(sTargetUrl);
|
|
313
|
+
function fnCrossAppNavErrorHandler(oContext, oError) {
|
|
314
|
+
oLogger.error("Error while opening the context " + oContext.getPath() + "in new tab: " + oError);
|
|
354
315
|
}
|
|
355
316
|
|
|
356
317
|
/**
|
|
@@ -366,23 +327,17 @@ sap.ui.define([
|
|
|
366
327
|
return;
|
|
367
328
|
}
|
|
368
329
|
|
|
369
|
-
var oAppComponent = oController.getOwnerComponent().getAppComponent();
|
|
370
|
-
var UShellContainer = sap.ui.require("sap/ushell/Container");
|
|
371
|
-
var oUrlParsingPromise = UShellContainer.getServiceAsync("URLParsing");
|
|
372
|
-
var oFLPUrlPromise = UShellContainer.getFLPUrlAsync(true);
|
|
373
|
-
// If the table has any pending changes, synchronize the draft before navigation.
|
|
374
330
|
var oSynchronizeDraftPromise = oSourceControl.getModel().hasPendingChanges() ? oTemplateUtils.oServices.oApplicationController.synchronizeDraftAsync() : Promise.resolve();
|
|
375
|
-
|
|
376
|
-
Promise.all([oUrlParsingPromise, oFLPUrlPromise, oSynchronizeDraftPromise]).then(function (aResults) {
|
|
377
|
-
var oUrlParser = aResults[0];
|
|
378
|
-
var sFLPUrl = aResults[1];
|
|
379
|
-
|
|
331
|
+
oSynchronizeDraftPromise.then(function () {
|
|
380
332
|
aNavigableContexts.forEach(function (oContext) {
|
|
381
|
-
|
|
333
|
+
if (oOutbound) {
|
|
334
|
+
var fnHandleError = fnCrossAppNavErrorHandler.bind(null, oContext);
|
|
335
|
+
oTemplateUtils.oCommonEventHandlers.navigateIntentOnNewTab(oOutbound, oContext, oState.oSmartFilterbar, fnHandleError);
|
|
336
|
+
} else {
|
|
337
|
+
oTemplateUtils.oCommonUtils.openContextInNewTabFromListItem(oContext);
|
|
338
|
+
}
|
|
382
339
|
});
|
|
383
|
-
})
|
|
384
|
-
oLogger.error("Error while opening in new tab", oError);
|
|
385
|
-
});
|
|
340
|
+
});
|
|
386
341
|
}
|
|
387
342
|
|
|
388
343
|
/**
|
|
@@ -393,7 +348,7 @@ sap.ui.define([
|
|
|
393
348
|
* a. Navigation is not supported by the table
|
|
394
349
|
* b. Direct edit flow (when the edit icon is pressed on row, the object is opened with draft record) is configured.
|
|
395
350
|
* c. The controller is configured with onListNavigationExtension (i.e custom navigation logic written by app).
|
|
396
|
-
*
|
|
351
|
+
* d. If ushell container is unavailable
|
|
397
352
|
*
|
|
398
353
|
* @param {sap.suite.ui.generic.template.lib.ContextMenuHandler.FocusInfo} oFocusInfo
|
|
399
354
|
* @returns {Promise<Function|undefined>} Promise which resolves the handler method
|
|
@@ -405,7 +360,8 @@ sap.ui.define([
|
|
|
405
360
|
|
|
406
361
|
var bDirectEdit = oTemplateUtils.oServices.oApplication.getEditFlowOfRoot() === "direct";
|
|
407
362
|
var bOnListNavigationExtensionFound = oController.hasOwnProperty("onListNavigationExtension");
|
|
408
|
-
|
|
363
|
+
var UshellContainer = sap.ui.require("sap/ushell/Container");
|
|
364
|
+
if (!bNavigationSupported || bDirectEdit || bOnListNavigationExtensionFound || !UshellContainer) {
|
|
409
365
|
return;
|
|
410
366
|
}
|
|
411
367
|
|
|
@@ -705,7 +705,8 @@ sap.ui.define(["sap/ui/base/Object", "sap/f/FlexibleColumnLayoutSemanticHelper",
|
|
|
705
705
|
isListAndFirstEntryLoadedOnStartup: isListAndFirstEntryLoadedOnStartup,
|
|
706
706
|
setStoredTargetLayoutToFullscreen: setStoredTargetLayoutToFullscreen,
|
|
707
707
|
adaptAppStatesForExternalNavigation: fnAdaptAppStatesForExternalNavigation,
|
|
708
|
-
willBeOpenedInFullscreen: fnWillBeOpenedInFullscreen
|
|
708
|
+
willBeOpenedInFullscreen: fnWillBeOpenedInFullscreen,
|
|
709
|
+
getFullscreenLayout: getFullscreenLayout
|
|
709
710
|
};
|
|
710
711
|
}
|
|
711
712
|
|
|
@@ -77,9 +77,10 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
77
77
|
"sap/suite/ui/generic/template/lib/navigation/startupParameterHelper",
|
|
78
78
|
"sap/suite/ui/generic/template/lib/TemplateComponent",
|
|
79
79
|
"sap/base/strings/whitespaceReplacer",
|
|
80
|
-
"sap/m/IllustratedMessageType"
|
|
80
|
+
"sap/m/IllustratedMessageType",
|
|
81
|
+
"sap/ui/util/openWindow"
|
|
81
82
|
], function(BaseObject, extend, isEmptyObject, HashChanger, History, coreLibrary, controlHelper, FeLogger, jsonHelper, oDataModelHelper, ProcessObserver, Queue, testableHelper, CRUDHelper, MessageUtils, routingHelper, startupParameterHelper,
|
|
82
|
-
TemplateComponent, whitespaceReplacer, IllustratedMessageType) {
|
|
83
|
+
TemplateComponent, whitespaceReplacer, IllustratedMessageType, openWindow) {
|
|
83
84
|
"use strict";
|
|
84
85
|
var sClassName = "lib.navigation.NavigationController";
|
|
85
86
|
var oLogger = new FeLogger(sClassName).getLogger();
|
|
@@ -1674,6 +1675,67 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
1674
1675
|
oTemplateContract.oBusyHelper.setBusy(oRet, undefined, undefined, oTargetIdentityInfo.willShowPlaceholder);
|
|
1675
1676
|
return oRet;
|
|
1676
1677
|
}
|
|
1678
|
+
|
|
1679
|
+
// Opens the context in new tab
|
|
1680
|
+
function fnOpenContextInNewTab(oSourceNode, oNavigationContext) {
|
|
1681
|
+
var oTargetIdentityInfo = getTargetIdentityInfoForContext({ treeNode: oSourceNode }, oNavigationContext, true, false);
|
|
1682
|
+
var oTargetIdentityPromise = oTargetIdentityInfo.promise;
|
|
1683
|
+
return oTargetIdentityPromise.then(function(oTargetIdentity){
|
|
1684
|
+
// Construct the query params
|
|
1685
|
+
var mQueryParameters = {};
|
|
1686
|
+
// In case FCL layout is supported by app, the target context should be opened in full screen mode.
|
|
1687
|
+
// So, calculate the full screen layout type and add it as a query param.
|
|
1688
|
+
var sFCLLayout = oTemplateContract.oFlexibleColumnLayoutHandler && oTemplateContract.oFlexibleColumnLayoutHandler.getFullscreenLayout(oTargetIdentity.treeNode.fCLLevel);
|
|
1689
|
+
if (sFCLLayout) {
|
|
1690
|
+
mQueryParameters["FCLLayout"] = sFCLLayout;
|
|
1691
|
+
}
|
|
1692
|
+
// Get the route information from target identity
|
|
1693
|
+
var oRouterInput = fnGetRouterInput(oTargetIdentity.treeNode, oTargetIdentity.keys, mQueryParameters);
|
|
1694
|
+
// Construct the app specific route URL from route name and parameters
|
|
1695
|
+
var sTargetAppSpecificRoute = oNavigationControllerProxy.oRouter.getURL(oRouterInput.route, oRouterInput.parameters);
|
|
1696
|
+
// Add the prefix
|
|
1697
|
+
var sRoutePrefix = sTargetAppSpecificRoute.startsWith("/") ? "&" : "&/";
|
|
1698
|
+
sTargetAppSpecificRoute = sRoutePrefix + sTargetAppSpecificRoute;
|
|
1699
|
+
// Construct the fully qualified URL updated with the target app route
|
|
1700
|
+
return fnConstructUrlFromRoute(sTargetAppSpecificRoute);
|
|
1701
|
+
}).then(function (sTargetUrl) {
|
|
1702
|
+
// Open the URL in new tab/window
|
|
1703
|
+
openWindow(sTargetUrl);
|
|
1704
|
+
}).catch(function (oError) {
|
|
1705
|
+
oLogger.error("Error while opening the context '" + oNavigationContext.getPath() + "' in a new tab: " + oError);
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// Constructs the fully qualified URL with the given app specific route.
|
|
1710
|
+
function fnConstructUrlFromRoute(sTargetAppSpecificRoute) {
|
|
1711
|
+
var UShellContainer = sap.ui.require("sap/ushell/Container");
|
|
1712
|
+
|
|
1713
|
+
if (!UShellContainer) {
|
|
1714
|
+
return Promise.reject("Unable to proceed as 'sap/ushell/Container' is not found!");
|
|
1715
|
+
}
|
|
1716
|
+
//Encode the route
|
|
1717
|
+
sTargetAppSpecificRoute = encodeURI(sTargetAppSpecificRoute);
|
|
1718
|
+
|
|
1719
|
+
var oUrlParsingPromise = UShellContainer.getServiceAsync("URLParsing");
|
|
1720
|
+
var oFLPUrlPromise = UShellContainer.getFLPUrlAsync(true);
|
|
1721
|
+
return Promise.all([oUrlParsingPromise, oFLPUrlPromise]).then(function (aResults) {
|
|
1722
|
+
var oUrlParser = aResults[0];
|
|
1723
|
+
var sFLPUrl = aResults[1];
|
|
1724
|
+
|
|
1725
|
+
// Construct URL object from FLP URL
|
|
1726
|
+
var oFLPUrl = new URL(sFLPUrl);
|
|
1727
|
+
// Get the hash from URL object
|
|
1728
|
+
var sHash = oFLPUrl.hash;
|
|
1729
|
+
// Parse the hash and update "appSpecificRoute" with "sTargetAppSpecificRoute"
|
|
1730
|
+
var oHash = oUrlParser.parseShellHash(sHash);
|
|
1731
|
+
oHash.appSpecificRoute = sTargetAppSpecificRoute;
|
|
1732
|
+
// Then, reconstruct the hash with updated value.
|
|
1733
|
+
sHash = oUrlParser.constructShellHash(oHash);
|
|
1734
|
+
// Update the hash on the FLP URL and reconstruct the URL
|
|
1735
|
+
oFLPUrl.hash = sHash;
|
|
1736
|
+
return oFLPUrl.toString();
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1677
1739
|
|
|
1678
1740
|
// This function is called when only tables could be found as focus target for the message oMessage.
|
|
1679
1741
|
// sFullTarget is one of the full targets defined for this message.
|
|
@@ -2834,13 +2896,44 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
2834
2896
|
return true;
|
|
2835
2897
|
}
|
|
2836
2898
|
// Now handle the case of an internal navigation which was not controlled by FE (e.g. browser back, navigation menu, bookmark){
|
|
2837
|
-
var oRouteInfo = oNavigationControllerProxy.oRouter
|
|
2899
|
+
var oRouteInfo = fnGetRouteInfoByHash(oNavigationControllerProxy.oRouter, oShellContext.innerAppRoute);
|
|
2900
|
+
if (!oRouteInfo) {
|
|
2901
|
+
return false;
|
|
2902
|
+
}
|
|
2838
2903
|
var oTargetIdentity = fnRouteConfigToIdentity(oRouteInfo.name, oRouteInfo.arguments);
|
|
2839
2904
|
return oTargetIdentity.treeNode !== oCurrentIdentity.treeNode || oTargetIdentity.keys.some(function(sKey, i){
|
|
2840
2905
|
return sKey !== oCurrentIdentity.keys[i];
|
|
2841
2906
|
});
|
|
2842
2907
|
}
|
|
2843
2908
|
|
|
2909
|
+
/**
|
|
2910
|
+
* From the given app route hash, returns the route information.
|
|
2911
|
+
* Also takes nested app route hash as input
|
|
2912
|
+
* @param {sap.m.routing.Router|sap.f.routing.Router} oRouter
|
|
2913
|
+
* @param {string} sHash
|
|
2914
|
+
* @returns {sap.ui.core.routing.RouteInfo|undefined} An object containing the route <code>name</code> and the <code>arguments</code>
|
|
2915
|
+
* or <code>undefined</code>
|
|
2916
|
+
*/
|
|
2917
|
+
function fnGetRouteInfoByHash(oRouter, sHash) {
|
|
2918
|
+
// If route info found by the input hash, just return it
|
|
2919
|
+
var oRouteInfo = oRouter.getRouteInfoByHash(sHash);
|
|
2920
|
+
if (oRouteInfo) {
|
|
2921
|
+
return oRouteInfo;
|
|
2922
|
+
}
|
|
2923
|
+
// Nested app route: Split the hash by "&/" and get the hash belongs to inner most app route (last index)
|
|
2924
|
+
// Then, check whether the route info found by inner most hash.
|
|
2925
|
+
var aNestedAppRoutes = sHash.split("&/");
|
|
2926
|
+
var sInnerMostHash = aNestedAppRoutes[aNestedAppRoutes.length - 1];
|
|
2927
|
+
oRouteInfo = oRouter.getRouteInfoByHash(sInnerMostHash);
|
|
2928
|
+
if (oRouteInfo) {
|
|
2929
|
+
return oRouteInfo;
|
|
2930
|
+
}
|
|
2931
|
+
// In case the inner most app route is prefixed with app name, just omit the app name and try to get route info from remaining hash.
|
|
2932
|
+
sInnerMostHash = sInnerMostHash.substring(sInnerMostHash.indexOf("/"));
|
|
2933
|
+
oRouteInfo = oRouter.getRouteInfoByHash(sInnerMostHash);
|
|
2934
|
+
return oRouteInfo;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2844
2937
|
function getEditScopeHeaderNode(oTreeNode){
|
|
2845
2938
|
var oMainNode = oTemplateContract.oApplicationProxy.getAncestralNode(oTreeNode, 1);
|
|
2846
2939
|
return oMainNode.isDraft ? oMainNode : oTreeNode;
|
|
@@ -2952,12 +3045,13 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
2952
3045
|
oNavigationControllerProxy.userHasAcceptedDataLoss = fnUserHasAcceptedDataLoss;
|
|
2953
3046
|
oNavigationControllerProxy.unwantedDataLossPossible = fnUnwantedDataLossPossible;
|
|
2954
3047
|
oNavigationControllerProxy.isBackLeavingTheEditScope = isBackLeavingTheEditScope;
|
|
2955
|
-
|
|
3048
|
+
oNavigationControllerProxy.openContextInNewTab = fnOpenContextInNewTab;
|
|
2956
3049
|
// Make private function accessible to unit tests
|
|
2957
3050
|
/* eslint-disable */
|
|
2958
3051
|
var fnCreateTemplateComponent = testableHelper.testable(fnCreateTemplateComponent, "createTemplateComponent");
|
|
2959
3052
|
var getParsedShellHashFromFLP = testableHelper.testable(getParsedShellHashFromFLP, "getParsedShellHashFromFLP");
|
|
2960
3053
|
var fnPreloadComponent = testableHelper.testable(fnPreloadComponent, "preloadComponent");
|
|
3054
|
+
var fnGetRouteInfoByHash = testableHelper.testable(fnGetRouteInfoByHash, "getRouteInfoByHash");
|
|
2961
3055
|
|
|
2962
3056
|
// Note: Function createHostView will be added by routingHelper.
|
|
2963
3057
|
// Allow to mock this by unit tests
|
|
@@ -3055,7 +3149,7 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
3055
3149
|
* @param {sap.suite.ui.generic.template.lib.AppComponent} oAppComponent The AppComponent instance
|
|
3056
3150
|
* @public
|
|
3057
3151
|
* @extends sap.ui.base.Object
|
|
3058
|
-
* @version 1.127.
|
|
3152
|
+
* @version 1.127.4
|
|
3059
3153
|
* @since 1.30.0
|
|
3060
3154
|
* @alias sap.suite.ui.generic.template.lib.NavigationController
|
|
3061
3155
|
*/
|
package/src/sap/suite/ui/generic/template/listTemplates/fragments/DetailSmartTable.fragment.xml
CHANGED
|
@@ -256,7 +256,9 @@
|
|
|
256
256
|
</ColumnListItem>
|
|
257
257
|
</items>
|
|
258
258
|
<contextMenu>
|
|
259
|
-
<
|
|
259
|
+
<template:with path="entitySet>" var="listEntitySet">
|
|
260
|
+
<core:Fragment fragmentName="sap.suite.ui.generic.template.fragments.SmartControlContextMenu" type="XML"/>
|
|
261
|
+
</template:with>
|
|
260
262
|
</contextMenu>
|
|
261
263
|
<dependents>
|
|
262
264
|
<plugins.ContextMenuSetting scope="Selection"/>
|