@sapui5/sap.ushell 1.119.2 → 1.120.0
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/main/js/sap/ushell/.library +3 -3
- package/src/main/js/sap/ushell/Container.js +272 -41
- package/src/main/js/sap/ushell/Fiori20Adapter.js +1 -1
- package/src/main/js/sap/ushell/Fiori20AdapterTest.js +3 -2
- package/src/main/js/sap/ushell/NWBCInterface.js +1 -1
- package/src/main/js/sap/ushell/SessionHandler.js +11 -6
- package/src/main/js/sap/ushell/TechnicalParameters.js +1 -1
- package/src/main/js/sap/ushell/URLTemplateProcessor.js +1 -1
- package/src/main/js/sap/ushell/Ui5NativeServiceFactory.js +1 -1
- package/src/main/js/sap/ushell/Ui5ServiceFactory.js +1 -1
- package/src/main/js/sap/ushell/User.js +26 -35
- package/src/main/js/sap/ushell/_ApplicationType/urlTemplateResolution.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/DefinitionParameterSetBuilder.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/DependencyGraph.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/Functions.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/Resolvers.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/TemplateParameterParser.js +1 -1
- package/src/main/js/sap/ushell/_URLTemplateProcessor/utils.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/ClientSideTargetResolutionAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/CommonDataModelAdapter.js +15 -11
- package/src/main/js/sap/ushell/adapters/cdm/ConfigurationDefaultsAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/ContainerAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/LaunchPageAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/PagesCommonDataModelAdapter.js +16 -11
- package/src/main/js/sap/ushell/adapters/cdm/PersonalizationAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/PersonalizationV2Adapter.js +18 -0
- package/src/main/js/sap/ushell/adapters/cdm/Ui5ComponentLoaderAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/modifyHome.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/readCatalogs.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/readHome.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/_LaunchPage/uri.transform.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/util/AppForInbound.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/util/cdmSiteUtils.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/AdapterBase.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/LaunchPageAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/StaticGroupsAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readApplications.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readCatalogs.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readHome.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readPages.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readUtils.js +1 -1
- package/src/main/js/sap/ushell/adapters/cdm/v3/_LaunchPage/readVisualizations.js +1 -1
- package/src/main/js/sap/ushell/adapters/cep/NavTargetResolutionAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cep/SearchCEPAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/cflp/UserDefaultParameterPersistenceAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/AdapterContainer.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/AppStateAdapter.js +24 -18
- package/src/main/js/sap/ushell/adapters/local/ClientSideTargetResolutionAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/ContainerAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/LaunchPageAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/MenuAdapter.js +4 -7
- package/src/main/js/sap/ushell/adapters/local/NavTargetResolutionAdapter.js +17 -22
- package/src/main/js/sap/ushell/adapters/local/PageBuildingAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/PagePersistenceAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/PersonalizationAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/PersonalizationV2Adapter.js +19 -0
- package/src/main/js/sap/ushell/adapters/local/SearchAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/SearchCEPAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/SupportTicketAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/Ui5ComponentLoaderAdapter.js +1 -1
- package/src/main/js/sap/ushell/adapters/local/UserDefaultParameterPersistenceAdapter.js +11 -7
- package/src/main/js/sap/ushell/adapters/local/UserInfoAdapter.js +8 -8
- package/src/main/js/sap/ushell/api/RTA.js +47 -0
- package/src/main/js/sap/ushell/appRuntime/neo/AppInfoService.js +154 -0
- package/src/main/js/sap/ushell/appRuntime/neo/AppRuntimeNeo.js +20 -0
- package/src/main/js/sap/ushell/appRuntime/neo/ProxyAppUtils.js +71 -0
- package/src/main/js/sap/ushell/appRuntime/ui5/AppRuntime.js +12 -5
- package/src/main/js/sap/ushell/appRuntime/ui5/AppRuntimeContext.js +2 -2
- package/src/main/js/sap/ushell/appRuntime/ui5/services/adapters/Ui5ComponentLoaderAdapter.js +1 -1
- package/src/main/js/sap/ushell/bootstrap/SchedulingAgent.js +2 -2
- package/src/main/js/sap/ushell/bootstrap/_SchedulingAgent/logger.js +1 -1
- package/src/main/js/sap/ushell/bootstrap/_SchedulingAgent/state.js +1 -1
- package/src/main/js/sap/ushell/bootstrap/cdm/cdm-def-dev.js +6 -3
- package/src/main/js/sap/ushell/bootstrap/common/common.configure.ui5datetimeformat.js +1 -1
- package/src/main/js/sap/ushell/bootstrap/common/common.configure.ushell.js +3 -0
- package/src/main/js/sap/ushell/bootstrap/common/common.load.launchpad.js +1 -1
- package/src/main/js/sap/ushell/bootstrap/common/common.util.js +34 -2
- package/src/main/js/sap/ushell/bootstrap/sandbox2.js +7 -2
- package/src/main/js/sap/ushell/components/ComponentKeysHandler.js +1 -1
- package/src/main/js/sap/ushell/components/HomepageManager.js +5 -5
- package/src/main/js/sap/ushell/components/SharedComponentUtils.js +7 -10
- package/src/main/js/sap/ushell/components/_HeaderManager/ShellHeader.controller.js +3 -3
- package/src/main/js/sap/ushell/components/_HomepageManager/DashboardLoadingManager.js +5 -0
- package/src/main/js/sap/ushell/components/_HomepageManager/PagingManager.js +5 -0
- package/src/main/js/sap/ushell/components/_HomepageManager/PersistentPageOperationAdapter.js +5 -0
- package/src/main/js/sap/ushell/components/_HomepageManager/TransientPageOperationAdapter.js +5 -0
- package/src/main/js/sap/ushell/components/appfinder/AppFinderView.js +1 -1
- package/src/main/js/sap/ushell/components/appfinder/CatalogView.js +1 -1
- package/src/main/js/sap/ushell/components/appfinder/EasyAccess.controller.js +3 -3
- package/src/main/js/sap/ushell/components/appfinder/EasyAccessView.js +0 -8
- package/src/main/js/sap/ushell/components/appfinder/HierarchyApps.controller.js +4 -4
- package/src/main/js/sap/ushell/components/appfinder/HierarchyFolders.controller.js +18 -16
- package/src/main/js/sap/ushell/components/appfinder/manifest.json +2 -2
- package/src/main/js/sap/ushell/components/applicationIntegration/AppLifeCycle.js +2 -2
- package/src/main/js/sap/ushell/components/applicationIntegration/application/Application.js +1 -1
- package/src/main/js/sap/ushell/components/applicationIntegration/application/BlueBoxHandler.js +1 -1
- package/src/main/js/sap/ushell/components/applicationIntegration/application/PostMessageAPI.js +2 -2
- package/src/main/js/sap/ushell/components/applicationIntegration/configuration/AppMeta.js +1 -1
- package/src/main/js/sap/ushell/components/applicationIntegration/elements/model.js +1 -1
- package/src/main/js/sap/ushell/components/applicationIntegration/relatedServices/RelatedServices.js +1 -1
- package/src/main/js/sap/ushell/components/applicationIntegration/relatedShellElements/RelatedShellElements.js +1 -1
- package/src/main/js/sap/ushell/components/cards/Card.controller.js +2 -2
- package/src/main/js/sap/ushell/components/container/ApplicationContainer.js +92 -71
- package/src/main/js/sap/ushell/components/contentFinder/Component.js +1 -1
- package/src/main/js/sap/ushell/components/contentFinder/controller/AppSearch.controller.js +1 -1
- package/src/main/js/sap/ushell/components/contentFinder/controller/ContentFinderDialog.controller.js +1 -1
- package/src/main/js/sap/ushell/components/contentFinder/controller/WidgetGallery.controller.js +1 -1
- package/src/main/js/sap/ushell/components/contentFinder/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/contentFinder/model/formatter.js +4 -4
- package/src/main/js/sap/ushell/components/factsheet/Component.js +1 -1
- package/src/main/js/sap/ushell/components/homeApp/error/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/homepage/ActionMode.js +1 -1
- package/src/main/js/sap/ushell/components/homepage/DashboardContent.view.js +1 -1
- package/src/main/js/sap/ushell/components/homepage/DashboardGroupsBox.js +1 -1
- package/src/main/js/sap/ushell/components/homepage/DashboardUIActions.js +1 -1
- package/src/main/js/sap/ushell/components/homepage/manifest.json +2 -2
- package/src/main/js/sap/ushell/components/pages/ActionMode.js +5 -5
- package/src/main/js/sap/ushell/components/pages/Component.js +1 -1
- package/src/main/js/sap/ushell/components/pages/MyHomeImport.js +1 -1
- package/src/main/js/sap/ushell/components/pages/StateManager.js +37 -24
- package/src/main/js/sap/ushell/components/pages/controller/ImportDialog.controller.js +1 -1
- package/src/main/js/sap/ushell/components/pages/controller/PageRuntime.controller.js +1 -1
- package/src/main/js/sap/ushell/components/pages/manifest.json +2 -2
- package/src/main/js/sap/ushell/components/runtimeSwitcher/controller/RuntimeSwitcher.controller.js +7 -4
- package/src/main/js/sap/ushell/components/runtimeSwitcher/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/shell/MenuBar/controller/MenuBar.controller.js +6 -7
- package/src/main/js/sap/ushell/components/shell/MenuBar/manifest.json +2 -2
- package/src/main/js/sap/ushell/components/shell/NavigationBarMenu/controller/NavigationBarMenu.controller.js +39 -13
- package/src/main/js/sap/ushell/components/shell/NavigationBarMenu/manifest.json +3 -3
- package/src/main/js/sap/ushell/components/shell/Notifications/Component.js +5 -5
- package/src/main/js/sap/ushell/components/shell/Notifications/Notifications.controller.js +25 -45
- package/src/main/js/sap/ushell/components/shell/PostLoadingHeaderEnhancement/Component.js +2 -2
- package/src/main/js/sap/ushell/components/shell/ProductSwitch/Component.js +1 -1
- package/src/main/js/sap/ushell/components/shell/Search/ESearch.js +1 -1
- package/src/main/js/sap/ushell/components/shell/Search/manifest.json +2 -2
- package/src/main/js/sap/ushell/components/shell/SearchCEP/Component.js +2 -2
- package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchCEP.controller.js +3 -3
- package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/FrequentActivityProvider.js +1 -1
- package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/RecentSearchProvider.js +1 -1
- package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/SearchProvider.js +1 -1
- package/src/main/js/sap/ushell/components/shell/SearchCEP/SearchProviders/SearchServiceProvider.js +1 -1
- package/src/main/js/sap/ushell/components/shell/Settings/Component.js +4 -4
- package/src/main/js/sap/ushell/components/shell/Settings/ProfilingLoader.js +4 -0
- package/src/main/js/sap/ushell/components/shell/Settings/UserSettings.controller.js +4 -0
- package/src/main/js/sap/ushell/components/shell/Settings/UserSettings.view.xml +4 -3
- package/src/main/js/sap/ushell/components/shell/Settings/homepage/HomepageEntry.js +10 -13
- package/src/main/js/sap/ushell/components/shell/Settings/notifications/NotificationsSetting.controller.js +13 -22
- package/src/main/js/sap/ushell/components/shell/Settings/userAccount/UserAccountSelector.controller.js +2 -2
- package/src/main/js/sap/ushell/components/shell/Settings/userActivities/UserActivitiesSetting.controller.js +11 -14
- package/src/main/js/sap/ushell/components/shell/Settings/userDefaults/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/shell/UserActionsMenu/Component.js +1 -1
- package/src/main/js/sap/ushell/components/shell/UserActionsMenu/UserActionsMenu.controller.js +2 -2
- package/src/main/js/sap/ushell/components/shell/UserImage/Component.js +2 -2
- package/src/main/js/sap/ushell/components/tiles/indicatorTileUtils/smartBusinessUtil.js +4 -6
- package/src/main/js/sap/ushell/components/visualizationOrganizer/Component.js +14 -18
- package/src/main/js/sap/ushell/components/workPageBuilder/Component.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageBuilder.accessibility.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageBuilder.controller.js +16 -12
- package/src/main/js/sap/ushell/components/workPageBuilder/controller/WorkPageHost.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPage.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageButton.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageCell.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageColumn.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageColumnResizer.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/controls/WorkPageRow.js +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/workPageBuilder/view/WorkPageBuilder.view.xml +3 -3
- package/src/main/js/sap/ushell/components/workPageRuntime/Component.js +1 -1
- package/src/main/js/sap/ushell/components/workPageRuntime/controller/WorkPageRuntime.controller.js +1 -2
- package/src/main/js/sap/ushell/components/workPageRuntime/manifest.json +1 -1
- package/src/main/js/sap/ushell/components/workPageRuntime/services/NavigationResolver.js +1 -1
- package/src/main/js/sap/ushell/components/workPageRuntime/services/WorkPage.js +1 -1
- package/src/main/js/sap/ushell/designtime/ApplicationContainer.designtime.js +1 -1
- package/src/main/js/sap/ushell/library.js +1 -1
- package/src/main/js/sap/ushell/navigationMode.js +1 -1
- package/src/main/js/sap/ushell/performance/ShellAnalytics.js +1 -1
- package/src/main/js/sap/ushell/performance/StatisticalRecord.js +1 -1
- package/src/main/js/sap/ushell/plugins/appwarmup/Component.js +1 -1
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/AccessKeysHandler.js +1 -1
- package/src/main/js/sap/ushell/renderer/History.js +84 -0
- package/src/main/js/sap/ushell/renderer/LogonFrameProvider.js +96 -0
- package/src/main/js/sap/ushell/renderer/Renderer.js +2851 -0
- package/src/main/js/sap/ushell/renderer/Shell.controller.js +3155 -0
- package/src/main/js/sap/ushell/{renderers/fiori2/ShellAsync.view.js → renderer/Shell.view.js} +29 -18
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/ShellLayout.js +3 -3
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/allMyApps/AllMyApps.controller.js +4 -4
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/allMyApps/AllMyApps.view.xml +1 -1
- package/src/main/js/sap/ushell/renderer/allMyApps/AllMyAppsKeyboardHandler.js +108 -0
- package/src/main/js/sap/ushell/renderer/allMyApps/AllMyAppsManager.js +453 -0
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources.properties +4 -0
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/Component.js +3 -3
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/controller/CEPSearchApp.controller.js +1 -1
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/controller/SearchApp.controller.js +1 -1
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/manifest.json +2 -2
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/view/CEPSearchApp.view.js +2 -2
- package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/searchComponent/view/SearchApp.view.js +2 -2
- package/src/main/js/sap/ushell/renderers/fiori2/History.js +7 -68
- package/src/main/js/sap/ushell/renderers/fiori2/LogonFrameProvider.js +9 -79
- package/src/main/js/sap/ushell/renderers/fiori2/Renderer.js +101 -1882
- package/src/main/js/sap/ushell/renderers/fiori2/RendererExtensions.js +2 -3
- package/src/main/js/sap/ushell/renderers/fiori2/Shell.controller.js +8 -3130
- package/src/main/js/sap/ushell/renderers/fiori2/Shell.view.js +7 -7
- package/src/main/js/sap/ushell/renderers/fiori2/allMyApps/AllMyAppsKeyboardHandler.js +7 -92
- package/src/main/js/sap/ushell/renderers/fiori2/allMyApps/AllMyAppsManager.js +8 -438
- package/src/main/js/sap/ushell/resources.js +1 -1
- package/src/main/js/sap/ushell/services/AllMyApps.js +16 -7
- package/src/main/js/sap/ushell/services/AppConfiguration.js +12 -0
- package/src/main/js/sap/ushell/services/AppLifeCycle.js +11 -14
- package/src/main/js/sap/ushell/services/AppState.js +12 -8
- package/src/main/js/sap/ushell/services/Bookmark.js +15 -13
- package/src/main/js/sap/ushell/services/BookmarkV2.js +919 -0
- package/src/main/js/sap/ushell/services/ClientSideTargetResolution.js +229 -241
- package/src/main/js/sap/ushell/services/CommonDataModel.js +14 -4
- package/src/main/js/sap/ushell/services/Configuration.js +12 -11
- package/src/main/js/sap/ushell/services/ConfigurationDefaults.js +13 -10
- package/src/main/js/sap/ushell/services/Container.js +1 -1
- package/src/main/js/sap/ushell/services/ContentExtensionAdapterFactory.js +1 -1
- package/src/main/js/sap/ushell/services/CrossApplicationNavigation.js +8 -6
- package/src/main/js/sap/ushell/services/DarkModeSupport.js +16 -10
- package/src/main/js/sap/ushell/services/EndUserFeedback.js +1 -1
- package/src/main/js/sap/ushell/services/Extension/FloatingContainer.js +103 -0
- package/src/main/js/sap/ushell/services/Extension/Footer.js +61 -0
- package/src/main/js/sap/ushell/services/Extension/Header.js +193 -0
- package/src/main/js/sap/ushell/services/Extension/Item.js +195 -0
- package/src/main/js/sap/ushell/services/Extension/SidePane.js +155 -0
- package/src/main/js/sap/ushell/services/Extension/ToolArea.js +152 -0
- package/src/main/js/sap/ushell/services/Extension.js +381 -0
- package/src/main/js/sap/ushell/services/LaunchPage.js +1 -1
- package/src/main/js/sap/ushell/services/Menu.js +48 -59
- package/src/main/js/sap/ushell/services/Message.js +15 -14
- package/src/main/js/sap/ushell/services/MessageBroker.js +12 -12
- package/src/main/js/sap/ushell/services/NavTargetResolution.js +48 -70
- package/src/main/js/sap/ushell/services/Navigation/utils.js +565 -0
- package/src/main/js/sap/ushell/services/Navigation.js +152 -139
- package/src/main/js/sap/ushell/services/NavigationDataProvider.js +11 -8
- package/src/main/js/sap/ushell/services/Notifications.js +118 -1523
- package/src/main/js/sap/ushell/services/NotificationsV2.js +1872 -0
- package/src/main/js/sap/ushell/services/PageBuilding.js +11 -8
- package/src/main/js/sap/ushell/services/PagePersistence.js +11 -8
- package/src/main/js/sap/ushell/services/PageReferencing.js +11 -8
- package/src/main/js/sap/ushell/services/Pages.js +11 -15
- package/src/main/js/sap/ushell/services/Personalization.js +5 -3
- package/src/main/js/sap/ushell/services/PersonalizationV2/ContextContainer.js +410 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/Personalizer.js +109 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/TransientPersonalizer.js +57 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/Variant.js +180 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/VariantSet.js +296 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/VariantSetAdapter.js +125 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/WindowAdapter.js +71 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/WindowAdapterContainer.js +172 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/constants.js +23 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/constants.private.js +18 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2/utils.js +233 -0
- package/src/main/js/sap/ushell/services/PersonalizationV2.js +641 -0
- package/src/main/js/sap/ushell/services/PluginManager.js +47 -55
- package/src/main/js/sap/ushell/services/ReferenceResolver.js +61 -54
- package/src/main/js/sap/ushell/services/Search.js +15 -2
- package/src/main/js/sap/ushell/services/SearchCEP.js +40 -44
- package/src/main/js/sap/ushell/services/SearchableContent.js +9 -9
- package/src/main/js/sap/ushell/services/ShellNavigation.js +14 -13
- package/src/main/js/sap/ushell/services/SmartNavigation.js +1 -1
- package/src/main/js/sap/ushell/services/SpaceContent.js +9 -10
- package/src/main/js/sap/ushell/services/SupportTicket.js +14 -14
- package/src/main/js/sap/ushell/services/UITracer.js +31 -35
- package/src/main/js/sap/ushell/services/URLParsing.js +9 -11
- package/src/main/js/sap/ushell/services/URLShortening.js +1 -1
- package/src/main/js/sap/ushell/services/URLTemplate.js +14 -13
- package/src/main/js/sap/ushell/services/Ui5ComponentLoader.js +29 -26
- package/src/main/js/sap/ushell/services/UsageAnalytics.js +6 -0
- package/src/main/js/sap/ushell/services/UserDefaultParameterPersistence.js +11 -7
- package/src/main/js/sap/ushell/services/UserDefaultParameters.js +20 -26
- package/src/main/js/sap/ushell/services/UserInfo.js +44 -23
- package/src/main/js/sap/ushell/services/UserRecents.js +13 -5
- package/src/main/js/sap/ushell/services/VisualizationDataProvider.js +12 -9
- package/src/main/js/sap/ushell/services/VisualizationInstantiation.js +10 -8
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Formatter.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/InboundIndex.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/InboundProvider.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/PrelaunchOperations.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Search.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/StagedLogger.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/SystemContext.js +1 -1
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/Utils.js +3 -4
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/VirtualInbounds.js +4 -4
- package/src/main/js/sap/ushell/services/_ClientSideTargetResolution/XAppStateProcessing.js +1 -1
- package/src/main/js/sap/ushell/services/_CommonDataModel/SiteConverter.js +1 -1
- package/src/main/js/sap/ushell/services/_ContentExtensionAdapterFactory/ContentExtensionAdapterConfig.js +1 -1
- package/src/main/js/sap/ushell/services/_ContentExtensionAdapterFactory/FeaturedGroupConfig.js +1 -1
- package/src/main/js/sap/ushell/services/_CrossApplicationNavigation/utils.js +2 -1
- package/src/main/js/sap/ushell/services/_MessageBroker/MessageBrokerEngine.js +1 -1
- package/src/main/js/sap/ushell/services/_PageReferencing/PageReferencer.js +1 -1
- package/src/main/js/sap/ushell/services/_Personalization/ContextContainer.js +6 -0
- package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainer.js +5 -1
- package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainerVariant.js +13 -9
- package/src/main/js/sap/ushell/services/_Personalization/PersonalizationContainerVariantSet.js +17 -13
- package/src/main/js/sap/ushell/services/_Personalization/Personalizer.js +5 -0
- package/src/main/js/sap/ushell/services/_Personalization/TransientPersonalizer.js +5 -1
- package/src/main/js/sap/ushell/services/_Personalization/Variant.js +4 -0
- package/src/main/js/sap/ushell/services/_Personalization/VariantSet.js +17 -9
- package/src/main/js/sap/ushell/services/_Personalization/VariantSetAdapter.js +4 -6
- package/src/main/js/sap/ushell/services/_Personalization/WindowAdapter.js +5 -44
- package/src/main/js/sap/ushell/services/_Personalization/WindowAdapterContainer.js +5 -101
- package/src/main/js/sap/ushell/services/_Personalization/constants.js +3 -0
- package/src/main/js/sap/ushell/services/_Personalization/constants.private.js +3 -0
- package/src/main/js/sap/ushell/services/_Personalization/utils.js +3 -0
- package/src/main/js/sap/ushell/services/_PluginManager/Extensions.js +1 -1
- package/src/main/js/sap/ushell/services/_PluginManager/HeaderExtensions.js +1 -1
- package/src/main/js/sap/ushell/services/_PluginManager/MenuExtensions.js +1 -1
- package/src/main/js/sap/ushell/services/_Ui5ComponentLoader/utils.js +29 -5
- package/src/main/js/sap/ushell/services/_UserRecents/UserRecentsBase.js +19 -27
- package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstance.js +4 -0
- package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstanceAbap.js +3 -0
- package/src/main/js/sap/ushell/services/_VisualizationInstantiation/VizInstanceLink.js +1 -1
- package/src/main/js/sap/ushell/services/personalization/VariantSetAdapter.js +13 -15
- package/src/main/js/sap/ushell/support/plugins/flpConfig/FlpConfigurationPlugin.js +1 -1
- package/src/main/js/sap/ushell/themes/sap_horizon/ShellAppTitle.less +4 -4
- package/src/main/js/sap/ushell/themes/sap_horizon_dark/ShellAppTitle.less +4 -4
- package/src/main/js/sap/ushell/themes/sap_horizon_hcb/ShellAppTitle.less +2 -2
- package/src/main/js/sap/ushell/themes/sap_horizon_hcw/ShellAppTitle.less +2 -2
- package/src/main/js/sap/ushell/ui/AppContainer.js +2 -2
- package/src/main/js/sap/ushell/ui/ContentNodeSelector.js +2 -2
- package/src/main/js/sap/ushell/ui/ShellHeader.js +2 -2
- package/src/main/js/sap/ushell/ui/cards/RecentActivitiesExtension.js +1 -1
- package/src/main/js/sap/ushell/ui/footerbar/AddBookmarkButton.js +8 -12
- package/src/main/js/sap/ushell/ui/launchpad/ExtendedChangeDetection.js +1 -1
- package/src/main/js/sap/ushell/ui/launchpad/Page.js +1 -1
- package/src/main/js/sap/ushell/ui/launchpad/Section.js +21 -8
- package/src/main/js/sap/ushell/ui/launchpad/TileState.js +0 -1
- package/src/main/js/sap/ushell/ui/launchpad/section/CompactArea.js +1 -1
- package/src/main/js/sap/ushell/ui/shell/ShellAppTitle.js +1 -1
- package/src/main/js/sap/ushell/ui/shell/ShellHeadItem.js +1 -1
- package/src/main/js/sap/ushell/ui/shell/SysInfoBar.js +1 -1
- package/src/main/js/sap/ushell/ui/shell/ToolAreaItem.js +1 -1
- package/src/main/js/sap/ushell/ui/utils.js +1 -1
- package/src/main/js/sap/ushell/ui5service/ShellUIService.js +1 -1
- package/src/main/js/sap/ushell/ui5service/UserStatus.js +1 -1
- package/src/main/js/sap/ushell/ui5service/_ShellUIService/shelluiservice.class.factory.js +14 -26
- package/src/main/js/sap/ushell/utils/Deferred.js +88 -0
- package/src/main/js/sap/ushell/utils/UrlShortening.js +1 -1
- package/src/main/js/sap/ushell/utils/WindowUtils.js +8 -8
- package/src/main/js/sap/ushell/utils.js +31 -67
- package/src/test/js/sap/ushell/bootstrap/sandbox.js +7 -2
- package/ui5.yaml +8 -2
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/HeadEndItemsOverflowPopover.fragment.xml +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ar.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_bg.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ca.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_cs.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_cy.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_da.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_de.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_el.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_GB.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_sappsd.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_saprigi.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_en_US_saptrc.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_es.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_es_MX.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_et.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fi.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fr.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_fr_CA.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hi.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hr.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_hu.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_id.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_it.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_iw.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ja.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_kk.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ko.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_lt.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_lv.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ms.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_nl.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_no.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pl.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pt.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_pt_PT.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ro.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_ru.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sh.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sk.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sl.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_sv.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_th.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_tr.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_uk.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_vi.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_zh_CN.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/resources/resources_zh_TW.properties +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/search/util.js +0 -0
- /package/src/main/js/sap/ushell/{renderers/fiori2 → renderer}/utils.js +0 -0
|
@@ -0,0 +1,3155 @@
|
|
|
1
|
+
// Copyright (c) 2009-2023 SAP SE, All Rights Reserved
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileOverview Shell Controller
|
|
5
|
+
*/
|
|
6
|
+
sap.ui.define([
|
|
7
|
+
"./History",
|
|
8
|
+
"sap/base/Log",
|
|
9
|
+
"sap/base/util/extend",
|
|
10
|
+
"sap/base/util/isPlainObject",
|
|
11
|
+
"sap/m/InstanceManager",
|
|
12
|
+
"sap/ui/core/Component",
|
|
13
|
+
"sap/ui/core/Configuration",
|
|
14
|
+
"sap/ui/core/Core",
|
|
15
|
+
"sap/ui/core/library",
|
|
16
|
+
"sap/ui/core/mvc/Controller",
|
|
17
|
+
"sap/ui/core/routing/HashChanger",
|
|
18
|
+
"sap/ui/core/routing/History",
|
|
19
|
+
"sap/ui/Device",
|
|
20
|
+
"sap/ui/model/json/JSONModel",
|
|
21
|
+
"sap/ui/performance/trace/Interaction",
|
|
22
|
+
"sap/ui/performance/Measurement",
|
|
23
|
+
"sap/ui/thirdparty/hasher",
|
|
24
|
+
"sap/ui/thirdparty/jquery",
|
|
25
|
+
"sap/ui/util/Storage",
|
|
26
|
+
"sap/ushell/bootstrap/SchedulingAgent",
|
|
27
|
+
"sap/ushell/components/_HeaderManager/ControlManager",
|
|
28
|
+
"sap/ushell/components/applicationIntegration/AppLifeCycle",
|
|
29
|
+
"sap/ushell/components/applicationIntegration/relatedServices/RelatedServices",
|
|
30
|
+
"sap/ushell/components/HeaderManager",
|
|
31
|
+
"sap/ushell/Config",
|
|
32
|
+
"sap/ushell/EventHub",
|
|
33
|
+
"sap/ushell/library",
|
|
34
|
+
"sap/ushell/performance/FesrEnhancer",
|
|
35
|
+
"sap/ushell/renderer/LogonFrameProvider",
|
|
36
|
+
"sap/ushell/resources",
|
|
37
|
+
"sap/ushell/services/AppConfiguration",
|
|
38
|
+
"sap/ushell/UserActivityLog",
|
|
39
|
+
"sap/ushell/utils",
|
|
40
|
+
"sap/ushell/utils/WindowUtils",
|
|
41
|
+
"sap/ushell/renderer/ShellLayout",
|
|
42
|
+
"sap/ushell/renderer/utils",
|
|
43
|
+
"sap/base/util/ObjectPath"
|
|
44
|
+
], function (
|
|
45
|
+
History,
|
|
46
|
+
Log,
|
|
47
|
+
extend,
|
|
48
|
+
isPlainObject,
|
|
49
|
+
InstanceManager,
|
|
50
|
+
Component,
|
|
51
|
+
Configuration,
|
|
52
|
+
Core,
|
|
53
|
+
library,
|
|
54
|
+
Controller,
|
|
55
|
+
HashChanger,
|
|
56
|
+
Ui5History,
|
|
57
|
+
Device,
|
|
58
|
+
JSONModel,
|
|
59
|
+
Interaction,
|
|
60
|
+
Measurement,
|
|
61
|
+
hasher,
|
|
62
|
+
jQuery,
|
|
63
|
+
Storage,
|
|
64
|
+
SchedulingAgent,
|
|
65
|
+
HeaderControlManager,
|
|
66
|
+
AppLifeCycleAI,
|
|
67
|
+
RelatedServices,
|
|
68
|
+
HeaderManager,
|
|
69
|
+
Config,
|
|
70
|
+
EventHub,
|
|
71
|
+
ushellLibrary,
|
|
72
|
+
FesrEnhancer,
|
|
73
|
+
LogonFrameProvider,
|
|
74
|
+
ushellResources,
|
|
75
|
+
AppConfiguration,
|
|
76
|
+
UserActivityLog,
|
|
77
|
+
ushellUtils,
|
|
78
|
+
WindowUtils,
|
|
79
|
+
ShellLayout,
|
|
80
|
+
RendererUtils,
|
|
81
|
+
ObjectPath
|
|
82
|
+
) {
|
|
83
|
+
"use strict";
|
|
84
|
+
|
|
85
|
+
var ShellLayoutMapping = ShellLayout.LAYOUT_MAPPING;
|
|
86
|
+
|
|
87
|
+
// shortcut for sap.ui.core.routing.HistoryDirection
|
|
88
|
+
var Ui5HistoryDirection = library.routing.HistoryDirection;
|
|
89
|
+
|
|
90
|
+
// shortcut for sap.ushell.AppType
|
|
91
|
+
var AppType = ushellLibrary.AppType;
|
|
92
|
+
|
|
93
|
+
/* don't delay these cause they are needed for direct bookmarks */
|
|
94
|
+
|
|
95
|
+
// create global model and add some demo data
|
|
96
|
+
var closeAllDialogs = true;
|
|
97
|
+
var bPreviousPageDirty = false;
|
|
98
|
+
var oShellModel;
|
|
99
|
+
var ShellModel = AppLifeCycleAI.getElementsModel();
|
|
100
|
+
var oModel;
|
|
101
|
+
var oEPCMNavigationMode = {
|
|
102
|
+
embedded: 0,
|
|
103
|
+
newWindowThenEmbedded: 1,
|
|
104
|
+
newWindow: 1,
|
|
105
|
+
replace: 0
|
|
106
|
+
};
|
|
107
|
+
var oNavigationMode = {
|
|
108
|
+
embedded: "embedded",
|
|
109
|
+
newWindowThenEmbedded: "newWindowThenEmbedded",
|
|
110
|
+
newWindow: "newWindow",
|
|
111
|
+
replace: "replace"
|
|
112
|
+
};
|
|
113
|
+
var oConfig = {};
|
|
114
|
+
|
|
115
|
+
// track performance marks and enhance UI5's Frontend Sub Records with FLP specific information
|
|
116
|
+
// Note: This can not yet be done using the SchedulingAgent as plain modules cannot be loaded and
|
|
117
|
+
// making it a UI5 component would be overhead (performance).
|
|
118
|
+
FesrEnhancer.init();
|
|
119
|
+
|
|
120
|
+
const sModuleName = "Shell.controller";
|
|
121
|
+
const sLogFesrPrefix = "[FesrFlp]";
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @name sap.ushell.renderer.Shell
|
|
125
|
+
* @extends sap.ui.core.mvc.Controller
|
|
126
|
+
* @public
|
|
127
|
+
*/
|
|
128
|
+
return Controller.extend("sap.ushell.renderer.Shell", {
|
|
129
|
+
_aDoables: [],
|
|
130
|
+
|
|
131
|
+
addDoable: function (oDoable) {
|
|
132
|
+
this._aDoables.push(oDoable);
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
_aDanglingControls: [],
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {sap.ui.core.Control} oControl The Control
|
|
139
|
+
* @see sap.ushell.renderer.Shell.controller#onExit
|
|
140
|
+
*
|
|
141
|
+
* @private
|
|
142
|
+
* @since 1.115.0
|
|
143
|
+
*/
|
|
144
|
+
addDanglingControl: function (oControl) {
|
|
145
|
+
this._aDanglingControls.push(oControl);
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
_aDanglingBindings: [],
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Adds a binding which is destroyed on Renderer destroy
|
|
152
|
+
* @param {sap.ui.model.Binding} oBinding The Binding
|
|
153
|
+
* @see sap.ushell.renderer.Shell.controller#onExit
|
|
154
|
+
*
|
|
155
|
+
* @private
|
|
156
|
+
* @since 1.115.0
|
|
157
|
+
*/
|
|
158
|
+
addDanglingBinding: function (oBinding) {
|
|
159
|
+
this._aDanglingBindings.push(oBinding);
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {sap.ui.model.Binding} oTargetBinding The Binding
|
|
164
|
+
* @see sap.ushell.renderer.Shell.controller#onExit
|
|
165
|
+
*
|
|
166
|
+
* @private
|
|
167
|
+
* @since 1.115.0
|
|
168
|
+
*/
|
|
169
|
+
removeDanglingBinding: function (oTargetBinding) {
|
|
170
|
+
var iBindingIndex = this._aDanglingBindings.findIndex(function (oBinding) {
|
|
171
|
+
return oBinding === oTargetBinding;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (iBindingIndex > -1) {
|
|
175
|
+
this._aDanglingBindings.splice(iBindingIndex, 1);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
_aPendingInitializations: [],
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Adds a promise to the list of initializations
|
|
183
|
+
* Only used in test environments!
|
|
184
|
+
* @param {Promise} oPromise A Promise
|
|
185
|
+
* @returns {Promise} Returns the provided promise to allow chaining
|
|
186
|
+
*
|
|
187
|
+
* @private
|
|
188
|
+
* @since 1.115.0
|
|
189
|
+
*/
|
|
190
|
+
addPendingInitialization: function (oPromise) {
|
|
191
|
+
this._aPendingInitializations.push(oPromise);
|
|
192
|
+
return oPromise;
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Only used in test environments!
|
|
197
|
+
* @returns {Promise} Resolves once all initializations have settled
|
|
198
|
+
*
|
|
199
|
+
* @private
|
|
200
|
+
* @since 1.115.0
|
|
201
|
+
*/
|
|
202
|
+
awaitPendingInitializations: function () {
|
|
203
|
+
var iOldLength = this._aPendingInitializations.length;
|
|
204
|
+
return Promise.allSettled(this._aPendingInitializations)
|
|
205
|
+
.then(function () {
|
|
206
|
+
var iNewLength = this._aPendingInitializations.length;
|
|
207
|
+
if (iOldLength < iNewLength) {
|
|
208
|
+
return this.awaitPendingInitializations();
|
|
209
|
+
}
|
|
210
|
+
}.bind(this));
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
onComponentTargetDisplay: function (oEvent) {
|
|
214
|
+
var oParameters = oEvent.getParameters();
|
|
215
|
+
var oContainer = oParameters.control;
|
|
216
|
+
var oComponentContainer = oParameters.object;
|
|
217
|
+
|
|
218
|
+
if (this.bRestorePreviousHash) {
|
|
219
|
+
this.bRestorePreviousHash = false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
oContainer.navTo("centerViewPort", oComponentContainer.getId(), "show");
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
onInit: function () {
|
|
226
|
+
var oRouter = Component.getOwnerComponentFor(this.getView()).getRouter();
|
|
227
|
+
|
|
228
|
+
// TODO We still need to think about implementing a custom router to move the display handler from
|
|
229
|
+
// this file to the custom router. Maybe use oRouter.attachBypassed?
|
|
230
|
+
oRouter.getTarget("home").attachDisplay(this.onComponentTargetDisplay, this);
|
|
231
|
+
oRouter.getTarget("appfinder").attachDisplay(this.onComponentTargetDisplay, this);
|
|
232
|
+
oRouter.getTarget("pages").attachDisplay(this.onComponentTargetDisplay, this);
|
|
233
|
+
oRouter.getTarget("workpages").attachDisplay(this.onComponentTargetDisplay, this);
|
|
234
|
+
oRouter.getTarget("runtimeSwitcher").attachDisplay(this.onComponentTargetDisplay, this);
|
|
235
|
+
oRouter.getTarget("wzsearch").attachDisplay(this.onComponentTargetDisplay, this);
|
|
236
|
+
|
|
237
|
+
if (Config.last("/core/homeApp/enabled")) {
|
|
238
|
+
oRouter.getTarget("homeapp").attachDisplay(this.onComponentTargetDisplay, this);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/*
|
|
242
|
+
* Assign hash changer directly because otherwise a default one is used.
|
|
243
|
+
*
|
|
244
|
+
* Default hash changers for UI5 routers assume &/ is the separator for a nested component route.
|
|
245
|
+
*
|
|
246
|
+
* We must re-assign this otherwise an hash like `#Shell-appfinder&/userMenu' ends up in `#Shell-appfinder&/'
|
|
247
|
+
* in the URL - &/userMenu part is eaten by the default hash changer.
|
|
248
|
+
*/
|
|
249
|
+
oRouter.oHashChanger = HashChanger.getInstance();
|
|
250
|
+
oRouter.initialize(true /*tell the router not to parse the current browser hash, and wait for ShellNavigation.init*/);
|
|
251
|
+
|
|
252
|
+
this.bEnableHashChange = true;
|
|
253
|
+
closeAllDialogs = true;
|
|
254
|
+
var oView = this.getView();
|
|
255
|
+
var oViewData = oView.getViewData() || {};
|
|
256
|
+
var mediaQ = window.matchMedia("(min-width: 600px)");
|
|
257
|
+
var oViewConfig = oViewData.config || {};
|
|
258
|
+
|
|
259
|
+
var oApplicationModel = AppLifeCycleAI.shellElements().model();
|
|
260
|
+
HeaderManager.init(oViewConfig, oApplicationModel);
|
|
261
|
+
|
|
262
|
+
oView.setModel(oViewData.helperModel, "helper");
|
|
263
|
+
oView.setModel(oViewData.shellModel);
|
|
264
|
+
// Add global model to view
|
|
265
|
+
this.initShellModel(oViewConfig, oApplicationModel);
|
|
266
|
+
|
|
267
|
+
var handleMedia = function (mq) {
|
|
268
|
+
Config.emit("/core/shell/model/isPhoneWidth", !mq.matches);
|
|
269
|
+
};
|
|
270
|
+
if (mediaQ.addListener) { // Assure that mediaMatch is supported(Not supported on IE9).
|
|
271
|
+
mediaQ.addListener(handleMedia);
|
|
272
|
+
handleMedia(mediaQ);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Bind the translation model to this view
|
|
276
|
+
oView.setModel(ushellResources.i18nModel, "i18n");
|
|
277
|
+
|
|
278
|
+
Core.getEventBus().subscribe("externalSearch", this.externalSearchTriggered, this);
|
|
279
|
+
Core.getEventBus().subscribe("sap.ushell", "appOpened", this.onAppOpened, this);
|
|
280
|
+
Core.getEventBus().subscribe("ESHSearchFinished", this._logSearchActivity, this);
|
|
281
|
+
// handling of configuration should be done before the code block below otherwise the doHashChange is
|
|
282
|
+
// triggered before the personalization flag is disabled (URL may contain hash value which invokes navigation)
|
|
283
|
+
this._setConfigurationToModel();
|
|
284
|
+
|
|
285
|
+
// Doable objects are kept in a global array to enable their off-ing later on.
|
|
286
|
+
this._registerAndCreateEventHubDoables();
|
|
287
|
+
|
|
288
|
+
oShellModel.addHeaderEndItem(["userActionsMenuHeaderButton"], false, ["home", "app", "minimal", "standalone", "embedded", "embedded-home", "lean"], true);
|
|
289
|
+
|
|
290
|
+
// Actions to add to custom states
|
|
291
|
+
var aActions = [];
|
|
292
|
+
|
|
293
|
+
if (oViewConfig && !oViewConfig.moveContactSupportActionToShellHeader) {
|
|
294
|
+
aActions.push("ContactSupportBtn");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.history = new History();
|
|
298
|
+
this.oViewPortContainer = Core.byId("viewPortContainer");
|
|
299
|
+
AppLifeCycleAI.init(oViewConfig.appState, this.oViewPortContainer, oViewConfig.rootIntent, oViewConfig.disableHomeAppCache, {
|
|
300
|
+
ownerComponent: this.getOwnerComponent()
|
|
301
|
+
}, aActions, oViewConfig.cacheConfiguration);
|
|
302
|
+
|
|
303
|
+
// init Shell Navigation
|
|
304
|
+
var initShellNavigation = function (oShellNavigation, oAppLifeCycleService) {
|
|
305
|
+
this.oShellNavigation = oShellNavigation;
|
|
306
|
+
this.oShellNavigation.registerPrivateFilters(oAppLifeCycleService);
|
|
307
|
+
|
|
308
|
+
// register the router in the ShellNavigation to let it skip the split of hash before firing the hashChange event
|
|
309
|
+
this.oShellNavigation.registerExtraRouter(oRouter);
|
|
310
|
+
this.oShellNavigation.registerNavigationFilter(this._handleEmptyHash.bind(this));
|
|
311
|
+
// must be after event registration (for synchronous nav target resolver calls)
|
|
312
|
+
this.oShellNavigation.init(this.doHashChange.bind(this));
|
|
313
|
+
|
|
314
|
+
this.oShellNavigation.registerNavigationFilter(this._disableSourceAppRouter.bind(this));
|
|
315
|
+
|
|
316
|
+
this.oShellNavigation.registerNavigationFilter(this.handleDataLoss.bind(this));
|
|
317
|
+
|
|
318
|
+
AppLifeCycleAI.registerHandleHashChange(this.oShellNavigation);
|
|
319
|
+
// enable the direct app start and tests to wait for the initialization
|
|
320
|
+
EventHub.emit("ShellNavigationInitialized", Date.now());
|
|
321
|
+
}.bind(this);
|
|
322
|
+
|
|
323
|
+
Promise.all([
|
|
324
|
+
sap.ushell.Container.getServiceAsync("URLParsing"),
|
|
325
|
+
sap.ushell.Container.getServiceAsync("ShellNavigation"),
|
|
326
|
+
sap.ushell.Container.getServiceAsync("AppLifeCycle")
|
|
327
|
+
])
|
|
328
|
+
.then(function (aServices) {
|
|
329
|
+
this.oURLParsing = aServices[0];
|
|
330
|
+
var oShellNavigation = aServices[1];
|
|
331
|
+
this._oAppLifeCycleService = aServices[2];
|
|
332
|
+
|
|
333
|
+
initShellNavigation(oShellNavigation, this._oAppLifeCycleService);
|
|
334
|
+
}.bind(this));
|
|
335
|
+
|
|
336
|
+
sap.ushell.Container.setLogonFrameProvider(this._getLogonFrameProvider());
|
|
337
|
+
|
|
338
|
+
if (Device.system.desktop) {
|
|
339
|
+
sap.ui.require(["sap/ushell/renderer/AccessKeysHandler"], function (AccessKeysHandler) {
|
|
340
|
+
AccessKeysHandler.init(oModel);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
window.onbeforeunload = function () {
|
|
345
|
+
if (sap.ushell.Container && sap.ushell.Container.getDirtyFlag()
|
|
346
|
+
// workaround: skip data-loss-warning in IE when app is NWBC-based (as there is a separate implementation)
|
|
347
|
+
&& !(Device.browser.name === Device.browser.BROWSER.INTERNET_EXPLORER
|
|
348
|
+
&& AppLifeCycleAI.getCurrentApplication().container.getApplicationType() === "NWBC")
|
|
349
|
+
) {
|
|
350
|
+
if (!ushellResources.browserI18n) {
|
|
351
|
+
ushellResources.browserI18n = ushellResources.getTranslationModel(window.navigator.language).getResourceBundle();
|
|
352
|
+
}
|
|
353
|
+
return ushellResources.browserI18n.getText("dataLossExternalMessage");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return undefined;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
if (Config.last("/core/shell/model/contentDensity")) {
|
|
360
|
+
// do not call _applyContentDensity,
|
|
361
|
+
// no promise that the component-preload is fully loaded and _applyContentDensity loads the root application.
|
|
362
|
+
// we only want to display the shell in its default state, once the root application will be loaded
|
|
363
|
+
// then the _applyContentDensity will be called with promise that component-preload loaded.
|
|
364
|
+
AppLifeCycleAI.getAppMeta()._applyContentDensityClass();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
this.initShellUIService();
|
|
368
|
+
|
|
369
|
+
if (!oViewConfig.disableSignOut && (oViewConfig.sessionTimeoutTileStopRefreshIntervalInMinutes > 0 || oViewConfig.sessionTimeoutReminderInMinutes > 0)) {
|
|
370
|
+
this._createSessionHandler(oViewConfig);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (Device.system.desktop) {
|
|
374
|
+
sap.ui.require(["sap/ushell/renderer/AccessKeysHandler"], function (AccessKeysHandler) {
|
|
375
|
+
oView.waitForShellLayout().then(function () {
|
|
376
|
+
var oNavigationBar = document.getElementById(ShellLayoutMapping.NavigationBar);
|
|
377
|
+
oNavigationBar.addEventListener("focusin", function () {
|
|
378
|
+
// focus not in the shell
|
|
379
|
+
AccessKeysHandler.bFocusOnShell = false;
|
|
380
|
+
AccessKeysHandler.bFocusPassedToExternalHandlerFirstTime = false;
|
|
381
|
+
});
|
|
382
|
+
oNavigationBar.addEventListener("focusout", function () {
|
|
383
|
+
// focus in the shell
|
|
384
|
+
AccessKeysHandler.bFocusOnShell = true;
|
|
385
|
+
AccessKeysHandler.bFocusPassedToExternalHandlerFirstTime = true;
|
|
386
|
+
});
|
|
387
|
+
var oRootView = document.getElementById(ShellLayoutMapping.RendererRootView);
|
|
388
|
+
oRootView.addEventListener("focusin", function () {
|
|
389
|
+
// focus not in the shell
|
|
390
|
+
AccessKeysHandler.bFocusOnShell = false;
|
|
391
|
+
AccessKeysHandler.bFocusPassedToExternalHandlerFirstTime = false;
|
|
392
|
+
});
|
|
393
|
+
oRootView.addEventListener("focusout", function () {
|
|
394
|
+
// focus in the shell
|
|
395
|
+
AccessKeysHandler.bFocusOnShell = true;
|
|
396
|
+
AccessKeysHandler.bFocusPassedToExternalHandlerFirstTime = true;
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
|
|
403
|
+
shellUpdateAggItem: function (sId, oContext) {
|
|
404
|
+
return Core.byId(oContext.getObject());
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
getViewPortContainer: function () {
|
|
408
|
+
return Core.byId("viewPortContainer");
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Creates the EventHub event bindings and saves them.
|
|
413
|
+
*/
|
|
414
|
+
_registerAndCreateEventHubDoables: function () {
|
|
415
|
+
[
|
|
416
|
+
EventHub.once("CenterViewPointContentRendered").do(this._loadCoreExt.bind(this)),
|
|
417
|
+
EventHub.once("PagesRuntimeRendered").do(this._loadCoreExt.bind(this)),
|
|
418
|
+
EventHub.once("AppRendered").do(this._loadCoreExtNonUI5.bind(this)),
|
|
419
|
+
EventHub.on("toggleContentDensity").do(this.toggleContentDensity.bind(this)),
|
|
420
|
+
EventHub.on("ShellFloatingContainerUndockOnResize").do(this._handleFloatingContainerUndockOnResize.bind(this)),
|
|
421
|
+
EventHub.on("ShellFloatingContainerDockedIsResized").do(this._emitFloatingContainerResizeEvent.bind(this)),
|
|
422
|
+
EventHub.on("LaunchpadCustomRouterRouteMatched").do(this._centerViewPort.bind(this)),
|
|
423
|
+
|
|
424
|
+
EventHub.once("CoreResourcesComplementLoaded").do(this._onCoreResourcesComplementLoaded.bind(this)),
|
|
425
|
+
EventHub.once("loadRendererExtensions").do(this._loadRendererExtensionPlugins.bind(this)),
|
|
426
|
+
EventHub.once("loadUsageAnalytics").do(this._loadUsageAnalytics.bind(this)),
|
|
427
|
+
EventHub.once("loadWarmupPlugins").do(this._loadWarmupPlugins.bind(this)),
|
|
428
|
+
EventHub.once("loadTrackingActivitiesSetting").do(this._loadTrackingActivitiesSetting.bind(this)),
|
|
429
|
+
EventHub.on("centerViewPort").do(this._centerViewPort.bind(this))
|
|
430
|
+
].forEach(function (oDoable) {
|
|
431
|
+
this.addDoable(oDoable);
|
|
432
|
+
}.bind(this));
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
initShellModel: function (oConfigForModel, oApplicationModel) {
|
|
436
|
+
oShellModel = ShellModel;
|
|
437
|
+
oShellModel.init(oConfigForModel, oApplicationModel);
|
|
438
|
+
oModel = this.getView().getViewData().shellModel;
|
|
439
|
+
Config.emit("/core/shell/model/personalization", Config.last("/core/shell/enablePersonalization"));
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
initShellUIService: function () {
|
|
443
|
+
AppLifeCycleAI.initShellUIService({
|
|
444
|
+
fnOnBackNavigationChange: this.onBackNavigationChange.bind(this)
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
if (oConfig.enableOnlineStatus) {
|
|
448
|
+
sap.ui.require(["sap/ushell/ui5service/UserStatus"], function (UserStatus) {
|
|
449
|
+
this.oUserStatus = new UserStatus({
|
|
450
|
+
scopeObject: this.getOwnerComponent(),
|
|
451
|
+
scopeType: "component"
|
|
452
|
+
});
|
|
453
|
+
}.bind(this));
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
/*
|
|
458
|
+
* This method change the back navigation handler with custom logic in the shell header when the ShellUIService#setBackNavigation method is called.
|
|
459
|
+
*
|
|
460
|
+
* This method currently assumes that the application is displayed in the "minimal" state (no home button present).
|
|
461
|
+
*/
|
|
462
|
+
onBackNavigationChange: function (oEvent) {
|
|
463
|
+
AppLifeCycleAI.setBackNavigationChanged(true);
|
|
464
|
+
var fnCallback = oEvent.getParameters().data;
|
|
465
|
+
var oCurrentStateModel = Config.last("/core/shell/model/currentState");
|
|
466
|
+
|
|
467
|
+
if (fnCallback) {
|
|
468
|
+
AppLifeCycleAI.service().setNavigateBack(fnCallback);
|
|
469
|
+
|
|
470
|
+
if (oCurrentStateModel.stateName === "minimal" || oCurrentStateModel.stateName === "standalone" || oCurrentStateModel.stateName === "embedded") {
|
|
471
|
+
sap.ushell.Container.getRenderer("fiori2").showHeaderItem("backBtn", true);
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
//if no callback is provided we set the default handler: history back
|
|
475
|
+
AppLifeCycleAI.service().resetNavigateBack();
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
toggleContentDensity: function (oData) {
|
|
480
|
+
var isCompact = oData.contentDensity === "compact";
|
|
481
|
+
AppLifeCycleAI.getAppMeta()._applyContentDensityByPriority(isCompact, true);
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
_handleEmptyHash: function (sHash) {
|
|
485
|
+
sHash = (typeof sHash === "string") ? sHash : "";
|
|
486
|
+
sHash = sHash.split("?")[0];
|
|
487
|
+
if (sHash.length === 0) {
|
|
488
|
+
var oViewData = this.getView() ? this.getView().getViewData() : {};
|
|
489
|
+
oConfig = oViewData.config || {};
|
|
490
|
+
// Migration support: we have to set rootIntent empty
|
|
491
|
+
// And continue navigation in order to check if empty hash is resolved locally
|
|
492
|
+
if (oConfig.migrationConfig) {
|
|
493
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
494
|
+
}
|
|
495
|
+
if (oConfig.rootIntent) {
|
|
496
|
+
window.setTimeout(function () {
|
|
497
|
+
window.hasher.setHash(oConfig.rootIntent);
|
|
498
|
+
}, 0);
|
|
499
|
+
return this.oShellNavigation.NavigationFilterStatus.Abandon;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
_setConfigurationToModel: function () {
|
|
506
|
+
var oViewData = this.getView().getViewData();
|
|
507
|
+
|
|
508
|
+
if (oViewData) {
|
|
509
|
+
oConfig = oViewData.config || {};
|
|
510
|
+
}
|
|
511
|
+
if (oConfig) {
|
|
512
|
+
if (oConfig.states) {
|
|
513
|
+
ShellModel.extendStates(oConfig.states);
|
|
514
|
+
HeaderManager.extendStates(oConfig.states);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (oConfig.enableSetTheme !== undefined) {
|
|
518
|
+
oModel.setProperty("/setTheme", oConfig.enableSetTheme);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Compact Cozy mode
|
|
522
|
+
oModel.setProperty("/contentDensity", oConfig.enableContentDensity === undefined ? true : oConfig.enableContentDensity);
|
|
523
|
+
|
|
524
|
+
// Check if the configuration is passed by html of older version(1.28 and lower)
|
|
525
|
+
if (oConfig.migrationConfig !== undefined) {
|
|
526
|
+
oModel.setProperty("/migrationConfig", oConfig.migrationConfig);
|
|
527
|
+
}
|
|
528
|
+
// User default parameters settings
|
|
529
|
+
if (oConfig.enableUserDefaultParameters !== undefined) {
|
|
530
|
+
oModel.setProperty("/userDefaultParameters", oConfig.enableUserDefaultParameters);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (oConfig.disableHomeAppCache !== undefined) {
|
|
534
|
+
oModel.setProperty("/disableHomeAppCache", oConfig.disableHomeAppCache);
|
|
535
|
+
}
|
|
536
|
+
// xRay enablement configuration
|
|
537
|
+
oModel.setProperty("/enableHelp", Config.last("/core/extension/enableHelp"));
|
|
538
|
+
oModel.setProperty("/searchAvailable", (oConfig.enableSearch !== false));
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
|
|
542
|
+
_loadTrackingActivitiesSetting: function (eventData) {
|
|
543
|
+
// Tracking activities
|
|
544
|
+
this._getPersData({
|
|
545
|
+
container: "flp.settings.FlpSettings",
|
|
546
|
+
item: "userActivitesTracking"
|
|
547
|
+
}).then(function (enableTrackingActivity) {
|
|
548
|
+
if (enableTrackingActivity === undefined) {
|
|
549
|
+
enableTrackingActivity = true;
|
|
550
|
+
}
|
|
551
|
+
oModel.setProperty("/enableTrackingActivity", enableTrackingActivity);
|
|
552
|
+
EventHub.emit("StepDone", eventData.stepName);
|
|
553
|
+
}).catch(function (error) {
|
|
554
|
+
EventHub.emit("StepFailed", eventData.stepName);
|
|
555
|
+
Log.error(
|
|
556
|
+
"Failed to load tracking activities state from the personalization", error,
|
|
557
|
+
"sap.ushell.components.flp.settings.FlpSettings");
|
|
558
|
+
});
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
_getPreviousPageDirty: function () {
|
|
562
|
+
return bPreviousPageDirty;
|
|
563
|
+
},
|
|
564
|
+
|
|
565
|
+
_setPreviousPageDirty: function (bState) {
|
|
566
|
+
bPreviousPageDirty = bState;
|
|
567
|
+
},
|
|
568
|
+
|
|
569
|
+
getModelConfiguration: function () {
|
|
570
|
+
var oViewData = this.getView().getViewData();
|
|
571
|
+
var oShellConfig;
|
|
572
|
+
|
|
573
|
+
if (oViewData) {
|
|
574
|
+
var oConfiguration = oViewData.config || {};
|
|
575
|
+
oShellConfig = extend({}, oConfiguration);
|
|
576
|
+
}
|
|
577
|
+
delete oShellConfig.applications;
|
|
578
|
+
return oShellConfig;
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* This method will be used by the Container service in order to create, show and destroy a Dialog control with an inner iframe.
|
|
583
|
+
* The iframe will be used for rare scenarios in which additional authentication is required.
|
|
584
|
+
* This is mainly related to SAML 2.0 flows. The api sequence will be managed by UI2 services.
|
|
585
|
+
*
|
|
586
|
+
* @returns {{create: function, show: function, destroy: function}} Logon Frame Provider interface
|
|
587
|
+
* @private
|
|
588
|
+
*/
|
|
589
|
+
_getLogonFrameProvider: function () {
|
|
590
|
+
return LogonFrameProvider;
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
onExit: function () {
|
|
594
|
+
this._aDoables.forEach(function (oDoable) {
|
|
595
|
+
oDoable.off();
|
|
596
|
+
});
|
|
597
|
+
this._aDoables = [];
|
|
598
|
+
|
|
599
|
+
this._aDanglingControls.forEach(function (oControl) {
|
|
600
|
+
oControl.destroy();
|
|
601
|
+
});
|
|
602
|
+
this._aDanglingControls = [];
|
|
603
|
+
|
|
604
|
+
this._aDanglingBindings.forEach(function (oBinding) {
|
|
605
|
+
oBinding.destroy();
|
|
606
|
+
});
|
|
607
|
+
this._aDanglingBindings = [];
|
|
608
|
+
|
|
609
|
+
Core.getEventBus().unsubscribe("externalSearch", this.externalSearchTriggered, this);
|
|
610
|
+
Core.getEventBus().unsubscribe("ESHSearchFinished", this._logSearchActivity, this);
|
|
611
|
+
Core.getEventBus().unsubscribe("sap.ushell", "appOpened", this.onAppOpened, this);
|
|
612
|
+
|
|
613
|
+
// Some qUnits destroy the shell very early, check if oShellNavigation exists
|
|
614
|
+
if (this.oShellNavigation) {
|
|
615
|
+
this.oShellNavigation.hashChanger.destroy();
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
HeaderManager.destroy();
|
|
619
|
+
HeaderControlManager.destroy();
|
|
620
|
+
|
|
621
|
+
UserActivityLog.deactivate();
|
|
622
|
+
oShellModel.destroy();
|
|
623
|
+
AppLifeCycleAI.shellElements().clean();
|
|
624
|
+
oShellModel = undefined;
|
|
625
|
+
},
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* @returns {object} the current router of the current application component
|
|
629
|
+
*/
|
|
630
|
+
_getCurrentAppRouter: function () {
|
|
631
|
+
var oAppLifeCycle = this._oAppLifeCycleService;
|
|
632
|
+
var oCurrentApplication = oAppLifeCycle && oAppLifeCycle.getCurrentApplication && oAppLifeCycle.getCurrentApplication();
|
|
633
|
+
var oComponentInstance = oCurrentApplication && oCurrentApplication.componentInstance;
|
|
634
|
+
|
|
635
|
+
if (oComponentInstance) {
|
|
636
|
+
return oComponentInstance.getRouter();
|
|
637
|
+
}
|
|
638
|
+
return null;
|
|
639
|
+
},
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* If the navigation is not an inner app navigation, this function stops the router of the old application.
|
|
643
|
+
*
|
|
644
|
+
* @param {string} newHash new url hash
|
|
645
|
+
* @param {string} oldHash old url hash
|
|
646
|
+
*
|
|
647
|
+
* @returns {string} ShellNavigation.NavigationFilterStatus
|
|
648
|
+
*/
|
|
649
|
+
_disableSourceAppRouter: function (newHash, oldHash) {
|
|
650
|
+
if (!this.bEnableHashChange || this.bRestorePreviousHash) {
|
|
651
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
var bAppSpecificChange = this.oShellNavigation.hashChanger.isInnerAppNavigation(newHash, oldHash);
|
|
655
|
+
if (!bAppSpecificChange) {
|
|
656
|
+
var oCurrentAppRouter = this._getCurrentAppRouter();
|
|
657
|
+
|
|
658
|
+
if (oCurrentAppRouter && oCurrentAppRouter.isInitialized()) {
|
|
659
|
+
oCurrentAppRouter.stop();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
664
|
+
},
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Makes sure that the router is not stopped after a failed / aborted navigation.
|
|
668
|
+
* We ignore the current hash when re-initializing the router because we are handling cases that restore the old state
|
|
669
|
+
* (nothing should change application side when the router is resumed).
|
|
670
|
+
*/
|
|
671
|
+
_resumeAppRouterIgnoringCurrentHash: function () {
|
|
672
|
+
var oAppRouter = this._getCurrentAppRouter();
|
|
673
|
+
|
|
674
|
+
if (oAppRouter) {
|
|
675
|
+
oAppRouter.initialize(true /* bIgnoreInitialHash */);
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Navigation Filter function registered with ShellNavigation service.
|
|
681
|
+
* Triggered on each navigation.
|
|
682
|
+
* Aborts navigation if there are unsaved data inside app(getDirtyFlag returns true).
|
|
683
|
+
* For non-IE browsers the dirtyState=true gets handled asynchronously by undoing the navigation and redoing the navigation.
|
|
684
|
+
* In case of an explace navigation there is no data loss popup.
|
|
685
|
+
*
|
|
686
|
+
* @param {string} targetIntent The new intent to navigate to.
|
|
687
|
+
* @param {string} currentIntent The current intent before navigation was triggered.
|
|
688
|
+
* @returns {string|object} A navigation filter status object or string.
|
|
689
|
+
* @private
|
|
690
|
+
*/
|
|
691
|
+
handleDataLoss: function (targetIntent, currentIntent) {
|
|
692
|
+
var oShellNavigationHashChanger = this.oShellNavigation.hashChanger;
|
|
693
|
+
var bReloadApplication = oShellNavigationHashChanger.getReloadApplication();
|
|
694
|
+
|
|
695
|
+
if (this.bReloadApplication !== null && this.bReloadApplication !== undefined) {
|
|
696
|
+
oShellNavigationHashChanger.setReloadApplication(this.bReloadApplication);
|
|
697
|
+
this.bReloadApplication = null;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// We are navigating from empty hash to rootIntent
|
|
701
|
+
if (currentIntent === "" || hasher.disableBlueBoxHashChangeTrigger === true) {
|
|
702
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (!this.bEnableHashChange && !this.bRedoNavigation) {
|
|
706
|
+
this.bEnableHashChange = true;
|
|
707
|
+
|
|
708
|
+
return this.oShellNavigation.NavigationFilterStatus.Custom;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (this.bRestorePreviousHash) {
|
|
712
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// User confirmed the data loss and now we do the hash change again
|
|
716
|
+
if (this.bRedoNavigation) {
|
|
717
|
+
this.bRedoNavigation = false;
|
|
718
|
+
this.bEnableHashChange = true;
|
|
719
|
+
this.bExplaceNavigation = false;
|
|
720
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Do we do an ex-place navigation?
|
|
724
|
+
var oParsedHash = this.oURLParsing.parseShellHash(targetIntent);
|
|
725
|
+
var bBuiltInIntent = sap.ushell.Container.getRenderer()._isBuiltInIntent(oParsedHash);
|
|
726
|
+
var aParsedNavMode = oParsedHash.params["sap-ushell-navmode"];
|
|
727
|
+
var sNavMode = aParsedNavMode && aParsedNavMode[0];
|
|
728
|
+
|
|
729
|
+
// Built-in intents must never be opened ex-place, therefore only continue with non built-in Intents
|
|
730
|
+
if (!bBuiltInIntent && (this.bExplaceNavigation || sNavMode === "explace" || sNavMode === "frameless")) {
|
|
731
|
+
// Yes, just continue the navigation without a dirtyFlag popup
|
|
732
|
+
this.bExplaceNavigation = false;
|
|
733
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// In case the async dirtyState provider is NOT set we only have to check the sync dirtyState.
|
|
737
|
+
// TODO: Simplify (Remove) the shortcut once the OPA test iframe issue is solved.
|
|
738
|
+
// The OPA iframe handler overwrites some hasher methods which results in a confused ushell navigation flow.
|
|
739
|
+
var bIsDirty = sap.ushell.Container.getDirtyFlag();
|
|
740
|
+
var bIsAsyncDirtyStateProviderSet = sap.ushell.Container.isAsyncDirtyStateProviderSet();
|
|
741
|
+
if (!bIsAsyncDirtyStateProviderSet && !bIsDirty) {
|
|
742
|
+
bPreviousPageDirty = bIsDirty;
|
|
743
|
+
return this.oShellNavigation.NavigationFilterStatus.Continue;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/*
|
|
747
|
+
The dirtyState is either true or has to be retrieved async.
|
|
748
|
+
After the hash changes we evaluate the dirtyState asynchronously
|
|
749
|
+
and redo the navigation in case it is false. In case it is true we do additional logic
|
|
750
|
+
_restoreHashUsingAction returns the NavigationFilterStatus Custom.
|
|
751
|
+
*/
|
|
752
|
+
var bIsBackNavigation = Ui5History.getInstance().getHistoryStateOffset() < 0;
|
|
753
|
+
Promise.all([
|
|
754
|
+
this._waitForHash(currentIntent),
|
|
755
|
+
sap.ushell.Container.getServiceAsync("NavTargetResolution"),
|
|
756
|
+
sap.ushell.Container.getDirtyFlagsAsync()
|
|
757
|
+
])
|
|
758
|
+
.then(function (aResults) {
|
|
759
|
+
var oService = aResults[1];
|
|
760
|
+
var bIsDirty = aResults[2];
|
|
761
|
+
|
|
762
|
+
/*
|
|
763
|
+
Update the internal dirtyFlag to match the current dirtyFlag
|
|
764
|
+
This is needed in case of a hashChangeFailure. When we navigate to a broken app the
|
|
765
|
+
controller does not ask for the dirtyState therefore we need to be able to restore it
|
|
766
|
+
*/
|
|
767
|
+
bPreviousPageDirty = bIsDirty;
|
|
768
|
+
|
|
769
|
+
if (!bIsDirty) {
|
|
770
|
+
this.bRedoNavigation = true;
|
|
771
|
+
this._restoreHashUsingAction(targetIntent, "redo");
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// Built-in intents can not be resolved, so we need to check
|
|
776
|
+
// first if the user is trying to navigate to one of them.
|
|
777
|
+
if (bBuiltInIntent) {
|
|
778
|
+
// We assume built-in intents are always in-place, so we need user input
|
|
779
|
+
if (this._handleDirtyStateUserConfirm()) {
|
|
780
|
+
this.bRedoNavigation = true;
|
|
781
|
+
this._restoreHashUsingAction(targetIntent, "redo");
|
|
782
|
+
}
|
|
783
|
+
} else {
|
|
784
|
+
// resolveHashFragment expects a full hash, this filter always gets the target without '#'
|
|
785
|
+
var sTargetHash = "#" + targetIntent;
|
|
786
|
+
oService.resolveHashFragment(sTargetHash)
|
|
787
|
+
.then(function (oResolvedHashFragment) {
|
|
788
|
+
var bIsExplaceNavigation = oResolvedHashFragment.targetNavigationMode === "explace" || oResolvedHashFragment.targetNavigationMode === "frameless";
|
|
789
|
+
var bIsBackNavigationAndNewWindow = bIsBackNavigation && oResolvedHashFragment.navigationMode === oNavigationMode.newWindowThenEmbedded;
|
|
790
|
+
|
|
791
|
+
if (bIsExplaceNavigation && (!bIsBackNavigationAndNewWindow)) {
|
|
792
|
+
this.bExplaceNavigation = true;
|
|
793
|
+
this.bRedoNavigation = true;
|
|
794
|
+
this._restoreHashUsingAction(targetIntent, "redo");
|
|
795
|
+
} else if (this._handleDirtyStateUserConfirm()) {
|
|
796
|
+
this.bRedoNavigation = true;
|
|
797
|
+
this.bReloadApplication = bReloadApplication;
|
|
798
|
+
this._restoreHashUsingAction(targetIntent, "redo");
|
|
799
|
+
}
|
|
800
|
+
}.bind(this))
|
|
801
|
+
.catch(function () {
|
|
802
|
+
// If the resolution failed, redoing the navigation will trigger the
|
|
803
|
+
// error pop-up.
|
|
804
|
+
this.bRedoNavigation = true;
|
|
805
|
+
this._restoreHashUsingAction(targetIntent, "redo");
|
|
806
|
+
}.bind(this));
|
|
807
|
+
}
|
|
808
|
+
}.bind(this));
|
|
809
|
+
|
|
810
|
+
// Returns this.oShellNavigation.NavigationFilterStatus.Custom
|
|
811
|
+
return this._restoreHashUsingAction(currentIntent, "undo");
|
|
812
|
+
},
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Wait for the given hash to be loaded by the browser.
|
|
816
|
+
*
|
|
817
|
+
* @param {string} hash The hash to wait for.
|
|
818
|
+
* @returns {Promise<undefined>} A promise that is resolved once the given hash was found. It is not rejected.
|
|
819
|
+
* @since 1.86.0
|
|
820
|
+
* @private
|
|
821
|
+
*/
|
|
822
|
+
_waitForHash: function (hash) {
|
|
823
|
+
var sHash = "#" + hash;
|
|
824
|
+
|
|
825
|
+
return new Promise(function (resolve) {
|
|
826
|
+
var fnWaitChange = function () {
|
|
827
|
+
var bChanged = sHash === decodeURIComponent(window.location.hash);
|
|
828
|
+
|
|
829
|
+
if (bChanged) {
|
|
830
|
+
window.removeEventListener("hashchange", fnWaitChange);
|
|
831
|
+
resolve();
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
window.addEventListener("hashchange", fnWaitChange);
|
|
836
|
+
});
|
|
837
|
+
},
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Shows a browser-popup for the user to confirm that they want to discard their changes.
|
|
841
|
+
* @returns {boolean} True if the popup has been confirmed by the user, otherwise false.
|
|
842
|
+
*
|
|
843
|
+
* @private
|
|
844
|
+
* @since 1.86.0
|
|
845
|
+
*/
|
|
846
|
+
_handleDirtyStateUserConfirm: function () {
|
|
847
|
+
Log.debug(`${sLogFesrPrefix} Interaction Start`, "_handleDirtyStateUserConfirm", sModuleName);
|
|
848
|
+
const fnResolveInteraction = Interaction.notifyAsyncStep();
|
|
849
|
+
|
|
850
|
+
// eslint-disable-next-line no-alert
|
|
851
|
+
if (window.confirm(ushellResources.i18n.getText("dataLossInternalMessage"))) {
|
|
852
|
+
sap.ushell.Container.setDirtyFlag(false);
|
|
853
|
+
if (RelatedServices.isBackNavigation() === true) {
|
|
854
|
+
RelatedServices.resetBackNavigationFlag();
|
|
855
|
+
}
|
|
856
|
+
Log.debug(`${sLogFesrPrefix} Interaction End`, "_handleDirtyStateUserConfirm", sModuleName);
|
|
857
|
+
fnResolveInteraction();
|
|
858
|
+
|
|
859
|
+
bPreviousPageDirty = true;
|
|
860
|
+
return true;
|
|
861
|
+
}
|
|
862
|
+
Log.debug(`${sLogFesrPrefix} Interaction End`, "_handleDirtyStateUserConfirm", sModuleName);
|
|
863
|
+
fnResolveInteraction();
|
|
864
|
+
|
|
865
|
+
return false;
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Undoes or redoes navigation. Restores the previous or next hash and the navigation history that lead to it.
|
|
870
|
+
*
|
|
871
|
+
* @param {string} sHash The old hash that should be reset.
|
|
872
|
+
* @param {string} sAction Whether a 'redo' or 'undo' action is to be performed.
|
|
873
|
+
* @returns {object} The navigation filter status.
|
|
874
|
+
* @since 1.86.0
|
|
875
|
+
* @private
|
|
876
|
+
*/
|
|
877
|
+
_restoreHashUsingAction: function (sHash, sAction) {
|
|
878
|
+
var bWasHistoryEntryReplaced = this.oShellNavigation.wasHistoryEntryReplaced();
|
|
879
|
+
var oRestoreStrategy = this._getRestoreHashStrategy(bWasHistoryEntryReplaced, sAction);
|
|
880
|
+
|
|
881
|
+
this._resumeAppRouterIgnoringCurrentHash();
|
|
882
|
+
|
|
883
|
+
return this._restoreHash(oRestoreStrategy, sHash);
|
|
884
|
+
},
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Decides the strategy to use when restoring an old hash in an attempt to undo a forward or a backward navigation.
|
|
888
|
+
* This method is mostly used for data loss handling, after a user confirmed that they want to stay in the current application.
|
|
889
|
+
*
|
|
890
|
+
* @param {boolean} bNavToReplacedHash Whether the last navigation had replaced the history without adding a new entry.
|
|
891
|
+
* @param {string} sAction The action to be carried out.
|
|
892
|
+
* @returns {object} The strategy to use to restore the previous shell hash which is one of:
|
|
893
|
+
* "historyBack", "replaceHash", "historyForward" and the number of steps to restore the hash.
|
|
894
|
+
*/
|
|
895
|
+
_getRestoreHashStrategy: function (bNavToReplacedHash, sAction) {
|
|
896
|
+
/**
|
|
897
|
+
* The bNavToReplacedHash needs to be checked first because the iHistoryStateOffset is undefined when:
|
|
898
|
+
* * hash is replaced
|
|
899
|
+
* * new hash is given
|
|
900
|
+
* * in browser where history pushState isn't fully supported
|
|
901
|
+
*/
|
|
902
|
+
if (bNavToReplacedHash) {
|
|
903
|
+
return {
|
|
904
|
+
strategy: "replaceHash",
|
|
905
|
+
stepCount: 0
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// This is a workaround:
|
|
910
|
+
// Notifying the UI5 history via the hashChanged event triggers unwanted navigation.
|
|
911
|
+
// But without the notify the offset gets out of sync with the current state and stacks up.
|
|
912
|
+
// We are now assuming that we only do (and undo) single navigation steps
|
|
913
|
+
var sStrategy;
|
|
914
|
+
var iHistoryStateOffset = Ui5History.getInstance().getHistoryStateOffset();
|
|
915
|
+
if (iHistoryStateOffset === undefined || iHistoryStateOffset >= 0) {
|
|
916
|
+
// Forward
|
|
917
|
+
iHistoryStateOffset = 1;
|
|
918
|
+
} else if (iHistoryStateOffset < 0) {
|
|
919
|
+
// Backward
|
|
920
|
+
iHistoryStateOffset = -1;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// If the history offset exists, we use the absolute value because later we use dedicated functions like _windowHistoryBack
|
|
924
|
+
// and _windowHistoryForward for back- and forwards navigation, respectively.
|
|
925
|
+
// Calling either of those function with a negative value would yield the exact opposite.
|
|
926
|
+
// TODO: Actually, we could refactor this to call history.go directly, so we don't have to transform it.
|
|
927
|
+
|
|
928
|
+
if (sAction === "undo") {
|
|
929
|
+
if (iHistoryStateOffset < 0) {
|
|
930
|
+
// Went backwards
|
|
931
|
+
sStrategy = "historyForward";
|
|
932
|
+
} else {
|
|
933
|
+
// Went forwards
|
|
934
|
+
sStrategy = "historyBack";
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
this.sLastUndoStrategy = sStrategy;
|
|
938
|
+
} else {
|
|
939
|
+
switch (this.sLastUndoStrategy) {
|
|
940
|
+
case "historyBack":
|
|
941
|
+
sStrategy = "historyForward";
|
|
942
|
+
break;
|
|
943
|
+
case "historyForward":
|
|
944
|
+
sStrategy = "historyBack";
|
|
945
|
+
break;
|
|
946
|
+
default:
|
|
947
|
+
sStrategy = "replaceHash";
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
return {
|
|
952
|
+
strategy: sStrategy,
|
|
953
|
+
stepCount: 1
|
|
954
|
+
};
|
|
955
|
+
},
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Restores the previous or next hash using the given restore-strategy.
|
|
959
|
+
* If the restore strategy is 'replaceHash', the given hash is used.
|
|
960
|
+
*
|
|
961
|
+
* @param {object} oRestoreStrategy A restore strategy containing a strategy such as 'historyBack', 'historyForward' or 'replaceHash'.
|
|
962
|
+
* @param {string} sHash A hash without hash sign to be set if the 'replaceHash' strategy is to be used.
|
|
963
|
+
* @returns {object} The Custom navigation filter status.
|
|
964
|
+
* @throws If the given restore strategy is not recognized.
|
|
965
|
+
* @private
|
|
966
|
+
*/
|
|
967
|
+
_restoreHash: function (oRestoreStrategy, sHash) {
|
|
968
|
+
var oNavigationFilterStatus = {
|
|
969
|
+
status: this.oShellNavigation.NavigationFilterStatus.Custom,
|
|
970
|
+
hash: ""
|
|
971
|
+
};
|
|
972
|
+
switch (oRestoreStrategy.strategy) {
|
|
973
|
+
case "historyBack":
|
|
974
|
+
this.bEnableHashChange = false;
|
|
975
|
+
this._windowHistoryBack(oRestoreStrategy.stepCount);
|
|
976
|
+
break;
|
|
977
|
+
case "historyForward":
|
|
978
|
+
this.bEnableHashChange = false;
|
|
979
|
+
this._windowHistoryForward(oRestoreStrategy.stepCount);
|
|
980
|
+
break;
|
|
981
|
+
case "replaceHash":
|
|
982
|
+
this.bEnableHashChange = false;
|
|
983
|
+
hasher.replaceHash(sHash);
|
|
984
|
+
break;
|
|
985
|
+
default:
|
|
986
|
+
throw new Error("Cannot execute unknown navigation strategy");
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
return oNavigationFilterStatus;
|
|
990
|
+
},
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* Checks whether an application is cold started.
|
|
994
|
+
* This method is scoped to checking the cold start conditions of applications only.
|
|
995
|
+
*
|
|
996
|
+
* A cold start state occurs whenever the user has previously opened the window.
|
|
997
|
+
*
|
|
998
|
+
* - page is refreshed
|
|
999
|
+
* - URL is pasted in a new window
|
|
1000
|
+
* - user opens the page and pastes a URL
|
|
1001
|
+
*
|
|
1002
|
+
* @returns {boolean} whether the application is in a cold start state
|
|
1003
|
+
*/
|
|
1004
|
+
_isColdStart: function () {
|
|
1005
|
+
var oRenderer = sap.ushell.Container.getRenderer("fiori2");
|
|
1006
|
+
var bNoCoreViewNavigated = !oRenderer || !oRenderer.getCurrentCoreView();
|
|
1007
|
+
if (this.history.getHistoryLength() <= 1 && bNoCoreViewNavigated) {
|
|
1008
|
+
return true;
|
|
1009
|
+
}
|
|
1010
|
+
this._isColdStart = function () {
|
|
1011
|
+
return false;
|
|
1012
|
+
};
|
|
1013
|
+
return false;
|
|
1014
|
+
},
|
|
1015
|
+
|
|
1016
|
+
_setEnableHashChange: function (bValue) {
|
|
1017
|
+
this.bEnableHashChange = bValue;
|
|
1018
|
+
},
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Triggers the app-usage mechanism to log an openApp action.
|
|
1022
|
+
*
|
|
1023
|
+
* @param {object} oRecentActivity An object containing details of a recently opened app
|
|
1024
|
+
* @returns {Promise} A promise that is resolved once the action is logged
|
|
1025
|
+
* @private
|
|
1026
|
+
*/
|
|
1027
|
+
_logRecentActivity: function (oRecentActivity) {
|
|
1028
|
+
// In a direct app start the logging happens before the user setting is loaded
|
|
1029
|
+
if (!this.oInitialEnableTrackingPromise) {
|
|
1030
|
+
// The initial value was overwritten by now
|
|
1031
|
+
if (Config.last("/core/shell/model/enableTrackingActivity") !== undefined) {
|
|
1032
|
+
this.oInitialEnableTrackingPromise = Promise.resolve();
|
|
1033
|
+
} else {
|
|
1034
|
+
this.oInitialEnableTrackingPromise = new Promise(function (resolve, reject) {
|
|
1035
|
+
Config.once("/core/shell/model/enableTrackingActivity").do(resolve);
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return this.oInitialEnableTrackingPromise.then(function () {
|
|
1041
|
+
if (Config.last("/core/shell/model/enableTrackingActivity")) {
|
|
1042
|
+
return new Promise(function (resolve, reject) {
|
|
1043
|
+
AppConfiguration.addActivity(oRecentActivity)
|
|
1044
|
+
.done(resolve)
|
|
1045
|
+
.fail(reject);
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
Log.warning("Tracking is not enabled", null, "sap.ushell.renderer.Shell.controller");
|
|
1049
|
+
return undefined;
|
|
1050
|
+
});
|
|
1051
|
+
},
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Sets application container based on information in URL hash.
|
|
1055
|
+
*
|
|
1056
|
+
* This is a callback registered with NavService. It's triggered whenever the url (or the hash fragment in the url) changes.
|
|
1057
|
+
*
|
|
1058
|
+
* NOTE: when this method is called, the new URL is already in the address bar of the browser.
|
|
1059
|
+
* Therefore back navigation is used to restore the URL in case of wrong navigation or errors.
|
|
1060
|
+
*
|
|
1061
|
+
* @param {string} sShellHash shell hash
|
|
1062
|
+
* @param {string} sAppPart application part
|
|
1063
|
+
* @param {string} sOldShellHash previous shell hash
|
|
1064
|
+
* @param {string} sOldAppPart previous application part
|
|
1065
|
+
* @param {object} oParseError parse error
|
|
1066
|
+
* @returns {Promise} promise
|
|
1067
|
+
* @public
|
|
1068
|
+
*/
|
|
1069
|
+
doHashChange: function (sShellHash, sAppPart, sOldShellHash, sOldAppPart, oParseError) {
|
|
1070
|
+
Log.debug(`${sLogFesrPrefix} Interaction Start`, "doHashChange", sModuleName);
|
|
1071
|
+
const fnResolveInteraction = Interaction.notifyAsyncStep();
|
|
1072
|
+
|
|
1073
|
+
//Performance Debug
|
|
1074
|
+
Measurement.start("FLP:ShellController.doHashChange", "doHashChange", "FLP");
|
|
1075
|
+
ushellUtils.setPerformanceMark("FLP-ShellController-doHashChange-begin");
|
|
1076
|
+
EventHub.emit("trackHashChange", sShellHash);
|
|
1077
|
+
|
|
1078
|
+
var oDashboard = Core.byId("sapUshellDashboardPage");
|
|
1079
|
+
if (oDashboard) {
|
|
1080
|
+
oDashboard.setBlocked(true);
|
|
1081
|
+
oDashboard.setBusy(true);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
return this._doHashChange(this, sShellHash, sAppPart, sOldShellHash, sOldAppPart, oParseError)
|
|
1085
|
+
.then(function () {
|
|
1086
|
+
Measurement.end("FLP:ShellController.doHashChange");
|
|
1087
|
+
|
|
1088
|
+
Log.debug(`${sLogFesrPrefix} Interaction End`, "doHashChange", sModuleName);
|
|
1089
|
+
fnResolveInteraction();
|
|
1090
|
+
}, function (vError) {
|
|
1091
|
+
Measurement.end("FLP:ShellController.doHashChange");
|
|
1092
|
+
EventHub.emit("doHashChangeError", Date.now());
|
|
1093
|
+
if (oDashboard) {
|
|
1094
|
+
oDashboard.setBlocked(false);
|
|
1095
|
+
oDashboard.setBusy(false);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
Log.debug(`${sLogFesrPrefix} Interaction End`, "doHashChange", sModuleName);
|
|
1099
|
+
fnResolveInteraction();
|
|
1100
|
+
});
|
|
1101
|
+
},
|
|
1102
|
+
|
|
1103
|
+
_doHashChange: function (oShellController, sShellHash, sAppPart, sOldShellHash, sOldAppPart, oParseError) {
|
|
1104
|
+
/*
|
|
1105
|
+
* reset here because the result of wasHistoryEntryReplaced is only useful in navigation filters
|
|
1106
|
+
* and might give inconsistent results after this point.
|
|
1107
|
+
*/
|
|
1108
|
+
this._wasHistoryEntryReplaced = this.oShellNavigation.wasHistoryEntryReplaced();
|
|
1109
|
+
this.oShellNavigation.resetHistoryEntryReplaced();
|
|
1110
|
+
var oInMemoryApplicationInstance;
|
|
1111
|
+
|
|
1112
|
+
if (!this.bEnableHashChange) {
|
|
1113
|
+
this.bEnableHashChange = true;
|
|
1114
|
+
return jQuery.when();
|
|
1115
|
+
}
|
|
1116
|
+
//When the application is opened in the new tab, the ShellHashEvent should be fired in order to update UI5 hasher,
|
|
1117
|
+
//but the application should not be resolved again.
|
|
1118
|
+
if (this.bRestorePreviousHash) {
|
|
1119
|
+
this.bRestorePreviousHash = false;
|
|
1120
|
+
return jQuery.when();
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
if (oParseError) {
|
|
1124
|
+
oShellController.hashChangeFailure(
|
|
1125
|
+
oShellController.history.getHistoryLength(),
|
|
1126
|
+
oParseError.message,
|
|
1127
|
+
null,
|
|
1128
|
+
"sap.ushell.renderer.Shell.controller",
|
|
1129
|
+
false
|
|
1130
|
+
);
|
|
1131
|
+
return jQuery.when();
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
var oDeferred = new jQuery.Deferred();
|
|
1135
|
+
|
|
1136
|
+
// save current history length to handle errors (in case)
|
|
1137
|
+
var iOriginalHistoryLength = oShellController.history.getHistoryLength();
|
|
1138
|
+
|
|
1139
|
+
var sFixedShellHash = oShellController.fixShellHash(sShellHash);
|
|
1140
|
+
var sOldFixedShellHash = oShellController.fixShellHash(sOldShellHash);
|
|
1141
|
+
|
|
1142
|
+
// track hash change
|
|
1143
|
+
oShellController.history.hashChange(sFixedShellHash, sOldShellHash);
|
|
1144
|
+
|
|
1145
|
+
// we save the current-application before resolving the next navigation's fragment,
|
|
1146
|
+
// as in cases of navigation in a new window we need to set it back for the app-configuration to be consistent
|
|
1147
|
+
oShellController.currentAppBeforeNav = AppConfiguration.getCurrentApplication();
|
|
1148
|
+
|
|
1149
|
+
oShellController._resolveHashFragment(sFixedShellHash)
|
|
1150
|
+
.then(function (oResolvedHashFragment, oParsedShellHash) {
|
|
1151
|
+
// NOTE: AppConfiguration.setCurrentApplication was called with the currently resolved target.
|
|
1152
|
+
|
|
1153
|
+
var sIntent = oParsedShellHash ? oParsedShellHash.semanticObject + "-" + oParsedShellHash.action : "";
|
|
1154
|
+
var oConfig = oShellController._getConfig();
|
|
1155
|
+
var bComponentLoaded = !!(oResolvedHashFragment && oResolvedHashFragment.componentHandle);
|
|
1156
|
+
// for SAPUI5 apps, the application type is still "URL" due to backwards compatibility, but the
|
|
1157
|
+
// NavTargetResolution service already extracts the component name, so this can directly be used as indicator
|
|
1158
|
+
var sTargetUi5ComponentName = oResolvedHashFragment && oResolvedHashFragment.ui5ComponentName;
|
|
1159
|
+
|
|
1160
|
+
// calculate effective Navigation Mode with resolution result and current Application,
|
|
1161
|
+
// we will determine the next navigation mode.
|
|
1162
|
+
oResolvedHashFragment = oShellController._calculateNavigationMode(oResolvedHashFragment);
|
|
1163
|
+
|
|
1164
|
+
oShellController._handleEarlyNavigation(sFixedShellHash, sAppPart, oResolvedHashFragment).then(function (bProcessed) {
|
|
1165
|
+
if (bProcessed !== true) {
|
|
1166
|
+
// add application config to the application properties
|
|
1167
|
+
if (oConfig && oConfig.applications && oConfig.applications[sIntent]) {
|
|
1168
|
+
oResolvedHashFragment.applicationConfiguration = oConfig.applications[sIntent];
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
oInMemoryApplicationInstance = AppLifeCycleAI.getInMemoryInstance(sIntent, sFixedShellHash, sAppPart, sOldShellHash);
|
|
1172
|
+
|
|
1173
|
+
if (oInMemoryApplicationInstance.isInstanceSupported) {
|
|
1174
|
+
oShellController._initiateApplication(oResolvedHashFragment, sFixedShellHash, oParsedShellHash, iOriginalHistoryLength, sAppPart, sOldFixedShellHash, sOldAppPart);
|
|
1175
|
+
oDeferred.resolve();
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
if (bComponentLoaded || !sTargetUi5ComponentName) {
|
|
1179
|
+
var oDeferredAppDestroy = new jQuery.Deferred();
|
|
1180
|
+
if ((oResolvedHashFragment.applicationType === "URL" || ushellUtils.isSAPLegacyApplicationType(oResolvedHashFragment.applicationType))
|
|
1181
|
+
&& oInMemoryApplicationInstance.isInstanceSupported === false && oInMemoryApplicationInstance.appId) {
|
|
1182
|
+
AppLifeCycleAI.destroyApplication(
|
|
1183
|
+
oInMemoryApplicationInstance.appId, oInMemoryApplicationInstance.container, oDeferredAppDestroy
|
|
1184
|
+
);
|
|
1185
|
+
} else {
|
|
1186
|
+
oDeferredAppDestroy.resolve();
|
|
1187
|
+
}
|
|
1188
|
+
oDeferredAppDestroy.done(function () {
|
|
1189
|
+
oShellController._initiateApplication(
|
|
1190
|
+
oResolvedHashFragment, sFixedShellHash, oParsedShellHash,
|
|
1191
|
+
iOriginalHistoryLength, sAppPart, sOldFixedShellHash, sOldAppPart
|
|
1192
|
+
);
|
|
1193
|
+
oDeferred.resolve();
|
|
1194
|
+
});
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
AppLifeCycleAI.destroyApplication(oInMemoryApplicationInstance.appId, oInMemoryApplicationInstance.container);
|
|
1198
|
+
AppLifeCycleAI.removeApplication(sIntent);
|
|
1199
|
+
AppConfiguration.setApplicationInInitMode();
|
|
1200
|
+
|
|
1201
|
+
// normal application:
|
|
1202
|
+
// fire the _prior.newUI5ComponentInstantion event before creating the new component instance, so that
|
|
1203
|
+
// the ApplicationContainer can stop the router of the current app (avoid inner-app hash change notifications)
|
|
1204
|
+
// NOTE: this dependency to the ApplicationContainer is not nice, but we need a fast fix now; we should refactor
|
|
1205
|
+
// the ApplicationContainer code, because most of the logic has to be done by the shell controller;
|
|
1206
|
+
// maybe rather introduce a utility module
|
|
1207
|
+
Core.getEventBus().publish("ApplicationContainer", "_prior.newUI5ComponentInstantion",
|
|
1208
|
+
{ name: sTargetUi5ComponentName }
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1211
|
+
//Performance Debug
|
|
1212
|
+
Measurement.start("FLP:ShellController.UI5createComponent", "UI5 createComponent", "FLP");
|
|
1213
|
+
// load ui5 component via shell service; core-ext-light will be loaded as part of the asyncHints
|
|
1214
|
+
|
|
1215
|
+
sap.ushell.Container.getServiceAsync("Ui5ComponentLoader").then(function () {
|
|
1216
|
+
AppLifeCycleAI.createComponent(oResolvedHashFragment, oParsedShellHash).done(function (/*oResolutionResultWithComponentHandle*/) {
|
|
1217
|
+
// `oResolutionResultWithComponentHandle` is unused.
|
|
1218
|
+
// This is because oResolvedHashFragment contains the component handle already.
|
|
1219
|
+
// See the preceding note in AppLifeCycle.createComponent.
|
|
1220
|
+
Measurement.end("FLP:ShellController.UI5createComponent");
|
|
1221
|
+
oShellController._initiateApplication(oResolvedHashFragment, sFixedShellHash, oParsedShellHash, iOriginalHistoryLength, sAppPart, sOldFixedShellHash, sOldAppPart);
|
|
1222
|
+
}).fail(function (vError) {
|
|
1223
|
+
var sErrorReason = ushellResources.i18n.getText("cannot_load_ui5_component_details", [sFixedShellHash]);
|
|
1224
|
+
var sErrorReasonEnglish = "Failed to load UI5 component for navigation intent " + sFixedShellHash;
|
|
1225
|
+
|
|
1226
|
+
AppConfiguration.setCurrentApplication(oShellController.currentAppBeforeNav);
|
|
1227
|
+
oShellController.hashChangeFailure(
|
|
1228
|
+
iOriginalHistoryLength,
|
|
1229
|
+
{
|
|
1230
|
+
title: ushellResources.i18n.getText("error"),
|
|
1231
|
+
message: ushellResources.i18n.getText("failed_to_open_ui5_component"),
|
|
1232
|
+
technicalMessage: sErrorReasonEnglish
|
|
1233
|
+
}, {
|
|
1234
|
+
info: sErrorReason,
|
|
1235
|
+
technicalMessage: vError.message + "\n" + vError.stack
|
|
1236
|
+
},
|
|
1237
|
+
"sap.ushell.renderer.Shell.controller",
|
|
1238
|
+
false);
|
|
1239
|
+
});
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
oDeferred.resolve();
|
|
1243
|
+
});
|
|
1244
|
+
}, function (sMsg) {
|
|
1245
|
+
var sErrorReason = ushellResources.i18n.getText("cannot_resolve_navigation_target_details", [sFixedShellHash]);
|
|
1246
|
+
var sErrorReasonEnglish = "Failed to resolve navigation target: " + sFixedShellHash
|
|
1247
|
+
+ ". This is most likely caused by an incorrect SAP Fiori launchpad content configuration or by missing role assignment.";
|
|
1248
|
+
|
|
1249
|
+
oShellController.hashChangeFailure(
|
|
1250
|
+
iOriginalHistoryLength,
|
|
1251
|
+
{
|
|
1252
|
+
title: ushellResources.i18n.getText("error"),
|
|
1253
|
+
message: ushellResources.i18n.getText("failed_to_open_app_missing_configuration_or_role_assignment"),
|
|
1254
|
+
technicalMessage: sErrorReasonEnglish
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
info: sErrorReason,
|
|
1258
|
+
fixedShellHash: sFixedShellHash,
|
|
1259
|
+
technicalMessage: sMsg
|
|
1260
|
+
},
|
|
1261
|
+
"sap.ushell.renderer.Shell.controller",
|
|
1262
|
+
false);
|
|
1263
|
+
|
|
1264
|
+
oDeferred.reject(sErrorReasonEnglish);
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
return oDeferred.promise();
|
|
1268
|
+
},
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Attempts to navigate to the target application via a shortcut,
|
|
1272
|
+
* without executing unnecessary AppLifeCycle navigation logic (e.g.,
|
|
1273
|
+
* application component initialization).
|
|
1274
|
+
*
|
|
1275
|
+
* This might be necessary when the navigation should not be handled in
|
|
1276
|
+
* the current window context anymore, for example, when the
|
|
1277
|
+
* application should be opened in a new window, or NWBC takes over the
|
|
1278
|
+
* navigation task.
|
|
1279
|
+
*
|
|
1280
|
+
* @param {string} sFixedShellHash
|
|
1281
|
+
* The hash fragment including "#"
|
|
1282
|
+
* @param {string} sAppPart
|
|
1283
|
+
* The inner app route part of the intent
|
|
1284
|
+
* @param {object} oResolvedHashFragment
|
|
1285
|
+
* The resolved target intent
|
|
1286
|
+
*
|
|
1287
|
+
* @returns {undefined} Nothing
|
|
1288
|
+
* @private
|
|
1289
|
+
*/
|
|
1290
|
+
_handleEarlyNavigation: function (sFixedShellHash, sAppPart, oResolvedHashFragment) {
|
|
1291
|
+
var that = this;
|
|
1292
|
+
var oDashboard;
|
|
1293
|
+
|
|
1294
|
+
return new Promise(function (fnResolve) {
|
|
1295
|
+
that._openAppViaNWBC(oResolvedHashFragment).then(function (bOpenedViaNWBC) {
|
|
1296
|
+
if (bOpenedViaNWBC === true) {
|
|
1297
|
+
oResolvedHashFragment.sFixedShellHash = sFixedShellHash;
|
|
1298
|
+
that.logOpenAppAction(oResolvedHashFragment, sAppPart);
|
|
1299
|
+
oDashboard = Core.byId("sapUshellDashboardPage");
|
|
1300
|
+
if (oDashboard) {
|
|
1301
|
+
oDashboard.setBlocked(false);
|
|
1302
|
+
oDashboard.setBusy(false);
|
|
1303
|
+
}
|
|
1304
|
+
fnResolve(true);
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
var bNewWindowNavigation = oResolvedHashFragment
|
|
1309
|
+
&& oResolvedHashFragment.navigationMode === oNavigationMode.newWindow;
|
|
1310
|
+
if (bNewWindowNavigation) {
|
|
1311
|
+
// add the app to application usage log
|
|
1312
|
+
oResolvedHashFragment.sFixedShellHash = sFixedShellHash;
|
|
1313
|
+
that.logOpenAppAction(oResolvedHashFragment, sAppPart);
|
|
1314
|
+
sap.ui.require(["sap/ushell/components/container/ApplicationContainer"], function (ApplicationContainer) {
|
|
1315
|
+
oResolvedHashFragment.url = ApplicationContainer.prototype._checkNwbcUrlAdjustment(undefined, oResolvedHashFragment.applicationType, oResolvedHashFragment.url, true);
|
|
1316
|
+
that._openAppInNewWindowAndRestore(oResolvedHashFragment);
|
|
1317
|
+
oDashboard = Core.byId("sapUshellDashboardPage");
|
|
1318
|
+
if (oDashboard) {
|
|
1319
|
+
oDashboard.setBlocked(false);
|
|
1320
|
+
oDashboard.setBusy(false);
|
|
1321
|
+
}
|
|
1322
|
+
fnResolve(true);
|
|
1323
|
+
});
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// Close dialogs only for inplace navigation
|
|
1328
|
+
if (InstanceManager && closeAllDialogs) {
|
|
1329
|
+
InstanceManager.closeAllDialogs();
|
|
1330
|
+
InstanceManager.closeAllPopovers();
|
|
1331
|
+
}
|
|
1332
|
+
closeAllDialogs = true;
|
|
1333
|
+
|
|
1334
|
+
// In case of empty hash, if there is a resolved target, set the flag to false, from now on the rootIntent
|
|
1335
|
+
// will be an empty hash. Otherwise, change hash to rootIntent to trigger normal resolution.
|
|
1336
|
+
if (Config.last("/core/shell/model/migrationConfig")) {
|
|
1337
|
+
oConfig.migrationConfig = false;
|
|
1338
|
+
that.getModel().setProperty("/migrationConfig", false);
|
|
1339
|
+
|
|
1340
|
+
if (oResolvedHashFragment && sFixedShellHash === "#") {
|
|
1341
|
+
oConfig.rootIntent = "";
|
|
1342
|
+
} else if (sFixedShellHash === "#") {
|
|
1343
|
+
window.setTimeout(function () {
|
|
1344
|
+
window.hasher.setHash(oConfig.rootIntent);
|
|
1345
|
+
}, 0);
|
|
1346
|
+
fnResolve(true);
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
fnResolve(false);
|
|
1352
|
+
return;
|
|
1353
|
+
});
|
|
1354
|
+
});
|
|
1355
|
+
},
|
|
1356
|
+
|
|
1357
|
+
_initiateApplication: function (oResolvedHashFragment, sFixedShellHash, oParsedShellHash, iOriginalHistoryLength, sAppPart, sOldFixedShellHash, sOldAppPart) {
|
|
1358
|
+
Measurement.start("FLP:ShellController._initiateApplication", "_initiateApplication", "FLP");
|
|
1359
|
+
|
|
1360
|
+
var oMetadata = AppConfiguration.getMetadata(oResolvedHashFragment);
|
|
1361
|
+
var bContactSupportEnabled = Config.last("/core/extension/SupportTicket");
|
|
1362
|
+
var bPreviousIsInitialNavigation;
|
|
1363
|
+
|
|
1364
|
+
// the "if" should protect against undefined, empty string and null
|
|
1365
|
+
if (oMetadata.title) {
|
|
1366
|
+
window.document.title = oMetadata.title;
|
|
1367
|
+
} else {
|
|
1368
|
+
// FIXME: Remove title so that users don't think it's a bug
|
|
1369
|
+
Log.debug("Shell controller._initiateApplication: the title of the window is not changed because most probably the application was resolved with undefined");
|
|
1370
|
+
}
|
|
1371
|
+
// the activation of user activity logging must be done after the app component is fully loaded
|
|
1372
|
+
// otherwise the module loading sequence causes race conditions on firefox
|
|
1373
|
+
if (bContactSupportEnabled) {
|
|
1374
|
+
window.setTimeout(function () {
|
|
1375
|
+
UserActivityLog.activate();
|
|
1376
|
+
}, 0);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
try {
|
|
1380
|
+
bPreviousIsInitialNavigation = this.oShellNavigation.isInitialNavigation();
|
|
1381
|
+
this.navigate(oParsedShellHash, sFixedShellHash, oMetadata, oResolvedHashFragment, sOldFixedShellHash);
|
|
1382
|
+
} catch (oExc) {
|
|
1383
|
+
if (oExc.stack) {
|
|
1384
|
+
Log.error("Application initialization (Intent: \n" + sFixedShellHash + "\n failed due to an Exception:\n" + oExc.stack);
|
|
1385
|
+
}
|
|
1386
|
+
this.oShellNavigation.setIsInitialNavigation(bPreviousIsInitialNavigation);
|
|
1387
|
+
this.hashChangeFailure(iOriginalHistoryLength, oExc.name, oExc.message, oMetadata ? oMetadata.title : "", false);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
Measurement.end("FLP:ShellController._initiateApplication");
|
|
1391
|
+
},
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Callback registered with NavService. Triggered on navigation requests
|
|
1395
|
+
*
|
|
1396
|
+
* @param {string} sShellHash the hash fragment to parse (must start with "#")
|
|
1397
|
+
* @returns {jQuery.Deferred.promise} a promise resolved with an object containing the resolved hash fragment (i.e., the result of
|
|
1398
|
+
* {@link sap.ushell.services.NavTargetResolution#resolveHashFragment}), the parsed shell hash obtained via
|
|
1399
|
+
* {@link sap.ushell.services.URLParsing#parseShellHash}, and a boolean value indicating whether application dependencies
|
|
1400
|
+
* <b>and</b> core-ext-light were loaded earlier. The promise is rejected with an error message in case errors occur.
|
|
1401
|
+
*/
|
|
1402
|
+
_resolveHashFragment: function (sShellHash) {
|
|
1403
|
+
//Performance Debug
|
|
1404
|
+
Measurement.start("FLP:ShellController._resolveHashFragment", "_resolveHashFragment", "FLP");
|
|
1405
|
+
var oParsedShellHash = this.oURLParsing.parseShellHash(sShellHash);
|
|
1406
|
+
var oDeferred = new jQuery.Deferred();
|
|
1407
|
+
var oConfig = this._getConfig(); // for testing
|
|
1408
|
+
|
|
1409
|
+
// Check and use resolved hash fragment from direct start promise if it's there
|
|
1410
|
+
if (window["sap-ushell-async-libs-promise-directstart"]) {
|
|
1411
|
+
window["sap-ushell-async-libs-promise-directstart"]
|
|
1412
|
+
.then(function (oDirectstartPromiseResult) {
|
|
1413
|
+
oDeferred.resolve(
|
|
1414
|
+
oDirectstartPromiseResult.resolvedHashFragment,
|
|
1415
|
+
oParsedShellHash
|
|
1416
|
+
);
|
|
1417
|
+
delete window["sap-ushell-async-libs-promise-directstart"];
|
|
1418
|
+
},
|
|
1419
|
+
function (sMsg) {
|
|
1420
|
+
oDeferred.reject(sMsg);
|
|
1421
|
+
delete window["sap-ushell-async-libs-promise-directstart"];
|
|
1422
|
+
});
|
|
1423
|
+
return oDeferred.promise();
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// Perform target resolution as normal...
|
|
1427
|
+
sap.ushell.Container.getServiceAsync("NavTargetResolution").then(function (oNavTargetResolution) {
|
|
1428
|
+
oNavTargetResolution.resolveHashFragment(sShellHash)
|
|
1429
|
+
.done(function (oResolvedHashFragment) {
|
|
1430
|
+
//@FIXME: Should be also executed for directstart
|
|
1431
|
+
AppConfiguration.setCurrentApplication(oResolvedHashFragment);
|
|
1432
|
+
/*
|
|
1433
|
+
* Override navigation mode for root intent.
|
|
1434
|
+
* Shell home should be opened in embedded mode to allow a new window to be opened from GUI applications.
|
|
1435
|
+
*/
|
|
1436
|
+
if (oParsedShellHash && (oParsedShellHash.semanticObject + "-" + oParsedShellHash.action) === oConfig.rootIntent) {
|
|
1437
|
+
oResolvedHashFragment.navigationMode = "embedded";
|
|
1438
|
+
}
|
|
1439
|
+
Measurement.end("FLP:ShellController._resolveHashFragment");
|
|
1440
|
+
ushellUtils.setPerformanceMark("FLP-ShellController-resolveHashFragment-end");
|
|
1441
|
+
oDeferred.resolve(oResolvedHashFragment, oParsedShellHash);
|
|
1442
|
+
})
|
|
1443
|
+
.fail(function (sMsg) {
|
|
1444
|
+
oDeferred.reject(sMsg);
|
|
1445
|
+
});
|
|
1446
|
+
});
|
|
1447
|
+
return oDeferred.promise();
|
|
1448
|
+
},
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* Adjust Navigation mode based on current state of the Shell and application and the ResolveHashFragment bo be started
|
|
1452
|
+
*
|
|
1453
|
+
* This operation mutates oResolvedHashFragment
|
|
1454
|
+
*
|
|
1455
|
+
* {@link #navigate}.
|
|
1456
|
+
*
|
|
1457
|
+
* @param {object} oResolvedHashFragment the hash fragment resolved via {@link sap.ushell.services.NavTargetResolution#resolveHashFragment}
|
|
1458
|
+
* @returns {object} a new, potentially altered resolution result. Note that url and navigation mode may have been changed!
|
|
1459
|
+
* For navigation in new window, the URL is replaced with the current location hash.
|
|
1460
|
+
* NOTE: refactor this; we should not have these implicit changes of the navigation target
|
|
1461
|
+
* @private
|
|
1462
|
+
*/
|
|
1463
|
+
_calculateNavigationMode: function (oResolvedHashFragment) {
|
|
1464
|
+
if (!oResolvedHashFragment) {
|
|
1465
|
+
return undefined; // happens in tests
|
|
1466
|
+
}
|
|
1467
|
+
var sNavigationMode = oResolvedHashFragment.navigationMode;
|
|
1468
|
+
|
|
1469
|
+
if (sNavigationMode === oNavigationMode.newWindowThenEmbedded) {
|
|
1470
|
+
// Implement newWindowThenEmbedded based on current state.
|
|
1471
|
+
if (this._isColdStart() || Ui5History.getInstance().getDirection() === Ui5HistoryDirection.Backwards) {
|
|
1472
|
+
/*
|
|
1473
|
+
* cold start
|
|
1474
|
+
* -> always open in place because the new window was opened by the user
|
|
1475
|
+
*
|
|
1476
|
+
* Ui5History.getInstance().getDirection()
|
|
1477
|
+
* -> URL has already been navigated to and it was the predecessor of the previous page
|
|
1478
|
+
*/
|
|
1479
|
+
oResolvedHashFragment.navigationMode = oNavigationMode.embedded;
|
|
1480
|
+
} else {
|
|
1481
|
+
oResolvedHashFragment.navigationMode = oNavigationMode.newWindow;
|
|
1482
|
+
// if its a non-native navigation, we resolve the hash again in the new window
|
|
1483
|
+
// we set the full current location hash as URL for the new window as it is
|
|
1484
|
+
// for avoiding encoding issues and stripping off parameters or inner-app route
|
|
1485
|
+
// see internal BCP 1770274241
|
|
1486
|
+
if (!ushellUtils.isNativeWebGuiNavigation(oResolvedHashFragment)) {
|
|
1487
|
+
oResolvedHashFragment.url = this._getCurrentLocationHash();
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
return oResolvedHashFragment;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
if (sNavigationMode === oNavigationMode.newWindow && this._isColdStart()) {
|
|
1494
|
+
// Workaround for URLs that start an FLP app which needs the shell.
|
|
1495
|
+
if (this._hasAppCapabilitiesNavigationMode(oResolvedHashFragment)
|
|
1496
|
+
&& oResolvedHashFragment.appCapabilities.navigationMode === oNavigationMode.embedded) {
|
|
1497
|
+
oResolvedHashFragment.navigationMode = oNavigationMode.embedded;
|
|
1498
|
+
return oResolvedHashFragment;
|
|
1499
|
+
}
|
|
1500
|
+
// Replace the content of the current window if the user has already opened one.
|
|
1501
|
+
oResolvedHashFragment.navigationMode = oNavigationMode.replace;
|
|
1502
|
+
return oResolvedHashFragment;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
if (sNavigationMode === oNavigationMode.newWindow
|
|
1506
|
+
&& this._hasAppCapabilitiesNavigationMode(oResolvedHashFragment)
|
|
1507
|
+
&& oResolvedHashFragment.appCapabilities.navigationMode === oNavigationMode.embedded) {
|
|
1508
|
+
oResolvedHashFragment.url = this._getCurrentLocationHash();
|
|
1509
|
+
}
|
|
1510
|
+
return oResolvedHashFragment;
|
|
1511
|
+
},
|
|
1512
|
+
|
|
1513
|
+
// Workaround for URLs that start an FLP app which needs the shell.
|
|
1514
|
+
_hasAppCapabilitiesNavigationMode: function (oResolvedHashFragment) {
|
|
1515
|
+
return ushellUtils.isPlainObject(oResolvedHashFragment.appCapabilities) && oResolvedHashFragment.appCapabilities.hasOwnProperty("navigationMode");
|
|
1516
|
+
},
|
|
1517
|
+
|
|
1518
|
+
_usesNavigationRedirect: function (oComponentHandle) {
|
|
1519
|
+
if (!oComponentHandle) {
|
|
1520
|
+
return new jQuery.Deferred().reject().promise();
|
|
1521
|
+
}
|
|
1522
|
+
var that = this;
|
|
1523
|
+
var oComponent = oComponentHandle.getInstance({});
|
|
1524
|
+
if (oComponent && typeof oComponent.navigationRedirect === "function") {
|
|
1525
|
+
// oComponent refers to a trampoline application
|
|
1526
|
+
var oDeferred = new jQuery.Deferred();
|
|
1527
|
+
var oNavRedirectPromise = oComponent.navigationRedirect();
|
|
1528
|
+
if (oNavRedirectPromise && (typeof oNavRedirectPromise.then === "function")) {
|
|
1529
|
+
oNavRedirectPromise.then(function (sNextHash) {
|
|
1530
|
+
Log.warning("Performing navigation redirect to hash " + sNextHash);
|
|
1531
|
+
oComponent.destroy();
|
|
1532
|
+
that.history.pop();
|
|
1533
|
+
sap.ushell.Container.getServiceAsync("ShellNavigation").then(function (oShellNavigation) {
|
|
1534
|
+
oShellNavigation.toExternal({ target: { shellHash: sNextHash } }, undefined, false);
|
|
1535
|
+
oDeferred.resolve(true);
|
|
1536
|
+
});
|
|
1537
|
+
}, function () {
|
|
1538
|
+
oDeferred.reject();
|
|
1539
|
+
});
|
|
1540
|
+
return oDeferred.promise();
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
return new jQuery.Deferred().reject().promise();
|
|
1544
|
+
},
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* Performs navigation based on the given resolved hash fragment.
|
|
1548
|
+
*
|
|
1549
|
+
* @param {object} oParsedShellHash the parsed shell hash obtained via {@link sap.ushell.services.URLParsing} service
|
|
1550
|
+
* @param {string} sFixedShellHash the hash fragment to navigate to. It must start with "#" (i.e., fixed).
|
|
1551
|
+
* @param {object} oMetadata the metadata object obtained via {@link sap.ushell.services.AppConfiguration#parseShellHash}
|
|
1552
|
+
* @param {object} oResolvedHashFragment the hash fragment resolved via {@link sap.ushell.services.NavTargetResolution#resolveHashFragment}
|
|
1553
|
+
*
|
|
1554
|
+
* @returns {Promise} Navigation Promise
|
|
1555
|
+
*/
|
|
1556
|
+
navigate: function (oParsedShellHash, sFixedShellHash, oMetadata, oResolvedHashFragment, sOldFixedShellHash) {
|
|
1557
|
+
//Performance Debug
|
|
1558
|
+
Measurement.start("FLP:ShellController.navigate", "navigate", "FLP");
|
|
1559
|
+
var sNavigationMode = (isPlainObject(oResolvedHashFragment) ? oResolvedHashFragment.navigationMode : null);
|
|
1560
|
+
var that = this;
|
|
1561
|
+
|
|
1562
|
+
/*
|
|
1563
|
+
* A null navigationMode is a no-op, it indicates no navigation should occur.
|
|
1564
|
+
* However, we need to restore the current hash to the previous one.
|
|
1565
|
+
* If cold start happened (history has only one entry), we go to the shell home.
|
|
1566
|
+
*/
|
|
1567
|
+
if (sNavigationMode === null) {
|
|
1568
|
+
if (this._isColdStart()) {
|
|
1569
|
+
window.hasher.setHash("");
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
this.bEnableHashChange = false;
|
|
1574
|
+
this.history.pop();
|
|
1575
|
+
this._windowHistoryBack(1);
|
|
1576
|
+
return Promise.resolve();
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
oResolvedHashFragment = this._calculateNavigationMode(oResolvedHashFragment);
|
|
1580
|
+
sNavigationMode = (isPlainObject(oResolvedHashFragment) ? oResolvedHashFragment.navigationMode : null);
|
|
1581
|
+
|
|
1582
|
+
if (!sNavigationMode) {
|
|
1583
|
+
Log.error(
|
|
1584
|
+
"Mandatory member 'navigationMode' is missing in the resolution result! Temporarily set to 'embedded' for further processing...",
|
|
1585
|
+
"sap.ushell.renderer.Shell.controller"
|
|
1586
|
+
);
|
|
1587
|
+
sNavigationMode = "embedded";
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
if (sNavigationMode === oNavigationMode.embedded) {
|
|
1591
|
+
if (!this._isColdStart() && !this._wasHistoryEntryReplaced) {
|
|
1592
|
+
this.oShellNavigation.setIsInitialNavigation(false);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
var oDeferred = this._usesNavigationRedirect(oResolvedHashFragment.componentHandle);
|
|
1596
|
+
var oNavigationPromise = new Promise(function (resolve, reject) {
|
|
1597
|
+
// When `oDeferred` succeeds, it implies the component references a trampoline application.
|
|
1598
|
+
// The trampoline application subsequently gets destroyed after it's used to enable the redirection.
|
|
1599
|
+
// The failure is being used here as a means for branching in the execution flow.
|
|
1600
|
+
oDeferred.then(null, function () {
|
|
1601
|
+
that._handleEmbeddedNavMode(sFixedShellHash, oParsedShellHash, oMetadata, oResolvedHashFragment, sOldFixedShellHash).then(function () {
|
|
1602
|
+
|
|
1603
|
+
//The event is used for FESR records
|
|
1604
|
+
//Normally FESR record is closed on the "AppRendered" event, but for some cases (stateful container, etc.)
|
|
1605
|
+
//the application container is not re-rendered and EmbeddedNavigationDone is additionally fired to close the record.
|
|
1606
|
+
EventHub.emit("CloseFesrRecord", { time: Date.now(), technicalName: oMetadata.technicalName });
|
|
1607
|
+
resolve();
|
|
1608
|
+
});
|
|
1609
|
+
});
|
|
1610
|
+
Measurement.end("FLP:ShellController.navigate");
|
|
1611
|
+
});
|
|
1612
|
+
|
|
1613
|
+
return oNavigationPromise;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
if (sNavigationMode === oNavigationMode.replace) {
|
|
1617
|
+
this.oShellNavigation.setIsInitialNavigation(false);
|
|
1618
|
+
// restore hash
|
|
1619
|
+
this.bEnableHashChange = false;
|
|
1620
|
+
this._changeWindowLocation(oResolvedHashFragment.url);
|
|
1621
|
+
return Promise.resolve();
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
if (sNavigationMode === oNavigationMode.newWindow) {
|
|
1625
|
+
this._openAppInNewWindowAndRestore(oResolvedHashFragment);
|
|
1626
|
+
return Promise.resolve();
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// the navigation mode doesn't match any valid one.
|
|
1630
|
+
// In this case an error message is logged and previous hash is fetched
|
|
1631
|
+
this.hashChangeFailure(this.history.getHistoryLength(), "Navigation mode is not recognized", null, "sap.ushell.renderer.Shell.controller", false);
|
|
1632
|
+
return Promise.resolve();
|
|
1633
|
+
},
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Attempts opening the application via NWBC.
|
|
1637
|
+
*
|
|
1638
|
+
* @param {object} oResolvedHashFragment
|
|
1639
|
+
* The resolved hash fragment
|
|
1640
|
+
* @returns {Promise}
|
|
1641
|
+
* Whether NWBC managed to open the application (resolved with either true or false)
|
|
1642
|
+
*
|
|
1643
|
+
* @private
|
|
1644
|
+
*/
|
|
1645
|
+
_openAppViaNWBC: function (oResolvedHashFragment) {
|
|
1646
|
+
var that = this;
|
|
1647
|
+
|
|
1648
|
+
return new Promise(function (fnResolve) {
|
|
1649
|
+
var bNwbcHandling;
|
|
1650
|
+
|
|
1651
|
+
if (oResolvedHashFragment && (ushellUtils.isNativeWebGuiNavigation(oResolvedHashFragment) || oResolvedHashFragment.nativeNWBCNavigation)) {
|
|
1652
|
+
bNwbcHandling = true;
|
|
1653
|
+
} else {
|
|
1654
|
+
bNwbcHandling = false;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
if (bNwbcHandling === false) {
|
|
1658
|
+
fnResolve(false);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
var oEPCM = ushellUtils.getPrivateEpcm();
|
|
1663
|
+
var iEPCMNavigationMode = oEPCMNavigationMode[oResolvedHashFragment.navigationMode];
|
|
1664
|
+
var sUrlWithSapUserAndShellParam;
|
|
1665
|
+
var iMode;
|
|
1666
|
+
|
|
1667
|
+
if (ushellUtils.hasNavigationModeCapability()) {
|
|
1668
|
+
iMode = iEPCMNavigationMode || oEPCMNavigationMode[oNavigationMode.embedded];
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
var oPromiseParams = that._appendUserIdToUrl("sap-user", oResolvedHashFragment.url).then(async function (sUrlWithSapUser) {
|
|
1672
|
+
sUrlWithSapUserAndShellParam = await ushellUtils.appendSapShellParam(sUrlWithSapUser);
|
|
1673
|
+
|
|
1674
|
+
return new Promise(function (fnResolveParams) {
|
|
1675
|
+
try {
|
|
1676
|
+
var sAppType = oResolvedHashFragment.applicationType;
|
|
1677
|
+
var sFrameworkId = (oResolvedHashFragment.appCapabilities && oResolvedHashFragment.appCapabilities.appFrameworkId);
|
|
1678
|
+
var oFLPParams = {};
|
|
1679
|
+
var aInfoArray = [];
|
|
1680
|
+
var aKeysArray;
|
|
1681
|
+
var fnPreparePostBodyParams = function () {
|
|
1682
|
+
oFLPParams["sap-flp-url"] = sap.ushell.Container.getFLPUrl(true);
|
|
1683
|
+
oFLPParams["system-alias"] = oResolvedHashFragment.systemAlias;
|
|
1684
|
+
return [{
|
|
1685
|
+
name: "sap-flp-params",
|
|
1686
|
+
value: JSON.stringify(oFLPParams)
|
|
1687
|
+
}];
|
|
1688
|
+
};
|
|
1689
|
+
var getParamKeys = function getParamKeys (sUrl, aInfoArray) {
|
|
1690
|
+
var aAppStateKeysArray = [];
|
|
1691
|
+
var fnAddKey = function (sName, sDataName) {
|
|
1692
|
+
if (sUrl.indexOf(sName + "=") > 0) {
|
|
1693
|
+
var aParams = new RegExp("(?:" + sName + "=)([^&/]+)").exec(sUrl);
|
|
1694
|
+
if (aParams && aParams.length === 2) {
|
|
1695
|
+
aAppStateKeysArray.push([aParams[1]]);
|
|
1696
|
+
aInfoArray.push(sDataName);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
|
|
1701
|
+
fnAddKey("sap-iapp-state", "sap-iapp-state-data");
|
|
1702
|
+
fnAddKey("sap-xapp-state", "sap-xapp-state-data");
|
|
1703
|
+
fnAddKey("sap-xapp-state-data", "sap-xapp-state-data");
|
|
1704
|
+
fnAddKey("sap-intent-param", "sap-intent-param-data");
|
|
1705
|
+
return aAppStateKeysArray;
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
if (ushellUtils.isSAPLegacyApplicationType(sAppType, sFrameworkId)) {
|
|
1709
|
+
sap.ushell.Container.getServiceAsync("Navigation").then(function (oCrossAppNavService) {
|
|
1710
|
+
aKeysArray = getParamKeys(sUrlWithSapUserAndShellParam, aInfoArray);
|
|
1711
|
+
if (aKeysArray.length > 0) {
|
|
1712
|
+
oCrossAppNavService.getAppStateData(aKeysArray).then(function (aDataArray) {
|
|
1713
|
+
aInfoArray.forEach(function (item, index) {
|
|
1714
|
+
if (aDataArray[index][0]) {
|
|
1715
|
+
oFLPParams[item] = aDataArray[index][0];
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
1718
|
+
fnResolveParams(fnPreparePostBodyParams());
|
|
1719
|
+
}, function (sError) {
|
|
1720
|
+
fnResolveParams();
|
|
1721
|
+
});
|
|
1722
|
+
} else {
|
|
1723
|
+
fnResolveParams(fnPreparePostBodyParams());
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
} else {
|
|
1727
|
+
fnResolveParams();
|
|
1728
|
+
}
|
|
1729
|
+
} catch (e) {
|
|
1730
|
+
//nothing to do, we will open the app without the post params as before
|
|
1731
|
+
fnResolveParams();
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
oPromiseParams.then(
|
|
1737
|
+
//the promise can not reject as we have to try to open the app
|
|
1738
|
+
function (oPostBodyParams) {
|
|
1739
|
+
try {
|
|
1740
|
+
Core.getEventBus().publish("launchpad", "appOpening", oResolvedHashFragment);
|
|
1741
|
+
if (!oEPCM.doNavigate(sUrlWithSapUserAndShellParam, iMode, undefined, undefined, undefined, undefined, undefined, oPostBodyParams)) {
|
|
1742
|
+
fnResolve(false);
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
Core.getEventBus().publish("sap.ushell", "appOpened", oResolvedHashFragment);
|
|
1746
|
+
|
|
1747
|
+
that._restoreAfterNwbcNavigation(oResolvedHashFragment).then(function () {
|
|
1748
|
+
/*
|
|
1749
|
+
TODO: This is a workaround.
|
|
1750
|
+
We should rather update the resolvedHashFragment before the navigation happens. Other Components listening
|
|
1751
|
+
to the appOpened event might rely on the correct navigationMode / targetNavigationMode of the
|
|
1752
|
+
resolvedHashFragment.
|
|
1753
|
+
*/
|
|
1754
|
+
// restore menu bar in case we are still on home
|
|
1755
|
+
if (that._oAppLifeCycleService.getCurrentApplication() && that._oAppLifeCycleService.getCurrentApplication().homePage) {
|
|
1756
|
+
that._setMenuVisible(true);
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
fnResolve(true);
|
|
1760
|
+
});
|
|
1761
|
+
} catch (e) {
|
|
1762
|
+
if (e.stack) {
|
|
1763
|
+
Log.error("Application initialization failed due to an Exception:\n" + e.stack);
|
|
1764
|
+
}
|
|
1765
|
+
that.hashChangeFailure(that.history.getHistoryLength(), e.name, e.message, oResolvedHashFragment.text, false);
|
|
1766
|
+
fnResolve(false);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
);
|
|
1770
|
+
});
|
|
1771
|
+
},
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
*
|
|
1775
|
+
* If a GUI application that was handled by NWBC was opened via deep link, a new tab is opened, which started the GUI.
|
|
1776
|
+
* Therefore, the current tab must navigate to the home page.
|
|
1777
|
+
*
|
|
1778
|
+
* In all other cases (non-deep link), it is sufficient
|
|
1779
|
+
* to navigate one step back in the browser history to restore the current hash.
|
|
1780
|
+
*
|
|
1781
|
+
* @param {object} oResolvedHashFragment The resolved hash fragment.
|
|
1782
|
+
* @returns {Promise} A Promise resolving when the hash is restored.
|
|
1783
|
+
* @private
|
|
1784
|
+
*/
|
|
1785
|
+
_restoreAfterNwbcNavigation: function (oResolvedHashFragment) {
|
|
1786
|
+
if (this.history.getHistoryLength() === 1 && !this._oAppLifeCycleService.getCurrentApplication()) {
|
|
1787
|
+
// Deep link case
|
|
1788
|
+
return sap.ushell.Container.getServiceAsync("Navigation").then(function (oNavigationService) {
|
|
1789
|
+
oNavigationService.navigate({ target: { shellHash: "#" }, writeHistory: false });
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// Regular case
|
|
1794
|
+
this._restorePreviousHashAfterOpenNewWindow(oResolvedHashFragment);
|
|
1795
|
+
return Promise.resolve();
|
|
1796
|
+
},
|
|
1797
|
+
|
|
1798
|
+
/**
|
|
1799
|
+
* Appends the ID of the user to the given URL.
|
|
1800
|
+
* The ID of the user is retrieved via the UserInfo service, and appended blindly to the given URL.
|
|
1801
|
+
* This method tries to detect whether a previous parameter was already appended
|
|
1802
|
+
* and use the <code>?</code> or <code>&</code> separator for the parameter accordingly.
|
|
1803
|
+
*
|
|
1804
|
+
* @param {string} sParamName The name of the parameter that needs to be appended.
|
|
1805
|
+
* @param {string} sUrl A URL with or without the sap-user parameter.
|
|
1806
|
+
* @returns {Promise<string>} The URL with the user id parameter appended.
|
|
1807
|
+
* @private
|
|
1808
|
+
*/
|
|
1809
|
+
_appendUserIdToUrl: function (sParamName, sUrl) {
|
|
1810
|
+
return sap.ushell.Container.getServiceAsync("UserInfo").then(function (oUserInfoService) {
|
|
1811
|
+
var sUserId = oUserInfoService.getUser().getId();
|
|
1812
|
+
var sSep = sUrl.indexOf("?") >= 0 ? "&" : "?";
|
|
1813
|
+
return sUrl + sSep + sParamName + "=" + sUserId;
|
|
1814
|
+
});
|
|
1815
|
+
},
|
|
1816
|
+
|
|
1817
|
+
/**
|
|
1818
|
+
* The method restore the previous hash when app is opened in the new tab
|
|
1819
|
+
* @param {*} oResolvedHashFragment resolved hash fragment
|
|
1820
|
+
*/
|
|
1821
|
+
_restorePreviousHashAfterOpenNewWindow: function (oResolvedHashFragment) {
|
|
1822
|
+
this.history.pop();
|
|
1823
|
+
var oVarInstance = oResolvedHashFragment.componentHandle && oResolvedHashFragment.componentHandle.getInstance
|
|
1824
|
+
&& oResolvedHashFragment.componentHandle.getInstance({});
|
|
1825
|
+
if (oVarInstance) {
|
|
1826
|
+
oVarInstance.destroy();
|
|
1827
|
+
}
|
|
1828
|
+
this._resumeAppRouterIgnoringCurrentHash();
|
|
1829
|
+
this.bRestorePreviousHash = true;
|
|
1830
|
+
this._windowHistoryBack(1);
|
|
1831
|
+
|
|
1832
|
+
// set back the current application to be the one before this navigation occurred as current application is opened in a new window
|
|
1833
|
+
AppConfiguration.setCurrentApplication(this.currentAppBeforeNav);
|
|
1834
|
+
EventHub.emit("openedAppInNewWindow", Date.now());
|
|
1835
|
+
},
|
|
1836
|
+
|
|
1837
|
+
_openAppInNewWindowAndRestore: function (oResolvedHashFragment) {
|
|
1838
|
+
Core.getEventBus().publish("launchpad", "appOpening", oResolvedHashFragment);
|
|
1839
|
+
this._openAppNewWindow(oResolvedHashFragment.url);
|
|
1840
|
+
Core.getEventBus().publish("sap.ushell", "appOpened", oResolvedHashFragment);
|
|
1841
|
+
this._restorePreviousHashAfterOpenNewWindow(oResolvedHashFragment);
|
|
1842
|
+
},
|
|
1843
|
+
|
|
1844
|
+
_handleEmbeddedNavMode: function (sFixedShellHash, oParsedShellHash, oMetadata, oResolvedHashFragment, sOldFixedShellHash) {
|
|
1845
|
+
// Performance Debug
|
|
1846
|
+
Measurement.start("FLP:ShellController._handleEmbeddedNavMode", "_handleEmbeddedNavMode", "FLP");
|
|
1847
|
+
var that = this,
|
|
1848
|
+
oConfig = this._getConfig();
|
|
1849
|
+
|
|
1850
|
+
this.resetShellUIServiceHandlers();
|
|
1851
|
+
|
|
1852
|
+
AppLifeCycleAI.getAppMeta().setAppIcons(oMetadata);
|
|
1853
|
+
|
|
1854
|
+
// obtain a unique id for the app (or the component)
|
|
1855
|
+
var sAppId = "-" + oParsedShellHash.semanticObject + "-" + oParsedShellHash.action;
|
|
1856
|
+
|
|
1857
|
+
var bIsNavToHome = sFixedShellHash === "#" ||
|
|
1858
|
+
(oConfig.rootIntent && ushellUtils.getBasicHash(oConfig.rootIntent) === oParsedShellHash.semanticObject + "-" + oParsedShellHash.action);
|
|
1859
|
+
|
|
1860
|
+
// Support migration from version 1.28 or lower in case local resolution for empty hash was used
|
|
1861
|
+
var sIntent = oParsedShellHash ? oParsedShellHash.semanticObject + "-" + oParsedShellHash.action : "";
|
|
1862
|
+
|
|
1863
|
+
AppLifeCycleAI.switchViewState(
|
|
1864
|
+
AppLifeCycleAI.shellElements().calculateElementsState(
|
|
1865
|
+
bIsNavToHome ? "home" : "app",
|
|
1866
|
+
oResolvedHashFragment.applicationType,
|
|
1867
|
+
oConfig.appState,
|
|
1868
|
+
oResolvedHashFragment.explicitNavMode
|
|
1869
|
+
),
|
|
1870
|
+
undefined,
|
|
1871
|
+
sAppId
|
|
1872
|
+
);
|
|
1873
|
+
|
|
1874
|
+
if (bIsNavToHome) {
|
|
1875
|
+
AppLifeCycleAI.getShellUIService().setBackNavigation();
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
// adding intent as this published application info is required for the contact-support scenario
|
|
1879
|
+
oResolvedHashFragment.sFixedShellHash = sFixedShellHash;
|
|
1880
|
+
|
|
1881
|
+
var oHandlerPromise = AppLifeCycleAI.handleControl(
|
|
1882
|
+
sIntent,
|
|
1883
|
+
sAppId,
|
|
1884
|
+
oParsedShellHash,
|
|
1885
|
+
oResolvedHashFragment,
|
|
1886
|
+
this.getWrappedApplicationWithMoreStrictnessInIntention.bind(this),
|
|
1887
|
+
sFixedShellHash,
|
|
1888
|
+
sOldFixedShellHash
|
|
1889
|
+
);
|
|
1890
|
+
|
|
1891
|
+
if (this.currentAppBeforeNav) {
|
|
1892
|
+
if (ushellUtils.isTRApplicationType(this.currentAppBeforeNav.applicationType, ObjectPath.get("appCapabilities.appFrameworkId", this.currentAppBeforeNav)) &&
|
|
1893
|
+
!ushellUtils.isTRApplicationType(oResolvedHashFragment.applicationType)) {
|
|
1894
|
+
sap.ui.require([
|
|
1895
|
+
"sap/ushell/components/applicationIntegration/application/BlueBoxHandler",
|
|
1896
|
+
"sap/ushell/components/applicationIntegration/application/WebGUIStatefulHandler"], function (BlueBoxHandler, WebGUIStatefulHandler) {
|
|
1897
|
+
var oPreviousStatefulContainer = BlueBoxHandler.getBlueBoxByUrl(that.currentAppBeforeNav.url);
|
|
1898
|
+
if (oPreviousStatefulContainer && oPreviousStatefulContainer.getStatefulType() === BlueBoxHandler.STATEFUL_TYPES.GUI_V1) {
|
|
1899
|
+
WebGUIStatefulHandler.guiStatefulCloseCurrentApp(oPreviousStatefulContainer);
|
|
1900
|
+
}
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
Measurement.end("FLP:ShellController._handleEmbeddedNavMode");
|
|
1906
|
+
|
|
1907
|
+
return oHandlerPromise;
|
|
1908
|
+
},
|
|
1909
|
+
|
|
1910
|
+
_centerViewPort: function () {
|
|
1911
|
+
this.oViewPortContainer.switchState("Center");
|
|
1912
|
+
},
|
|
1913
|
+
|
|
1914
|
+
_isShellHomeIntent: function (sIntent) {
|
|
1915
|
+
return sIntent === "#" || sIntent === oConfig.rootIntent;
|
|
1916
|
+
},
|
|
1917
|
+
|
|
1918
|
+
// Please help improve the strictness of this method.
|
|
1919
|
+
getWrappedApplicationWithMoreStrictnessInIntention: function (sIntent, oMetadata, oShellHash, oResolvedNavigationTarget, sAppId, bFullWidth, sFixedShellHash) {
|
|
1920
|
+
var that = this;
|
|
1921
|
+
|
|
1922
|
+
if (Device.system.desktop) {
|
|
1923
|
+
sap.ui.require(["sap/ushell/renderer/AccessKeysHandler"], function (AccessKeysHandler) {
|
|
1924
|
+
var oShellAppTitle = Core.byId("shellAppTitle");
|
|
1925
|
+
if (oShellAppTitle && Config.last("/core/shell/model/currentState/stateName") === "app") {
|
|
1926
|
+
var oShellAppTitleDomRef = oShellAppTitle.getFocusDomRef();
|
|
1927
|
+
if (oShellAppTitleDomRef) {
|
|
1928
|
+
AccessKeysHandler.sendFocusBackToShell(oShellAppTitleDomRef.getAttribute("id"));
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
window.setTimeout(function () {
|
|
1935
|
+
window.setTimeout(function () {
|
|
1936
|
+
//Screen reader: "Loading Complete"
|
|
1937
|
+
that.readNavigationEnd();
|
|
1938
|
+
}, 600);
|
|
1939
|
+
|
|
1940
|
+
Core.getEventBus().publish("launchpad", "appOpening", oResolvedNavigationTarget);
|
|
1941
|
+
Log.info("app is being opened");
|
|
1942
|
+
}, 0);
|
|
1943
|
+
if (oConfig.applications) {
|
|
1944
|
+
oResolvedNavigationTarget.applicationConfiguration = oConfig.applications[sIntent];
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
var oAppContainer = AppLifeCycleAI.getAppContainer(sAppId, oResolvedNavigationTarget, this._isColdStart(), oShellHash, sFixedShellHash);
|
|
1948
|
+
var bContainerFromCachePool = false;
|
|
1949
|
+
if (oAppContainer.getIsFetchedFromCache && oAppContainer.getIsFetchedFromCache()) {
|
|
1950
|
+
bContainerFromCachePool = true;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
if (!bContainerFromCachePool) {
|
|
1954
|
+
AppLifeCycleAI.publishNavigationStateEvents(oAppContainer, oResolvedNavigationTarget, this.onAppAfterRendering.bind(this, oResolvedNavigationTarget));
|
|
1955
|
+
|
|
1956
|
+
if (ushellUtils.isSAPLegacyApplicationType(oAppContainer.getApplicationType(), oAppContainer.getFrameworkId())) {
|
|
1957
|
+
oAppContainer.addStyleClass("sapUShellApplicationContainerShiftedIframe");
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
if (!bFullWidth) {
|
|
1961
|
+
oAppContainer.addStyleClass("sapUShellApplicationContainerLimitedWidth");
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
if (this._isFloatingContainerDocked() && window.matchMedia("(min-width: 106.4rem)").matches) {
|
|
1965
|
+
oAppContainer.addStyleClass("sapUShellDockingContainer");
|
|
1966
|
+
oAppContainer.removeStyleClass("sapUShellApplicationContainerLimitedWidth");
|
|
1967
|
+
} else if (this._isFloatingContainerDocked()) {
|
|
1968
|
+
oAppContainer.removeStyleClass("sapUShellApplicationContainerLimitedWidth");
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
oAppContainer.toggleStyleClass("sapUshellDefaultBackground", !oMetadata.hideLightBackground);
|
|
1972
|
+
|
|
1973
|
+
AppLifeCycleAI.getAppMeta()._applyContentDensityByPriority();
|
|
1974
|
+
|
|
1975
|
+
// Add inner control for next request
|
|
1976
|
+
AppLifeCycleAI.addControl(oAppContainer);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
ushellUtils.setPerformanceMark("FLP - addAppContainer");
|
|
1980
|
+
|
|
1981
|
+
Measurement.end("FLP:ShellController.getWrappedApplication");
|
|
1982
|
+
return oAppContainer;
|
|
1983
|
+
},
|
|
1984
|
+
|
|
1985
|
+
// Set booleans to false which indicate whether shellUIService was called or not
|
|
1986
|
+
resetShellUIServiceHandlers: function () {
|
|
1987
|
+
AppLifeCycleAI.getAppMeta().resetShellUIServiceHandlers();
|
|
1988
|
+
AppLifeCycleAI.setBackNavigationChanged(false);
|
|
1989
|
+
},
|
|
1990
|
+
|
|
1991
|
+
onAppAfterRendering: function (oApplication) {
|
|
1992
|
+
var oShellUIService = AppLifeCycleAI.getShellUIService();
|
|
1993
|
+
// wrapped in setTimeout since "publish" is not async
|
|
1994
|
+
window.setTimeout(function () {
|
|
1995
|
+
Core.getEventBus().publish("sap.ushell", "appOpened", oApplication);
|
|
1996
|
+
Log.info("app was opened");
|
|
1997
|
+
}, 0);
|
|
1998
|
+
|
|
1999
|
+
// publish the event externally
|
|
2000
|
+
// TODO: cloned, frozen object!
|
|
2001
|
+
var oAppOpenedEventData = AppLifeCycleAI._publicEventDataFromResolutionResult(oApplication);
|
|
2002
|
+
|
|
2003
|
+
// Event is emitted internally (EventHub) _and_ externally (for compatibility reasons)
|
|
2004
|
+
EventHub.emit("AppRendered", oAppOpenedEventData, true);
|
|
2005
|
+
RendererUtils.publishExternalEvent("appOpened", oAppOpenedEventData);
|
|
2006
|
+
ushellUtils.setPerformanceMark("FLP.appOpened");
|
|
2007
|
+
|
|
2008
|
+
// Call setHierarchy, setTitle, setRelatedApps with default values in case handlers were not called yet
|
|
2009
|
+
if (oShellUIService) {
|
|
2010
|
+
AppLifeCycleAI.initAppMetaParams();
|
|
2011
|
+
}
|
|
2012
|
+
oShellModel.updateStateProperty("application/icon", AppLifeCycleAI.getAppMeta().getAppIcon(), true);
|
|
2013
|
+
},
|
|
2014
|
+
|
|
2015
|
+
/**
|
|
2016
|
+
* Adds a listener to the "appComponentLoaded" Event that is published by the "sap.ushell".
|
|
2017
|
+
* Once the "home app" Component is saved, the listener is removed, and this function will not do anything.
|
|
2018
|
+
*/
|
|
2019
|
+
_saveHomePageComponent: function () {
|
|
2020
|
+
if (this.oHomeApp) {
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
var that = this;
|
|
2024
|
+
var sContainerNS = "sap.ushell";
|
|
2025
|
+
var fListener = function (oEvent, sChannel, oData) {
|
|
2026
|
+
that.oHomeApp = oData.component;
|
|
2027
|
+
Core.getEventBus().unsubscribe(sContainerNS, "appComponentLoaded", fListener);
|
|
2028
|
+
};
|
|
2029
|
+
Core.getEventBus().subscribe(sContainerNS, "appComponentLoaded", fListener);
|
|
2030
|
+
},
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* Shows an error message and navigates to the previous page.
|
|
2034
|
+
*
|
|
2035
|
+
* @param {int} iHistoryLength the length of the history <b>before</b> the navigation occurred.
|
|
2036
|
+
* @param {string|object} vMessage the error message
|
|
2037
|
+
* @param {string|object} vDetails the detailed error message
|
|
2038
|
+
* @param {string} sComponent the component that generated the error message
|
|
2039
|
+
* @param {boolean} bEnableHashChange enable hash change
|
|
2040
|
+
*/
|
|
2041
|
+
hashChangeFailure: function (iHistoryLength, vMessage, vDetails, sComponent, bEnableHashChange) {
|
|
2042
|
+
var oDashboard = Core.byId("sapUshellDashboardPage");
|
|
2043
|
+
if (oDashboard) {
|
|
2044
|
+
oDashboard.setBlocked(false);
|
|
2045
|
+
oDashboard.setBusy(false);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
if (ushellUtils.isPlainObject(vMessage)) {
|
|
2049
|
+
this.reportError(vMessage.technicalMessage, vDetails.technicalMessage, sComponent);
|
|
2050
|
+
sap.ushell.Container.getServiceAsync("Message").then(function (oMessage) {
|
|
2051
|
+
oMessage.show(
|
|
2052
|
+
oMessage.Type.ERROR,
|
|
2053
|
+
vMessage.message,
|
|
2054
|
+
{
|
|
2055
|
+
title: vMessage.title,
|
|
2056
|
+
details: vDetails
|
|
2057
|
+
}
|
|
2058
|
+
);
|
|
2059
|
+
});
|
|
2060
|
+
} else {
|
|
2061
|
+
this.reportError(vMessage, vDetails, sComponent);
|
|
2062
|
+
// use timeout to avoid "MessageService not initialized.: error
|
|
2063
|
+
this.delayedMessageError(ushellResources.i18n.getText("fail_to_start_app_try_later"));
|
|
2064
|
+
}
|
|
2065
|
+
closeAllDialogs = false;
|
|
2066
|
+
|
|
2067
|
+
this._resumeAppRouterIgnoringCurrentHash();
|
|
2068
|
+
if (iHistoryLength === 0) {
|
|
2069
|
+
// if started with an illegal shell hash (deep link), we just remove the hash
|
|
2070
|
+
window.hasher.setHash("");
|
|
2071
|
+
} else if (new URLSearchParams(window.location.search).get("bFallbackToShellHome")) {
|
|
2072
|
+
// The previous url is not valid navigation
|
|
2073
|
+
window.hasher.setHash("");
|
|
2074
|
+
} else {
|
|
2075
|
+
// navigate to the previous URL since in this state the hash that has failed to load is in the URL.
|
|
2076
|
+
this.bEnableHashChange = bEnableHashChange;
|
|
2077
|
+
sap.ushell.Container.setDirtyFlag(bPreviousPageDirty);
|
|
2078
|
+
this._windowHistoryBack(1);
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2081
|
+
|
|
2082
|
+
reportError: function (sMessage, sDetails, sComponent) {
|
|
2083
|
+
Log.error(sMessage, sDetails, sComponent);
|
|
2084
|
+
},
|
|
2085
|
+
|
|
2086
|
+
delayedMessageError: function (sMsg) {
|
|
2087
|
+
window.setTimeout(function () {
|
|
2088
|
+
if (sap.ushell.Container !== undefined) {
|
|
2089
|
+
sap.ushell.Container.getServiceAsync("Message").then(function (oMessage) {
|
|
2090
|
+
oMessage.error(sMsg);
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
}, 0);
|
|
2094
|
+
},
|
|
2095
|
+
|
|
2096
|
+
fixShellHash: function (sShellHash) {
|
|
2097
|
+
if (!sShellHash) {
|
|
2098
|
+
sShellHash = "#";
|
|
2099
|
+
} else if (sShellHash.charAt(0) !== "#") {
|
|
2100
|
+
sShellHash = "#" + sShellHash;
|
|
2101
|
+
}
|
|
2102
|
+
return sShellHash;
|
|
2103
|
+
},
|
|
2104
|
+
|
|
2105
|
+
_openAppNewWindow: function (sUrl) {
|
|
2106
|
+
var oNewWin = WindowUtils.openURL(sUrl);
|
|
2107
|
+
// Show a message when window.open returns null --> Popup Blocker
|
|
2108
|
+
// Exception: in WorkZone's mobile client, when external nav happens: Keep calm and carry on.
|
|
2109
|
+
if (!oNewWin && !this._checkWindowLocationSearch("workzone-mobile-app=true")) {
|
|
2110
|
+
var msg = ushellResources.i18n.getText("fail_to_start_app_popup_blocker", [window.location.hostname]);
|
|
2111
|
+
this.delayedMessageError(msg);
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
|
|
2115
|
+
_checkWindowLocationSearch: function (sTerm) {
|
|
2116
|
+
return window.location.search.indexOf(sTerm) > -1;
|
|
2117
|
+
},
|
|
2118
|
+
|
|
2119
|
+
_windowHistoryBack: function (iSteps) {
|
|
2120
|
+
window.history.go(-1 * iSteps);
|
|
2121
|
+
},
|
|
2122
|
+
|
|
2123
|
+
_windowHistoryForward: function (iSteps) {
|
|
2124
|
+
window.history.go(iSteps);
|
|
2125
|
+
},
|
|
2126
|
+
|
|
2127
|
+
_changeWindowLocation: function (sUrl) {
|
|
2128
|
+
window.location.href = sUrl;
|
|
2129
|
+
},
|
|
2130
|
+
|
|
2131
|
+
_setMenuVisible: function (bVisible) {
|
|
2132
|
+
var navigationBar = document.getElementById(ShellLayoutMapping.NavigationBar);
|
|
2133
|
+
if (!navigationBar) {
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
bVisible = bVisible || (Config.last("/core/menu/enabled") && Config.last("/core/menu/visibleInAllStates")); // visibleInAllStates:true has priority
|
|
2137
|
+
|
|
2138
|
+
navigationBar.classList.toggle("sapUshellShellHidden", !bVisible);
|
|
2139
|
+
},
|
|
2140
|
+
|
|
2141
|
+
/**
|
|
2142
|
+
* Triggered by the EventBus "appOpened" event.
|
|
2143
|
+
* Performs logging for recent activities and application usage
|
|
2144
|
+
*
|
|
2145
|
+
* @param {string} sChannelId The channelId of the event
|
|
2146
|
+
* @param {string} sEventId The event id
|
|
2147
|
+
* @param {object} oResolvedHashFragment The resolved hash fragment object belonging to the event
|
|
2148
|
+
*/
|
|
2149
|
+
onAppOpened: function (sChannelId, sEventId, oResolvedHashFragment) {
|
|
2150
|
+
if (oResolvedHashFragment.targetNavigationMode !== "explace" && oResolvedHashFragment.targetNavigationMode !== "frameless") {
|
|
2151
|
+
this._setMenuVisible(false);
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
var sAppHash = this.oShellNavigation.hashChanger.getAppHash();
|
|
2155
|
+
var sAppPart = sAppHash ? "&/" + sAppHash : null;
|
|
2156
|
+
|
|
2157
|
+
this.logOpenAppAction(oResolvedHashFragment, sAppPart);
|
|
2158
|
+
|
|
2159
|
+
this._notifyUITracer(oResolvedHashFragment);
|
|
2160
|
+
},
|
|
2161
|
+
|
|
2162
|
+
externalSearchTriggered: function (sChannelId, sEventId, oData) {
|
|
2163
|
+
Config.emit("/core/shell/model/searchTerm", oData.searchTerm);
|
|
2164
|
+
oData.query = oData.searchTerm;
|
|
2165
|
+
},
|
|
2166
|
+
|
|
2167
|
+
onBeforeNavigate: function (oEvent) {
|
|
2168
|
+
var oToView = oEvent.getParameter("to");
|
|
2169
|
+
var oOwnerComponent = this.getOwnerComponent();
|
|
2170
|
+
|
|
2171
|
+
var bToDashboardView = oToView === oOwnerComponent.byId("Shell-home-component-container");
|
|
2172
|
+
var bToPagesView = oToView === oOwnerComponent.byId("pages-component-container");
|
|
2173
|
+
var bToHomeAppView = oToView === oOwnerComponent.byId("homeApp-component-container");
|
|
2174
|
+
var bToWorkpagesView = oToView === oOwnerComponent.byId("workPageRuntime-component-container");
|
|
2175
|
+
var bToSwitcherView = oToView === oOwnerComponent.byId("runtimeSwitcher-component-container");
|
|
2176
|
+
var bMenuVisible = bToDashboardView || bToPagesView || bToHomeAppView || bToWorkpagesView || bToSwitcherView;
|
|
2177
|
+
|
|
2178
|
+
AppLifeCycleAI.onBeforeNavigate(oEvent.getParameter("fromId"), oEvent.getParameter("from"), oEvent.getParameter("toId"), oEvent.getParameter("to"));
|
|
2179
|
+
this._setMenuVisible(bMenuVisible);
|
|
2180
|
+
},
|
|
2181
|
+
|
|
2182
|
+
onAfterNavigate: function (oEvent) {
|
|
2183
|
+
var sToId = oEvent.mParameters ? oEvent.mParameters.toId : undefined;
|
|
2184
|
+
|
|
2185
|
+
var oDashboard = Core.byId("sapUshellDashboardPage");
|
|
2186
|
+
if (oDashboard) {
|
|
2187
|
+
oDashboard.setBlocked(false);
|
|
2188
|
+
oDashboard.setBusy(false);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
AppLifeCycleAI.onAfterNavigate(oEvent.getParameter("fromId"), oEvent.getParameter("from"), sToId, oEvent.getParameter("to"));
|
|
2192
|
+
Core.getEventBus().publish("sap.ushell", "navigated", {});
|
|
2193
|
+
},
|
|
2194
|
+
|
|
2195
|
+
// 1 - remove appClosed hooks
|
|
2196
|
+
// 2 - logApplicationUsage to take resolved hash fragment
|
|
2197
|
+
|
|
2198
|
+
logOpenAppAction: function (oResolvedHashFragment, sAppPart) {
|
|
2199
|
+
var bEnableRecentActivity = Config.last("/core/shell/enableRecentActivity") && Config.last("/core/shell/enableRecentActivityLogging");
|
|
2200
|
+
if (!bEnableRecentActivity) {
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
var oRecentEntry = {};
|
|
2205
|
+
var oMetadata = AppConfiguration.getMetadata(oResolvedHashFragment);
|
|
2206
|
+
var sFixedShellHash = oResolvedHashFragment.sFixedShellHash;
|
|
2207
|
+
var sUrl = sFixedShellHash;
|
|
2208
|
+
if (sAppPart) {
|
|
2209
|
+
sUrl += sAppPart; // some application use inner routes, for example search.
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
oRecentEntry.title = oMetadata.title;
|
|
2213
|
+
oRecentEntry.appType = AppType.APP; // default app type the shell adds is 'Application'
|
|
2214
|
+
oRecentEntry.url = sUrl;
|
|
2215
|
+
|
|
2216
|
+
var oParsed = this.oURLParsing.parseShellHash(sFixedShellHash);
|
|
2217
|
+
if (oParsed) {
|
|
2218
|
+
/*
|
|
2219
|
+
* This is the key that determines whether an existing activity should be updated or added.
|
|
2220
|
+
*
|
|
2221
|
+
* In theory we could use the full hash without parameters here, however this causes the same application to be logged
|
|
2222
|
+
* multiple times with the same title, confusing the user.
|
|
2223
|
+
*
|
|
2224
|
+
* Therefore we choose to update a previous entry in case just the parameters change. This might cause a bit of
|
|
2225
|
+
* confusion in case another target mapping is opened, as the title of a previously logged entry would be updated
|
|
2226
|
+
* instead of having a new title added to the recent activities (same target mapping but different title).
|
|
2227
|
+
*
|
|
2228
|
+
* Perhaps this could be further fixed by hashing a target mapping on the client before returning the resolution
|
|
2229
|
+
* result, and using the hash as the id.
|
|
2230
|
+
*/
|
|
2231
|
+
oRecentEntry.appId = "#" + this.oURLParsing.constructShellHash({
|
|
2232
|
+
semanticObject: oParsed.semanticObject,
|
|
2233
|
+
action: oParsed.action
|
|
2234
|
+
});
|
|
2235
|
+
} else {
|
|
2236
|
+
oRecentEntry.appId = sFixedShellHash;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
// The recent activity for searches is done in a different way, see this._logSearchActivity
|
|
2240
|
+
if (sFixedShellHash && sFixedShellHash.indexOf("#Action-search") === -1 && sFixedShellHash.indexOf("#Shell-startIntent") === -1) {
|
|
2241
|
+
window.setTimeout(function () {
|
|
2242
|
+
this._logRecentActivity(oRecentEntry);
|
|
2243
|
+
}.bind(this), 1500);
|
|
2244
|
+
}
|
|
2245
|
+
},
|
|
2246
|
+
|
|
2247
|
+
/**
|
|
2248
|
+
* Notifies the UITracer service about the navigation (app launch) by emitting
|
|
2249
|
+
* a corresponding event on the event hub.
|
|
2250
|
+
*
|
|
2251
|
+
* @param {object} oResolvedHashFragment - the result of the NavTargetResolution service
|
|
2252
|
+
*/
|
|
2253
|
+
_notifyUITracer: function (oResolvedHashFragment) {
|
|
2254
|
+
try {
|
|
2255
|
+
var sApplicationId = oResolvedHashFragment.ui5ComponentName;
|
|
2256
|
+
if (oResolvedHashFragment.reservedParameters) {
|
|
2257
|
+
sApplicationId =
|
|
2258
|
+
oResolvedHashFragment.reservedParameters["sap-fiori-id"] ||
|
|
2259
|
+
oResolvedHashFragment.reservedParameters["sap-ui-app-id-hint"];
|
|
2260
|
+
}
|
|
2261
|
+
EventHub.emit("UITracer.trace", {
|
|
2262
|
+
reason: "NavigateApp",
|
|
2263
|
+
source: "Intent",
|
|
2264
|
+
data: {
|
|
2265
|
+
applicationId: sApplicationId || "",
|
|
2266
|
+
applicationType: oResolvedHashFragment.applicationType || "",
|
|
2267
|
+
hash: oResolvedHashFragment.sFixedShellHash || "",
|
|
2268
|
+
targetNavigationMode: oResolvedHashFragment.targetNavigationMode || "",
|
|
2269
|
+
providerId: oResolvedHashFragment.contentProviderId || "",
|
|
2270
|
+
targetUrl: oResolvedHashFragment.url || ""
|
|
2271
|
+
}
|
|
2272
|
+
});
|
|
2273
|
+
} catch (ex) {
|
|
2274
|
+
Log.warning("Could not emit UITracer.trace event", ex, "sap.ushell.renderer.Shell.controller");
|
|
2275
|
+
}
|
|
2276
|
+
},
|
|
2277
|
+
|
|
2278
|
+
// Special logic for Search.
|
|
2279
|
+
// The search activity must be logged even after a user makes different searches in a single #Action-search session.
|
|
2280
|
+
// Therefore, the logging should occur on the search event and not by the navigation to the search application.
|
|
2281
|
+
_logSearchActivity: function () {
|
|
2282
|
+
if (Config.last("/core/shell/enableRecentActivity") && Config.last("/core/shell/enableRecentActivityLogging")) {
|
|
2283
|
+
var sTitle = "";
|
|
2284
|
+
try {
|
|
2285
|
+
sTitle = Core.byId("searchFieldInShell-input").getModel().getLastSearchTerm();
|
|
2286
|
+
} catch (ex) {
|
|
2287
|
+
Log.error("Shell: last search term is not available to log a recent activity");
|
|
2288
|
+
}
|
|
2289
|
+
this._logRecentActivity({
|
|
2290
|
+
appId: "#Action-search",
|
|
2291
|
+
appType: AppType.SEARCH,
|
|
2292
|
+
title: sTitle,
|
|
2293
|
+
url: "#" + window.hasher.getHash()
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
},
|
|
2297
|
+
|
|
2298
|
+
readNavigationEnd: function () {
|
|
2299
|
+
var oAccessibilityHelperLoadingComplete = document.getElementById("sapUshellLoadingAccessibilityHelper-loadingComplete");
|
|
2300
|
+
|
|
2301
|
+
if (oAccessibilityHelperLoadingComplete) {
|
|
2302
|
+
oAccessibilityHelperLoadingComplete.setAttribute("aria-live", "polite");
|
|
2303
|
+
oAccessibilityHelperLoadingComplete.innerHTML = ushellResources.i18n.getText("loadingComplete");
|
|
2304
|
+
window.setTimeout(function () {
|
|
2305
|
+
oAccessibilityHelperLoadingComplete.setAttribute("aria-live", "off");
|
|
2306
|
+
oAccessibilityHelperLoadingComplete.innerHTML = "";
|
|
2307
|
+
}, 0);
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
2310
|
+
|
|
2311
|
+
_loadCoreExtNonUI5: function (oAppTarget) {
|
|
2312
|
+
if (oAppTarget && oAppTarget.applicationType !== "SAPUI5") {
|
|
2313
|
+
this._loadCoreExt();
|
|
2314
|
+
}
|
|
2315
|
+
},
|
|
2316
|
+
|
|
2317
|
+
_loadUsageAnalytics: function (eventData) {
|
|
2318
|
+
sap.ushell.Container.getServiceAsync("UsageAnalytics").then(function (oUsageAnalytics) {
|
|
2319
|
+
oUsageAnalytics.init(
|
|
2320
|
+
ushellResources.i18n.getText("usageAnalytics"),
|
|
2321
|
+
ushellResources.i18n.getText("i_agree"),
|
|
2322
|
+
ushellResources.i18n.getText("i_disagree"),
|
|
2323
|
+
ushellResources.i18n.getText("remind_me_later")
|
|
2324
|
+
);
|
|
2325
|
+
EventHub.emit("StepDone", eventData.stepName);
|
|
2326
|
+
}, function () {
|
|
2327
|
+
EventHub.emit("StepFailed", eventData.stepName);
|
|
2328
|
+
});
|
|
2329
|
+
},
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* RendererExtensions plugins are loaded after the core-ext modules.
|
|
2333
|
+
* core-ext is loaded, either in first application load flow in case app is not FLP or explicitly by the Renderer (in this file) after FLP is loaded.
|
|
2334
|
+
* In any case, after we load the plugins, we also publish the event that all Core resources are loaded
|
|
2335
|
+
*/
|
|
2336
|
+
_onCoreResourcesComplementLoaded: function () {
|
|
2337
|
+
ushellUtils.setPerformanceMark("SchedulingAgent-StartOfFlow");
|
|
2338
|
+
// Create delayed controls in the view
|
|
2339
|
+
var oView = this.getView();
|
|
2340
|
+
if (oView) { // some qUnits do not create the view
|
|
2341
|
+
oView.createPostCoreExtControls();
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
SchedulingAgent._initialize();
|
|
2345
|
+
|
|
2346
|
+
EventHub.emit("startScheduler");
|
|
2347
|
+
},
|
|
2348
|
+
|
|
2349
|
+
/*
|
|
2350
|
+
* After core-ext is loaded (see_onCoreResourcesComplementLoaded) the renderer extensions plugins can be loaded.
|
|
2351
|
+
* To enable the Scheduling Agent to direct this the loading is wrapped in this function.
|
|
2352
|
+
*/
|
|
2353
|
+
_loadRendererExtensionPlugins: function (eventData) {
|
|
2354
|
+
var oUriParameters = new URLSearchParams(window.location.search);
|
|
2355
|
+
var bDelayPlugin = oUriParameters.get("sap-ushell-xx-pluginmode") === "delayed";
|
|
2356
|
+
|
|
2357
|
+
function createPlugins (oPluginManager) {
|
|
2358
|
+
// in addition we have to ensure the new EventHub Event is thrown
|
|
2359
|
+
function fnPublishPostLoadingEvents () {
|
|
2360
|
+
EventHub.emit("StepDone", eventData.stepName);
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
// load the plugins and always publish post events
|
|
2364
|
+
function fnLoadPlugins () {
|
|
2365
|
+
oPluginManager
|
|
2366
|
+
.loadPlugins("RendererExtensions")
|
|
2367
|
+
.always(fnPublishPostLoadingEvents);
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
if (bDelayPlugin) {
|
|
2371
|
+
// delay loading by 5 sec.
|
|
2372
|
+
window.setTimeout(fnLoadPlugins, 5000);
|
|
2373
|
+
} else {
|
|
2374
|
+
fnLoadPlugins();
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
sap.ushell.Container.getServiceAsync("PluginManager").then(createPlugins.bind(this));
|
|
2378
|
+
},
|
|
2379
|
+
|
|
2380
|
+
// Triggers loading of the warmup plugins via Plugin Manager
|
|
2381
|
+
_loadWarmupPlugins: function (eventData) {
|
|
2382
|
+
sap.ushell.Container.getServiceAsync("PluginManager").then(function (oPluginManager) {
|
|
2383
|
+
oPluginManager.loadPlugins("AppWarmup").always(function () {
|
|
2384
|
+
Log.debug("WARMUP plugins loaded", null, "sap.ushell.renderer.Shell");
|
|
2385
|
+
EventHub.emit("StepDone", eventData.stepName);
|
|
2386
|
+
ushellUtils.setPerformanceMark("SchedulingAgent-EndOfFlow");
|
|
2387
|
+
ushellUtils.setPerformanceMeasure("SchedulingAgentTotalTime", "SchedulingAgent-StartOfFlow", "SchedulingAgent-EndOfFlow");
|
|
2388
|
+
});
|
|
2389
|
+
});
|
|
2390
|
+
},
|
|
2391
|
+
|
|
2392
|
+
// Triggers loading of CoreExt via EventHub
|
|
2393
|
+
_loadCoreExt: function () {
|
|
2394
|
+
Measurement.end("FLP:Container.InitLoading");
|
|
2395
|
+
// Trigger oEventHub.once("loadCoreResourcesComplement") in case homepage is first rendered.
|
|
2396
|
+
// Usually this is done with resolveHashFragment, but without passing from that path we should trigger it actively.
|
|
2397
|
+
sap.ushell.Container.getServiceAsync("Ui5ComponentLoader").then(function () {
|
|
2398
|
+
EventHub.emit("loadCoreResourcesComplement", Date.now());
|
|
2399
|
+
});
|
|
2400
|
+
},
|
|
2401
|
+
|
|
2402
|
+
getCurrentViewportState: function () {
|
|
2403
|
+
return Config.last("/core/shell/model/currentViewPortState");
|
|
2404
|
+
},
|
|
2405
|
+
|
|
2406
|
+
_activateFloatingUIActions: function (iWindowWidth) {
|
|
2407
|
+
if (iWindowWidth < 417) {
|
|
2408
|
+
this.oFloatingUIActions.disable();
|
|
2409
|
+
} else {
|
|
2410
|
+
this.oFloatingUIActions.enable();
|
|
2411
|
+
}
|
|
2412
|
+
},
|
|
2413
|
+
|
|
2414
|
+
setFloatingContainerDragSelector: function (sElementToCaptureSelector) {
|
|
2415
|
+
if (!this._oFloatingContainerPromise) {
|
|
2416
|
+
this._oFloatingContainerPromise = this.getView().createFloatingContainer();
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
this._oFloatingContainerPromise.then(function () {
|
|
2420
|
+
var oElementToCapture = document.querySelector(sElementToCaptureSelector);
|
|
2421
|
+
if (oElementToCapture) {
|
|
2422
|
+
oElementToCapture.classList.add("sapUshellFloatingContainerSelector");
|
|
2423
|
+
} else {
|
|
2424
|
+
Log.error("setFloatingContainerDragSelector could not find the element", "sap.ushell.renderer.Shell.controller");
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// Fix for internal incident #1770519876 2017 -
|
|
2428
|
+
// Avoiding crash of CoPilot after deleting an instance and using a property (in UIAction) of the deleted one
|
|
2429
|
+
sap.ui.require(["sap/ushell/UIActions"], function (UIActions) {
|
|
2430
|
+
if (!this.oFloatingUIActions) {
|
|
2431
|
+
this.oFloatingUIActions = new UIActions({
|
|
2432
|
+
containerSelector: ".sapUiBody",
|
|
2433
|
+
wrapperSelector: ".sapUshellFloatingContainerWrapper",
|
|
2434
|
+
draggableSelector: ".sapUshellFloatingContainerWrapper", // the element that we drag
|
|
2435
|
+
rootSelector: ".sapUiBody",
|
|
2436
|
+
cloneClass: "sapUshellFloatingContainer-clone",
|
|
2437
|
+
dragCallback: this._handleFloatingContainerDrag.bind(this), // for hide the original item while dragging
|
|
2438
|
+
endCallback: this._handleFloatingContainerDrop.bind(this),
|
|
2439
|
+
moveTolerance: 3,
|
|
2440
|
+
onDragStartUIHandler: this._onFloatingContainerDragStart.bind(this),
|
|
2441
|
+
onDragEndUIHandler: this._onFloatingContainerDragEnd.bind(this),
|
|
2442
|
+
dragAndScrollCallback: this._onFloatingContainerDrag.bind(this),
|
|
2443
|
+
switchModeDelay: 1000,
|
|
2444
|
+
isLayoutEngine: false,
|
|
2445
|
+
isTouch: false, // that.isTouch,
|
|
2446
|
+
elementToCapture: sElementToCaptureSelector,
|
|
2447
|
+
defaultMouseMoveHandler: function () { },
|
|
2448
|
+
debug: Log.getLevel() >= Log.Level.DEBUG
|
|
2449
|
+
});
|
|
2450
|
+
} else {
|
|
2451
|
+
this.oFloatingUIActions.elementsToCapture = jQuery(sElementToCaptureSelector);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
this._activateFloatingUIActions(jQuery(window).width());
|
|
2455
|
+
var timer;
|
|
2456
|
+
addEventListener("resize", function () {
|
|
2457
|
+
clearTimeout(timer);
|
|
2458
|
+
timer = window.setTimeout(this._activateFloatingUIActions(jQuery(window).width()), 300);
|
|
2459
|
+
}.bind(this));
|
|
2460
|
+
}.bind(this));
|
|
2461
|
+
}.bind(this));
|
|
2462
|
+
},
|
|
2463
|
+
|
|
2464
|
+
/**
|
|
2465
|
+
* This function called once start to drag the co-pilot element
|
|
2466
|
+
* It checks whether it reach 64px(4rem) to the right/left in order to open the docking area
|
|
2467
|
+
* Also it checks whether to close the docking area
|
|
2468
|
+
* @param {object} oCfg configuration parameters
|
|
2469
|
+
* @private
|
|
2470
|
+
*/
|
|
2471
|
+
_onFloatingContainerDrag: function (oCfg) {
|
|
2472
|
+
Measurement.start("FLP:Shell.controller._doDock", "dragging co-pilot element", "FLP");
|
|
2473
|
+
|
|
2474
|
+
if (!this._isFloatingContainerDockSupported()) {
|
|
2475
|
+
Measurement.end("FLP:Shell.controller._doDock");
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
var iWindowWidth = jQuery(window).width();
|
|
2480
|
+
if (oCfg) {
|
|
2481
|
+
oCfg.docked = {};
|
|
2482
|
+
var oDockedProp = oCfg.docked;
|
|
2483
|
+
// cfg.moveX get FloatingContainer courser x position.
|
|
2484
|
+
// handle for opening the docking area for right and left
|
|
2485
|
+
// in case that docking area open - close it
|
|
2486
|
+
// in case canvas moved (because the docking ) close it
|
|
2487
|
+
if (oCfg.moveX >= iWindowWidth - 64) {
|
|
2488
|
+
oDockedProp.dockPos = "right";
|
|
2489
|
+
oDockedProp.setIsDockingAreaOpen = true;
|
|
2490
|
+
this._handleDockingPreview(oCfg);
|
|
2491
|
+
} else if (oCfg.moveX < 64) {
|
|
2492
|
+
oDockedProp.dockPos = "left";
|
|
2493
|
+
oDockedProp.setIsDockingAreaOpen = true;
|
|
2494
|
+
this._handleDockingPreview(oCfg);
|
|
2495
|
+
} else {
|
|
2496
|
+
// prevent flickering
|
|
2497
|
+
if (this._isDockingAreaOpen()) {
|
|
2498
|
+
this._handleDockingPreview(false);
|
|
2499
|
+
}
|
|
2500
|
+
if (this._isFloatingContainerDocked()) {
|
|
2501
|
+
this._handleDockingPreview(false);
|
|
2502
|
+
this._undockFloatingContainer();
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
Measurement.end("FLP:Shell.controller._doDock");
|
|
2508
|
+
},
|
|
2509
|
+
|
|
2510
|
+
_isFloatingContainerDockSupported: function () {
|
|
2511
|
+
// open dock option only if config is enable and screen size is L (desktop + tablet landscape)
|
|
2512
|
+
var oDevice = Device.media.getCurrentRange(Device.media.RANGESETS.SAP_STANDARD);
|
|
2513
|
+
return oDevice.name === "Desktop";
|
|
2514
|
+
},
|
|
2515
|
+
|
|
2516
|
+
/**
|
|
2517
|
+
* This method handle the finish (after drop) for the docking
|
|
2518
|
+
* @param {object} oDockCfg properties object
|
|
2519
|
+
* @private
|
|
2520
|
+
*/
|
|
2521
|
+
_finishDoDock: function (oDockCfg) {
|
|
2522
|
+
this._handleDockingPreview(false);
|
|
2523
|
+
this._saveFloatingContainerState("docked:" + oDockCfg.dockPos);
|
|
2524
|
+
|
|
2525
|
+
this._moveFloatingContainerIntoDock(oDockCfg);
|
|
2526
|
+
const oData = {
|
|
2527
|
+
isDocked: (this.getFloatingContainerState() || "").startsWith("docked"),
|
|
2528
|
+
isVisible: this.getFloatingContainerVisibility()
|
|
2529
|
+
};
|
|
2530
|
+
// New event for co-pilot is docked.
|
|
2531
|
+
Core.getEventBus().publish("launchpad", "shellFloatingContainerIsDocked", oData);
|
|
2532
|
+
},
|
|
2533
|
+
|
|
2534
|
+
_expandFloatingContainerToDock: function () {
|
|
2535
|
+
var oWrapperElement = document.getElementById(ShellLayoutMapping.FloatingContainer);
|
|
2536
|
+
oWrapperElement.style.height = "100%";
|
|
2537
|
+
|
|
2538
|
+
Core.byId("shell-floatingContainer").addStyleClass("sapUshellShellFloatingContainerFullHeight");
|
|
2539
|
+
},
|
|
2540
|
+
|
|
2541
|
+
_shrinkFloatingContainerToDragUI: function () {
|
|
2542
|
+
var oWrapperElement = document.getElementById(ShellLayoutMapping.FloatingContainer);
|
|
2543
|
+
oWrapperElement.classList.remove("sapUshellContainerDocked");
|
|
2544
|
+
|
|
2545
|
+
Core.byId("shell-floatingContainer").removeStyleClass("sapUshellShellFloatingContainerFullHeight");
|
|
2546
|
+
jQuery(".sapUshellShellFloatingContainerFullHeight").removeClass("sapUshellShellFloatingContainerFullHeight"); // remove it also for the clone
|
|
2547
|
+
},
|
|
2548
|
+
|
|
2549
|
+
_emitFloatingContainerResizeEvent: function () {
|
|
2550
|
+
var oViewPortContainer = Core.byId("viewPortContainer");
|
|
2551
|
+
if (oViewPortContainer) {
|
|
2552
|
+
oViewPortContainer._handleSizeChange();
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// handle appFinder size changed
|
|
2556
|
+
// timeOut waiting for resize event is finish
|
|
2557
|
+
window.setTimeout(function () {
|
|
2558
|
+
Core.getEventBus().publish("launchpad", "appFinderWithDocking");
|
|
2559
|
+
}, 300);
|
|
2560
|
+
},
|
|
2561
|
+
|
|
2562
|
+
_undockFloatingContainer: function () {
|
|
2563
|
+
if (this._isFloatingContainerDocked()) {
|
|
2564
|
+
this._saveFloatingContainerState("floating");
|
|
2565
|
+
|
|
2566
|
+
this._shrinkFloatingContainerToDragUI();
|
|
2567
|
+
this._removeFloatingContainerFromDock();
|
|
2568
|
+
this._startFloatingContainerAnimation(false);
|
|
2569
|
+
}
|
|
2570
|
+
},
|
|
2571
|
+
|
|
2572
|
+
_handleFloatingContainerUndockOnResize: function () {
|
|
2573
|
+
this._undockFloatingContainer();
|
|
2574
|
+
const oData = {
|
|
2575
|
+
isDocked: (this.getFloatingContainerState() || "").startsWith("docked"),
|
|
2576
|
+
isVisible: this.getFloatingContainerVisibility()
|
|
2577
|
+
};
|
|
2578
|
+
Core.getEventBus().publish("launchpad", "shellFloatingContainerIsUnDockedOnResize", oData);
|
|
2579
|
+
},
|
|
2580
|
+
|
|
2581
|
+
/**
|
|
2582
|
+
* This function happens when start to drag
|
|
2583
|
+
* In this case if we docked we need to remove animations and close canvas
|
|
2584
|
+
* @private
|
|
2585
|
+
*/
|
|
2586
|
+
_onFloatingContainerDragStart: function () {
|
|
2587
|
+
Measurement.start("FLP:Shell.controller._onDragStartUI", "start drag", "FLP");
|
|
2588
|
+
this._undockFloatingContainer();
|
|
2589
|
+
const oData = {
|
|
2590
|
+
isDocked: (this.getFloatingContainerState() || "").startsWith("docked"),
|
|
2591
|
+
isVisible: this.getFloatingContainerVisibility()
|
|
2592
|
+
};
|
|
2593
|
+
// New event for co-pilot is unDock
|
|
2594
|
+
Core.getEventBus().publish("launchpad", "shellFloatingContainerIsUnDocked", oData);
|
|
2595
|
+
Measurement.end("FLP:Shell.controller._onDragStartUI");
|
|
2596
|
+
},
|
|
2597
|
+
|
|
2598
|
+
/**
|
|
2599
|
+
* This function handle the adding animations when dock/undock
|
|
2600
|
+
* @param {boolean} bIsDock set docked
|
|
2601
|
+
* @returns {Promise} Resolves once the animation is done
|
|
2602
|
+
*
|
|
2603
|
+
* @private
|
|
2604
|
+
*/
|
|
2605
|
+
_startFloatingContainerAnimation: function (bIsDock) {
|
|
2606
|
+
return new Promise(function (resolve, reject) {
|
|
2607
|
+
this._clearFloatingContainerAnimation();
|
|
2608
|
+
var aElements = Array.from(document.getElementsByClassName("sapUshellFloatingContainerWrapper"));
|
|
2609
|
+
aElements.forEach(function (oElement) {
|
|
2610
|
+
if (bIsDock) {
|
|
2611
|
+
oElement.classList.add("sapUshellContainerDockedExtendCoPilot");
|
|
2612
|
+
this._emitFloatingContainerResizeEvent();
|
|
2613
|
+
} else {
|
|
2614
|
+
// todo minimize animation does not work properly
|
|
2615
|
+
//oElement.classList.add("sapUshellContainerDockedMinimizeCoPilot");
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
["webkitAnimationEnd", "onanimationend", "msAnimationEnd", "animationend"].forEach(function (sEvent) {
|
|
2620
|
+
oElement.addEventListener(sEvent, function () {
|
|
2621
|
+
this._clearFloatingContainerAnimation();
|
|
2622
|
+
resolve();
|
|
2623
|
+
}.bind(this), { once: true });
|
|
2624
|
+
}.bind(this));
|
|
2625
|
+
}.bind(this));
|
|
2626
|
+
}.bind(this));
|
|
2627
|
+
},
|
|
2628
|
+
|
|
2629
|
+
_clearFloatingContainerAnimation: function () {
|
|
2630
|
+
var aElements = Array.from(document.getElementsByClassName("sapUshellFloatingContainerWrapper"));
|
|
2631
|
+
aElements.forEach(function (oElement) {
|
|
2632
|
+
oElement.classList.remove("sapUshellContainerDockedExtendCoPilot");
|
|
2633
|
+
oElement.classList.remove("sapUshellContainerDockedMinimizeCoPilot");
|
|
2634
|
+
});
|
|
2635
|
+
},
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* This function opens docking area for copilot
|
|
2639
|
+
* @param {object} oCfg configuration object
|
|
2640
|
+
* @private
|
|
2641
|
+
*/
|
|
2642
|
+
_handleDockingPreview: function (oCfg) {
|
|
2643
|
+
var oDockProperties = oCfg ? oCfg.docked : false;
|
|
2644
|
+
var bIsDock = oDockProperties ? oDockProperties.setIsDockingAreaOpen : false;
|
|
2645
|
+
// check if need to open docking area and it doesn't exist already
|
|
2646
|
+
if (bIsDock && jQuery("#DockingAreaDiv").length === 0) {
|
|
2647
|
+
var bIsRTL = Configuration.getRTL();
|
|
2648
|
+
if ((oDockProperties.dockPos === "right" && oCfg.clone && !bIsRTL) || (oDockProperties.dockPos === "left" && oCfg.clone && bIsRTL)) {
|
|
2649
|
+
jQuery('<div id="DockingAreaDiv" class="sapUshellShellDisplayDockingAreaRight">').appendTo(oCfg.clone.parentElement);
|
|
2650
|
+
} else if ((oDockProperties.dockPos === "left" && oCfg.clone && !bIsRTL) || (oDockProperties.dockPos === "right" && oCfg.clone && bIsRTL)) {
|
|
2651
|
+
jQuery('<div id="DockingAreaDiv" class="sapUshellShellDisplayDockingAreaLeft">').appendTo(oCfg.clone.parentElement);
|
|
2652
|
+
}
|
|
2653
|
+
oCfg.clone.oDockedProp = {};
|
|
2654
|
+
oCfg.clone.oDockedProp.dockPos = oDockProperties.dockPos;
|
|
2655
|
+
// After drop the copilot - docking area should disappear
|
|
2656
|
+
} else if (!bIsDock) {
|
|
2657
|
+
window.setTimeout(function () {
|
|
2658
|
+
jQuery(".sapUshellShellDisplayDockingAreaRight").remove();
|
|
2659
|
+
jQuery(".sapUshellShellDisplayDockingAreaLeft").remove();
|
|
2660
|
+
}, 150);
|
|
2661
|
+
}
|
|
2662
|
+
},
|
|
2663
|
+
|
|
2664
|
+
/**
|
|
2665
|
+
* @returns {boolean} True if co-pilot is docked. Otherwise false.
|
|
2666
|
+
* @private
|
|
2667
|
+
*/
|
|
2668
|
+
_isFloatingContainerDocked: function () {
|
|
2669
|
+
return document.getElementsByClassName("sapUshellContainerDocked").length !== 0;
|
|
2670
|
+
},
|
|
2671
|
+
|
|
2672
|
+
/**
|
|
2673
|
+
* This function return whether the docking area open or not
|
|
2674
|
+
* @returns {boolean} if the docker area is opened
|
|
2675
|
+
* @private
|
|
2676
|
+
*/
|
|
2677
|
+
_isDockingAreaOpen: function () {
|
|
2678
|
+
return document.getElementsByClassName("sapUshellShellDisplayDockingAreaRight").length !== 0
|
|
2679
|
+
|| document.getElementsByClassName("sapUshellShellDisplayDockingAreaLeft").length !== 0;
|
|
2680
|
+
},
|
|
2681
|
+
|
|
2682
|
+
/**
|
|
2683
|
+
* This function open the canvas so there will be place for the docking area
|
|
2684
|
+
* @param {object} oDockedProp dock properties object
|
|
2685
|
+
* @private
|
|
2686
|
+
*/
|
|
2687
|
+
_moveFloatingContainerIntoDock: function (oDockedProp) {
|
|
2688
|
+
var bIsRTL = Configuration.getRTL();
|
|
2689
|
+
var oWrapper = document.getElementById(ShellLayoutMapping.FloatingContainer);
|
|
2690
|
+
oWrapper.classList.add("sapUshellContainerDocked");
|
|
2691
|
+
|
|
2692
|
+
var sPlaceholderId;
|
|
2693
|
+
if ((oDockedProp.dockPos === "left" && !bIsRTL) || oDockedProp.dockPos === "right" && bIsRTL) {
|
|
2694
|
+
sPlaceholderId = ShellLayoutMapping.FloatingContainerDockStart;
|
|
2695
|
+
} else {
|
|
2696
|
+
sPlaceholderId = ShellLayoutMapping.FloatingContainerDockEnd;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
// Flex Layout already takes care of start / end
|
|
2700
|
+
if (oDockedProp.dockPos === "left") {
|
|
2701
|
+
oWrapper.classList.add("sapUshellContainerDockedStart");
|
|
2702
|
+
oWrapper.classList.remove("sapUshellContainerDockedEnd");
|
|
2703
|
+
} else {
|
|
2704
|
+
oWrapper.classList.remove("sapUshellContainerDockedStart");
|
|
2705
|
+
oWrapper.classList.add("sapUshellContainerDockedEnd");
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
var oPlaceHolder = document.getElementById(sPlaceholderId);
|
|
2709
|
+
oPlaceHolder.appendChild(oWrapper);
|
|
2710
|
+
|
|
2711
|
+
this._expandFloatingContainerToDock();
|
|
2712
|
+
this._emitFloatingContainerResizeEvent();
|
|
2713
|
+
},
|
|
2714
|
+
|
|
2715
|
+
_removeFloatingContainerFromDock: function () {
|
|
2716
|
+
var oWrapper = document.getElementById(ShellLayoutMapping.FloatingContainer);
|
|
2717
|
+
document.body.appendChild(oWrapper);
|
|
2718
|
+
|
|
2719
|
+
oWrapper.classList.remove("sapUshellContainerDocked");
|
|
2720
|
+
oWrapper.classList.remove("sapUshellContainerDockedStart");
|
|
2721
|
+
oWrapper.classList.remove("sapUshellContainerDockedEnd");
|
|
2722
|
+
|
|
2723
|
+
this._emitFloatingContainerResizeEvent();
|
|
2724
|
+
},
|
|
2725
|
+
|
|
2726
|
+
/**
|
|
2727
|
+
* Handle the height of the copilot + add animations for ir
|
|
2728
|
+
* @param {object} oEvent event object
|
|
2729
|
+
* @private
|
|
2730
|
+
*/
|
|
2731
|
+
_onFloatingContainerDragEnd: function (oEvent) {
|
|
2732
|
+
// if movement X && Y is 0 its means there is no drag was made only click
|
|
2733
|
+
var iWindowWidth = jQuery(window).width();
|
|
2734
|
+
|
|
2735
|
+
if (this._isFloatingContainerDocked()) {
|
|
2736
|
+
if (oEvent && (oEvent.clientX >= iWindowWidth - 64 || oEvent.clientX < 64)) { // if less then 64 its just a click - no need to animate
|
|
2737
|
+
this._startFloatingContainerAnimation(false);
|
|
2738
|
+
}
|
|
2739
|
+
} else {
|
|
2740
|
+
// jQuery("#sapUshellFloatingContainerWrapper").removeClass("sapUshellContainerDockedMinimizeCoPilot sapUshellContainerDockedExtendCoPilot");
|
|
2741
|
+
}
|
|
2742
|
+
},
|
|
2743
|
+
|
|
2744
|
+
_handleFloatingContainerDrop: function (oEvent, floatingContainerWrapper, oDelta) {
|
|
2745
|
+
Measurement.start("FLP:Shell.controller._handleFloatingContainerDrop", "drop floating container", "FLP");
|
|
2746
|
+
var oFloatingContainer = floatingContainerWrapper.firstChild ? Core.byId(floatingContainerWrapper.firstChild.id) : undefined;
|
|
2747
|
+
var oStorage = new Storage(Storage.Type.local, "com.sap.ushell.adapters.local.FloatingContainer");
|
|
2748
|
+
var iWindowWidth = jQuery(window).width();
|
|
2749
|
+
var iWindowHeight = jQuery(window).height();
|
|
2750
|
+
var iPosLeft = oDelta.deltaX / iWindowWidth;
|
|
2751
|
+
var iPosTop = -oDelta.deltaY / iWindowHeight;
|
|
2752
|
+
var sOrigContainerVisibility = floatingContainerWrapper.style.visibility;
|
|
2753
|
+
var sOrigContainerDisplay = floatingContainerWrapper.style.display;
|
|
2754
|
+
var iContainerLeft = parseFloat(floatingContainerWrapper.style.left.replace("%", ""));
|
|
2755
|
+
var iContainerTop = parseFloat(floatingContainerWrapper.style.top.replace("%", ""));
|
|
2756
|
+
|
|
2757
|
+
if (typeof (iContainerLeft) === "number") {
|
|
2758
|
+
iPosLeft = iContainerLeft + 100 * oDelta.deltaX / iWindowWidth;
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
if (typeof (iContainerTop) === "number") {
|
|
2762
|
+
iPosTop = iContainerTop + 100 * oDelta.deltaY / iWindowHeight;
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
// when docking area is open - means the copilot should be on top of the screen
|
|
2766
|
+
if (this._isDockingAreaOpen()) {
|
|
2767
|
+
iPosTop = 0;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
floatingContainerWrapper.style.left = iPosLeft + "%";
|
|
2771
|
+
floatingContainerWrapper.style.top = iPosTop + "%";
|
|
2772
|
+
floatingContainerWrapper.style.position = "absolute";
|
|
2773
|
+
floatingContainerWrapper.style.display = "block";
|
|
2774
|
+
floatingContainerWrapper.visibility = sOrigContainerVisibility;
|
|
2775
|
+
floatingContainerWrapper.display = sOrigContainerDisplay;
|
|
2776
|
+
|
|
2777
|
+
oStorage.put("floatingContainerStyle", floatingContainerWrapper.style.cssText);
|
|
2778
|
+
// call resizeHandler to adjust the size and position of the floating container in case it was dropped out of the window size boundaries
|
|
2779
|
+
if (oFloatingContainer) {
|
|
2780
|
+
oFloatingContainer.handleDrop();
|
|
2781
|
+
// when docking area is open and the copilot drop inside - should handle it
|
|
2782
|
+
if (oDelta.clone.oDockedProp && this._isDockingAreaOpen()) {
|
|
2783
|
+
this._finishDoDock(oDelta.clone.oDockedProp);
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
Measurement.end("FLP:Shell.controller.handleFloatingContainerDrop");
|
|
2787
|
+
},
|
|
2788
|
+
|
|
2789
|
+
// This function called after co-pilot start to be dragged
|
|
2790
|
+
_handleFloatingContainerDrag: function (evt, ui) {
|
|
2791
|
+
Measurement.start("FLP:Shell.controller._handleFloatingContainerUIStart", "starts dragging floating container", "FLP");
|
|
2792
|
+
var floatingContainer = ui;
|
|
2793
|
+
floatingContainer.style.display = "none";
|
|
2794
|
+
if (window.getSelection) {
|
|
2795
|
+
var selection = window.getSelection();
|
|
2796
|
+
// for IE
|
|
2797
|
+
try {
|
|
2798
|
+
selection.removeAllRanges();
|
|
2799
|
+
} catch (e) {
|
|
2800
|
+
// continue regardless of error
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
Measurement.end("FLP:Shell.controller._handleFloatingContainerUIStart");
|
|
2804
|
+
},
|
|
2805
|
+
|
|
2806
|
+
// This function open local storage and return the docked state: docked or floating
|
|
2807
|
+
getFloatingContainerState: function () {
|
|
2808
|
+
var oStorage = new Storage(Storage.Type.local, "com.sap.ushell.adapters.local.CopilotLastState");
|
|
2809
|
+
var sLastState = "floating";
|
|
2810
|
+
if (oStorage !== null) {
|
|
2811
|
+
sLastState = oStorage.get("lastState");
|
|
2812
|
+
if (sLastState === null) {
|
|
2813
|
+
sLastState = "floating";
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
return sLastState;
|
|
2817
|
+
},
|
|
2818
|
+
|
|
2819
|
+
_saveFloatingContainerState: function (sState) {
|
|
2820
|
+
var oStorage = new Storage(Storage.Type.local, "com.sap.ushell.adapters.local.CopilotLastState");
|
|
2821
|
+
oStorage.put("lastState", sState);
|
|
2822
|
+
},
|
|
2823
|
+
|
|
2824
|
+
setFloatingContainerVisibility: function (bVisible) {
|
|
2825
|
+
if (!this._oFloatingContainerPromise) {
|
|
2826
|
+
this._oFloatingContainerPromise = this.getView().createFloatingContainer();
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
this.getView().getModel("helper").setProperty("/shell/floatingContainerVisible", bVisible);
|
|
2830
|
+
|
|
2831
|
+
return this._oFloatingContainerPromise.then(function () {
|
|
2832
|
+
var sLastState = this.getFloatingContainerState() || "";
|
|
2833
|
+
|
|
2834
|
+
if (sLastState === "floating") {
|
|
2835
|
+
// no initial handling required
|
|
2836
|
+
} else if (sLastState.indexOf("docked") !== -1) {
|
|
2837
|
+
if (bVisible) {
|
|
2838
|
+
if (this._isFloatingContainerDockSupported()) {
|
|
2839
|
+
var sDockPos = sLastState.indexOf("right") !== -1 ? "right" : "left";
|
|
2840
|
+
this._moveFloatingContainerIntoDock({ dockPos: sDockPos });
|
|
2841
|
+
this._startFloatingContainerAnimation(true);
|
|
2842
|
+
|
|
2843
|
+
} else {
|
|
2844
|
+
this._saveFloatingContainerState("floating");
|
|
2845
|
+
}
|
|
2846
|
+
} else {
|
|
2847
|
+
// case : undock from button
|
|
2848
|
+
this._startFloatingContainerAnimation(false);
|
|
2849
|
+
}
|
|
2850
|
+
this._emitFloatingContainerResizeEvent();
|
|
2851
|
+
}
|
|
2852
|
+
}.bind(this));
|
|
2853
|
+
},
|
|
2854
|
+
|
|
2855
|
+
getFloatingContainerVisibility: function () {
|
|
2856
|
+
return this.getView().getModel("helper").getProperty("/shell/floatingContainerVisible");
|
|
2857
|
+
},
|
|
2858
|
+
|
|
2859
|
+
setFloatingContainerContent: function (sPropertyString, aIds, bCurrentState, aStates) {
|
|
2860
|
+
oShellModel.setFloatingContainerContent(sPropertyString, aIds, bCurrentState, aStates);
|
|
2861
|
+
},
|
|
2862
|
+
|
|
2863
|
+
getRightFloatingContainerVisibility: function () {
|
|
2864
|
+
var oRightFloatingContainer = this.getView().getRightFloatingContainer();
|
|
2865
|
+
var bRightFloatingContainerVisible = oRightFloatingContainer && oRightFloatingContainer.getVisible();
|
|
2866
|
+
|
|
2867
|
+
return bRightFloatingContainerVisible;
|
|
2868
|
+
},
|
|
2869
|
+
|
|
2870
|
+
setHeaderTitle: function (sTitle) {
|
|
2871
|
+
HeaderManager.updateStates({
|
|
2872
|
+
propertyName: "title",
|
|
2873
|
+
value: sTitle || "",
|
|
2874
|
+
aStates: ["home", "app"],
|
|
2875
|
+
bCurrentState: false,
|
|
2876
|
+
bDoNotPropagate: false
|
|
2877
|
+
});
|
|
2878
|
+
},
|
|
2879
|
+
|
|
2880
|
+
setNavigationBar: function (oNavigationBar) {
|
|
2881
|
+
oNavigationBar.placeAt(ShellLayoutMapping.NavigationBar, "only");
|
|
2882
|
+
this.addDanglingControl(oNavigationBar);
|
|
2883
|
+
},
|
|
2884
|
+
|
|
2885
|
+
setShellShapes: function (oShellShapes) {
|
|
2886
|
+
if (oShellShapes.placeAt) {
|
|
2887
|
+
oShellShapes.placeAt(ShellLayoutMapping.ShellShapes, "only");
|
|
2888
|
+
this.addDanglingControl(oShellShapes);
|
|
2889
|
+
} else if (oShellShapes instanceof Node) {
|
|
2890
|
+
document.getElementById(ShellLayoutMapping.ShellShapes).appendChild(oShellShapes);
|
|
2891
|
+
}
|
|
2892
|
+
},
|
|
2893
|
+
|
|
2894
|
+
setFooter: function (oFooter) {
|
|
2895
|
+
var oView = this.getView();
|
|
2896
|
+
var oHelperModel = oView.getModel("helper");
|
|
2897
|
+
if (typeof oFooter !== "object" || !oFooter.getId) {
|
|
2898
|
+
throw new Error("oFooter value is invalid");
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
var sOldFooterId = oHelperModel.getProperty("/shell/footerContent");
|
|
2902
|
+
if (sOldFooterId) {
|
|
2903
|
+
Log.warning("You can only set one footer. Replacing existing footer: " + sOldFooterId + ", with the new footer: " + oFooter.getId() + ".");
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
oHelperModel.setProperty("/shell/footerContent", oFooter.getId());
|
|
2907
|
+
oFooter.placeAt(ShellLayoutMapping.Footer, "only");
|
|
2908
|
+
this.addDanglingControl(oFooter);
|
|
2909
|
+
|
|
2910
|
+
if (oFooter._applyContextClassFor) {
|
|
2911
|
+
oFooter._applyContextClassFor("footer");
|
|
2912
|
+
}
|
|
2913
|
+
},
|
|
2914
|
+
|
|
2915
|
+
getFooterId: function () {
|
|
2916
|
+
var oView = this.getView();
|
|
2917
|
+
var oHelperModel = oView.getModel("helper");
|
|
2918
|
+
var sFooterId = oHelperModel.getProperty("/shell/footerContent");
|
|
2919
|
+
return sFooterId;
|
|
2920
|
+
},
|
|
2921
|
+
|
|
2922
|
+
removeFooter: function () {
|
|
2923
|
+
var oView = this.getView();
|
|
2924
|
+
var oHelperModel = oView.getModel("helper");
|
|
2925
|
+
var sFooterId = oHelperModel.getProperty("/shell/footerContent");
|
|
2926
|
+
|
|
2927
|
+
if (sFooterId) {
|
|
2928
|
+
var oFooter = Core.byId(sFooterId);
|
|
2929
|
+
if (oFooter && oFooter.destroy) {
|
|
2930
|
+
oFooter.destroy();
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
oHelperModel.setProperty("/shell/footerContent", "");
|
|
2935
|
+
},
|
|
2936
|
+
|
|
2937
|
+
addUserPreferencesEntry: function (entryObject, bGrouped) {
|
|
2938
|
+
this._validateUserPrefEntryConfiguration(entryObject, bGrouped);
|
|
2939
|
+
this._updateUserPrefModel(entryObject, bGrouped);
|
|
2940
|
+
},
|
|
2941
|
+
|
|
2942
|
+
addUserProfilingEntry: function (entryObject) {
|
|
2943
|
+
this._validateUserPrefEntryConfiguration(entryObject);
|
|
2944
|
+
this._updateProfilingModel(entryObject);
|
|
2945
|
+
},
|
|
2946
|
+
|
|
2947
|
+
_validateUserPrefEntryConfiguration: function (entryObject, bGrouped) {
|
|
2948
|
+
if ((!entryObject) || (typeof entryObject !== "object")) {
|
|
2949
|
+
throw new Error("object oConfig was not provided");
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
if (!entryObject.title) {
|
|
2953
|
+
throw new Error("title was not provided");
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
if (!entryObject.value) {
|
|
2957
|
+
throw new Error("value was not provided");
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
if (typeof entryObject.entryHelpID !== "undefined") {
|
|
2961
|
+
if (typeof entryObject.entryHelpID !== "string") {
|
|
2962
|
+
throw new Error("entryHelpID type is invalid");
|
|
2963
|
+
} else if (entryObject.entryHelpID === "") {
|
|
2964
|
+
throw new Error("entryHelpID should not be an empty string");
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
if (entryObject.title && typeof entryObject.title !== "string") {
|
|
2969
|
+
throw new Error("title type is invalid");
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
if (typeof entryObject.value !== "function" && typeof entryObject.value !== "string" && typeof entryObject.value !== "number") {
|
|
2973
|
+
throw new Error("value type is invalid");
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
[
|
|
2977
|
+
"onSave",
|
|
2978
|
+
"content",
|
|
2979
|
+
"onCancel"
|
|
2980
|
+
].forEach(function (sPropertyName) {
|
|
2981
|
+
if (entryObject[sPropertyName] && typeof entryObject[sPropertyName] !== "function") {
|
|
2982
|
+
throw new Error(sPropertyName + " type is " + typeof entryObject[sPropertyName] + " but should be a function");
|
|
2983
|
+
}
|
|
2984
|
+
});
|
|
2985
|
+
|
|
2986
|
+
if (bGrouped) {
|
|
2987
|
+
[
|
|
2988
|
+
{
|
|
2989
|
+
name: "groupingId",
|
|
2990
|
+
type: "string"
|
|
2991
|
+
},
|
|
2992
|
+
{
|
|
2993
|
+
name: "groupingTabTitle",
|
|
2994
|
+
type: "string"
|
|
2995
|
+
},
|
|
2996
|
+
{
|
|
2997
|
+
name: "groupingTabHelpId",
|
|
2998
|
+
type: "string"
|
|
2999
|
+
}
|
|
3000
|
+
].forEach(function (oProperty) {
|
|
3001
|
+
if (!entryObject[oProperty.name]) {
|
|
3002
|
+
throw new Error(oProperty.name + " is missing");
|
|
3003
|
+
} else if (typeof entryObject[oProperty.name] !== oProperty.type) {
|
|
3004
|
+
throw new Error(oProperty.name + " type is " + typeof entryObject[oProperty.name] + " but should be a " + oProperty.type);
|
|
3005
|
+
}
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
},
|
|
3009
|
+
|
|
3010
|
+
_createSessionHandler: function (oSessionConfig) {
|
|
3011
|
+
var that = this;
|
|
3012
|
+
var iLazyCreationTime = 20000;
|
|
3013
|
+
|
|
3014
|
+
sap.ui.require(["sap/ushell/SessionHandler"], function (SessionHandler) {
|
|
3015
|
+
that.oSessionHandler = new SessionHandler(AppLifeCycleAI);
|
|
3016
|
+
//we need to immediately init the logout logic that is needed
|
|
3017
|
+
//for cFLP without any delay
|
|
3018
|
+
that.oSessionHandler.initLogout();
|
|
3019
|
+
window.setTimeout(function () {
|
|
3020
|
+
that.oSessionHandler.init({
|
|
3021
|
+
sessionTimeoutReminderInMinutes: oSessionConfig.sessionTimeoutReminderInMinutes,
|
|
3022
|
+
sessionTimeoutIntervalInMinutes: oSessionConfig.sessionTimeoutIntervalInMinutes,
|
|
3023
|
+
sessionTimeoutTileStopRefreshIntervalInMinutes: oSessionConfig.sessionTimeoutTileStopRefreshIntervalInMinutes,
|
|
3024
|
+
enableAutomaticSignout: oSessionConfig.enableAutomaticSignout
|
|
3025
|
+
});
|
|
3026
|
+
}, iLazyCreationTime);
|
|
3027
|
+
});
|
|
3028
|
+
},
|
|
3029
|
+
|
|
3030
|
+
_getSessionHandler: function () {
|
|
3031
|
+
return this.oSessionHandler;
|
|
3032
|
+
},
|
|
3033
|
+
|
|
3034
|
+
_navBack: function () {
|
|
3035
|
+
// set meAria as closed when navigating back
|
|
3036
|
+
this.setUserActionsMenuSelected(false);
|
|
3037
|
+
AppLifeCycleAI.service().navigateBack();
|
|
3038
|
+
},
|
|
3039
|
+
|
|
3040
|
+
_updateUserPrefModel: function (entryObject, bGrouped) {
|
|
3041
|
+
var oNewEntry = this._getModelEntryFromEntryObject(entryObject);
|
|
3042
|
+
var aEntries = Config.last("/core/userPreferences/entries") || [];
|
|
3043
|
+
|
|
3044
|
+
if (bGrouped) {
|
|
3045
|
+
oNewEntry.groupingEnablement = true;
|
|
3046
|
+
oNewEntry.groupingId = entryObject.groupingId;
|
|
3047
|
+
oNewEntry.groupingTabTitle = entryObject.groupingTabTitle;
|
|
3048
|
+
oNewEntry.groupingTabHelpId = entryObject.groupingTabHelpId;
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
aEntries.push(oNewEntry);
|
|
3052
|
+
// Re-order the entries array to have the Home Page entry right after the Appearance entry (if both exist)
|
|
3053
|
+
aEntries = this._reorderUserPrefEntries(aEntries);
|
|
3054
|
+
Config.emit("/core/userPreferences/entries", aEntries);
|
|
3055
|
+
},
|
|
3056
|
+
|
|
3057
|
+
_updateProfilingModel: function (entryObject) {
|
|
3058
|
+
var oNewEntry = this._getModelEntryFromEntryObject(entryObject);
|
|
3059
|
+
var aProfilingEntries = Config.last("/core/userPreferences/profiling") || [];
|
|
3060
|
+
|
|
3061
|
+
aProfilingEntries.push(oNewEntry);
|
|
3062
|
+
Config.emit("/core/userPreferences/profiling", aProfilingEntries);
|
|
3063
|
+
},
|
|
3064
|
+
|
|
3065
|
+
_getModelEntryFromEntryObject: function (entryObject) {
|
|
3066
|
+
return {
|
|
3067
|
+
id: ushellUtils._getUid(),
|
|
3068
|
+
entryHelpID: entryObject.entryHelpID,
|
|
3069
|
+
title: entryObject.title,
|
|
3070
|
+
valueArgument: entryObject.value,
|
|
3071
|
+
valueResult: null,
|
|
3072
|
+
onSave: entryObject.onSave,
|
|
3073
|
+
onCancel: entryObject.onCancel,
|
|
3074
|
+
contentFunc: entryObject.content,
|
|
3075
|
+
contentResult: null,
|
|
3076
|
+
icon: entryObject.icon,
|
|
3077
|
+
provideEmptyWrapper: entryObject.provideEmptyWrapper
|
|
3078
|
+
};
|
|
3079
|
+
},
|
|
3080
|
+
|
|
3081
|
+
_reorderUserPrefEntries: function (aEntries) {
|
|
3082
|
+
var aNewEntries = [];
|
|
3083
|
+
var aOrderedIds = [
|
|
3084
|
+
"userAccountEntry",
|
|
3085
|
+
"themes",
|
|
3086
|
+
"homepageEntry",
|
|
3087
|
+
"spacesEntry",
|
|
3088
|
+
"userActivitiesEntry",
|
|
3089
|
+
"userProfiling",
|
|
3090
|
+
"language",
|
|
3091
|
+
"notificationsEntry",
|
|
3092
|
+
"userDefaultEntry"
|
|
3093
|
+
];
|
|
3094
|
+
var mSpecialEntries = {};
|
|
3095
|
+
|
|
3096
|
+
for (var i = aEntries.length - 1; i >= 0; i--) {
|
|
3097
|
+
if (aOrderedIds.indexOf(aEntries[i].id) !== -1) {
|
|
3098
|
+
var oSpecialEntry = aEntries.splice(i, 1)[0];
|
|
3099
|
+
mSpecialEntries[oSpecialEntry.id] = oSpecialEntry;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
aOrderedIds.forEach(function (sId) {
|
|
3104
|
+
var oEntry = mSpecialEntries[sId];
|
|
3105
|
+
if (oEntry) {
|
|
3106
|
+
aNewEntries.push(oEntry);
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3109
|
+
|
|
3110
|
+
return aNewEntries.concat(aEntries);
|
|
3111
|
+
},
|
|
3112
|
+
|
|
3113
|
+
getModel: function () {
|
|
3114
|
+
return oModel;
|
|
3115
|
+
},
|
|
3116
|
+
|
|
3117
|
+
_getConfig: function () {
|
|
3118
|
+
return oConfig || {};
|
|
3119
|
+
},
|
|
3120
|
+
|
|
3121
|
+
_getPersData: function (oPersonalizationId) {
|
|
3122
|
+
var oComponent = Component.getOwnerComponentFor(this.getView());
|
|
3123
|
+
return sap.ushell.Container.getServiceAsync("PersonalizationV2").then(async function (oPersonalizationService) {
|
|
3124
|
+
var oScope = {
|
|
3125
|
+
keyCategory: oPersonalizationService.constants.keyCategory.FIXED_KEY,
|
|
3126
|
+
writeFrequency: oPersonalizationService.constants.writeFrequency.LOW,
|
|
3127
|
+
clientStorageAllowed: true
|
|
3128
|
+
};
|
|
3129
|
+
var oPersonalizer = await oPersonalizationService.getPersonalizer(oPersonalizationId, oScope, oComponent);
|
|
3130
|
+
return oPersonalizer.getPersData();
|
|
3131
|
+
});
|
|
3132
|
+
},
|
|
3133
|
+
|
|
3134
|
+
// encapsulate access to location so that we can stub it easily in tests
|
|
3135
|
+
_getCurrentLocationHash: function () {
|
|
3136
|
+
return window.location.hash;
|
|
3137
|
+
},
|
|
3138
|
+
|
|
3139
|
+
setUserActionsMenuSelected: function (bSelected) {
|
|
3140
|
+
EventHub.emit("showUserActionsMenu", bSelected);
|
|
3141
|
+
},
|
|
3142
|
+
|
|
3143
|
+
getUserActionsMenuSelected: function () {
|
|
3144
|
+
return Config.last("/core/shell/model/currentViewPortState") === "LeftCenter";
|
|
3145
|
+
},
|
|
3146
|
+
|
|
3147
|
+
setNotificationsSelected: function (bSelected) {
|
|
3148
|
+
EventHub.emit("showNotifications", bSelected);
|
|
3149
|
+
},
|
|
3150
|
+
|
|
3151
|
+
getNotificationsSelected: function () {
|
|
3152
|
+
return Config.last("/core/shell/model/currentViewPortState") === "RightCenter";
|
|
3153
|
+
}
|
|
3154
|
+
});
|
|
3155
|
+
});
|