@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.
Files changed (21) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/generic/template/.library +1 -1
  3. package/src/sap/suite/ui/generic/template/AnalyticalListPage/controller/VisualFilterDialogController.js +1 -1
  4. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  5. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  6. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  7. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  8. package/src/sap/suite/ui/generic/template/ObjectPage/templateSpecificPreparationHelper.js +90 -42
  9. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  10. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  11. package/src/sap/suite/ui/generic/template/designtime/ObjectPage.designtime.js +6 -0
  12. package/src/sap/suite/ui/generic/template/fragments/SmartControlContextMenu.fragment.xml +6 -0
  13. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  14. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +31 -1
  15. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +6 -1
  16. package/src/sap/suite/ui/generic/template/lib/ComponentUtils.js +6 -1
  17. package/src/sap/suite/ui/generic/template/lib/ContextMenuHandler.js +23 -67
  18. package/src/sap/suite/ui/generic/template/lib/FlexibleColumnLayoutHandler.js +2 -1
  19. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +99 -5
  20. package/src/sap/suite/ui/generic/template/library.js +1 -1
  21. package/src/sap/suite/ui/generic/template/listTemplates/fragments/DetailSmartTable.fragment.xml +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapui5/sap.suite.ui.generic.template",
3
- "version": "1.127.2",
3
+ "version": "1.127.4",
4
4
  "description": "SAPUI5 Library sap.suite.ui.generic.template",
5
5
  "keywords": [
6
6
  "sapui5",
@@ -7,7 +7,7 @@
7
7
 
8
8
  (c) Copyright 2009-2015 SAP SE. All rights reserved
9
9
  </copyright>
10
- <version>1.127.2</version>
10
+ <version>1.127.4</version>
11
11
 
12
12
  <documentation>Library with generic Suite UI templates.</documentation>
13
13
 
@@ -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.getProperty();
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
  },
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.127.2"
11
+ "version": "1.127.4"
12
12
  },
13
13
  "title": "{{TITLE}}",
14
14
  "description": "{{DESCRIPTION}}",
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.127.2"
11
+ "version": "1.127.4"
12
12
  },
13
13
  "title": "Canvas",
14
14
  "description": "Canvas Page",
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.127.2"
11
+ "version": "1.127.4"
12
12
  },
13
13
  "title": "{{TITLE}}",
14
14
  "description": "{{DESCRIPTION}}",
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.127.2"
9
+ "version": "1.127.4"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -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
- if (oPathforRestriction) {
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
- var oUpdateRestrictionSetViaNavRestrictions = AnnotationHelper.handleNavigationRestrictions(oMetaModel, oLeadingEntitySet, oEntitySet, 'Updatable');
373
- if (oUpdateRestrictionSetViaNavRestrictions) {
374
- oUpdatableAnnotation = oUpdateRestrictionSetViaNavRestrictions['Updatable'];
375
- } else {
376
- var oSectionUpdatableRestriction = oEntitySet['Org.OData.Capabilities.V1.UpdateRestrictions'];
377
- oUpdatableAnnotation = oSectionUpdatableRestriction && oSectionUpdatableRestriction['Updatable'];
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
- var sInsertablePath = oInsertableAnnotation ? oInsertableAnnotation.Path : "";
381
- var sUpdatablePath = oUpdatableAnnotation ? oUpdatableAnnotation.Path : "";
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
- if (sInsertablePath || sUpdatablePath) {
384
- return {
385
- insertable: sInsertablePath,
386
- updatable: sUpdatablePath
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 null;
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.
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.127.2"
9
+ "version": "1.127.4"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.127.2"
9
+ "version": "1.127.4"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -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.2
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
- "sap/ui/util/openWindow"
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
- // shortcut for sap.f.LayoutType
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
- * Constructs the app specific route for the target to be opened on new tab. The target route consists of
311
- * 1. Deep path of the context
312
- * 2. URL parameters of the current app specific route.
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
- // Opens the given context in a new tab
339
- function fnOpenContextInNewTab (oContext, oUrlParser, sFLPUrl, oAppComponent) {
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
- fnOpenContextInNewTab(oContext, oUrlParser, sFLPUrl, oAppComponent);
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
- }).catch(function (oError) {
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
- * //TODO: These negative scenarios need to be revisited
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
- if (!bNavigationSupported || bDirectEdit || bOnListNavigationExtensionFound) {
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.getRouteInfoByHash(oShellContext.innerAppRoute);
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.2
3152
+ * @version 1.127.4
3059
3153
  * @since 1.30.0
3060
3154
  * @alias sap.suite.ui.generic.template.lib.NavigationController
3061
3155
  */
@@ -62,7 +62,7 @@ sap.ui.define([
62
62
  interfaces: [],
63
63
  controls: [],
64
64
  elements: [],
65
- version: "1.127.2",
65
+ version: "1.127.4",
66
66
  extensions: {
67
67
  //Configuration used for rule loading of Support Assistant
68
68
  "sap.ui.support": {
@@ -256,7 +256,9 @@
256
256
  </ColumnListItem>
257
257
  </items>
258
258
  <contextMenu>
259
- <core:Fragment fragmentName="sap.suite.ui.generic.template.fragments.SmartControlContextMenu" type="XML"/>
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"/>