@sapui5/sap.fe.core 1.141.2 → 1.143.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/sap/fe/core/.library +4 -1
- package/src/sap/fe/core/ActionRuntime.js +78 -23
- package/src/sap/fe/core/ActionRuntime.ts +91 -35
- package/src/sap/fe/core/AppComponent.js +76 -6
- package/src/sap/fe/core/AppComponent.ts +91 -8
- package/src/sap/fe/core/AppStateHandler.js +7 -7
- package/src/sap/fe/core/AppStateHandler.ts +9 -8
- package/src/sap/fe/core/BaseController.js +8 -5
- package/src/sap/fe/core/BaseController.ts +6 -1
- package/src/sap/fe/core/CommonUtils.js +4 -123
- package/src/sap/fe/core/CommonUtils.ts +3 -172
- package/src/sap/fe/core/ExtensionAPI.js +3 -11
- package/src/sap/fe/core/ExtensionAPI.ts +3 -16
- package/src/sap/fe/core/PageController.js +64 -43
- package/src/sap/fe/core/PageController.ts +62 -47
- package/src/sap/fe/core/TemplateComponent.js +12 -1
- package/src/sap/fe/core/TemplateComponent.ts +16 -2
- package/src/sap/fe/core/buildingBlocks/BuildingBlock.js +37 -24
- package/src/sap/fe/core/buildingBlocks/BuildingBlock.ts +47 -31
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockSupport.js +1 -1
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockSupport.ts +4 -0
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.js +4 -1
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.ts +3 -0
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplatingBase.js +5 -3
- package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplatingBase.ts +5 -2
- package/src/sap/fe/core/controllerextensions/BaseControllerExtension.js +7 -5
- package/src/sap/fe/core/controllerextensions/BaseControllerExtension.ts +22 -2
- package/src/sap/fe/core/controllerextensions/CollaborativeDraft.js +82 -44
- package/src/sap/fe/core/controllerextensions/CollaborativeDraft.ts +92 -59
- package/src/sap/fe/core/controllerextensions/EditFlow.js +74 -48
- package/src/sap/fe/core/controllerextensions/EditFlow.ts +87 -50
- package/src/sap/fe/core/controllerextensions/InlineEditFlow.js +9 -7
- package/src/sap/fe/core/controllerextensions/InlineEditFlow.ts +17 -5
- package/src/sap/fe/core/controllerextensions/InternalRouting.js +37 -18
- package/src/sap/fe/core/controllerextensions/InternalRouting.ts +49 -17
- package/src/sap/fe/core/controllerextensions/KPIManagement.js +30 -15
- package/src/sap/fe/core/controllerextensions/KPIManagement.ts +32 -14
- package/src/sap/fe/core/controllerextensions/MessageHandler.js +9 -10
- package/src/sap/fe/core/controllerextensions/MessageHandler.ts +10 -9
- package/src/sap/fe/core/controllerextensions/Paginator.js +2 -2
- package/src/sap/fe/core/controllerextensions/Paginator.ts +1 -1
- package/src/sap/fe/core/controllerextensions/Placeholder.js +10 -2
- package/src/sap/fe/core/controllerextensions/Placeholder.ts +5 -1
- package/src/sap/fe/core/controllerextensions/Recommendations.js +3 -3
- package/src/sap/fe/core/controllerextensions/Recommendations.ts +2 -2
- package/src/sap/fe/core/controllerextensions/Routing.js +4 -4
- package/src/sap/fe/core/controllerextensions/Routing.ts +3 -6
- package/src/sap/fe/core/controllerextensions/Share.js +5 -5
- package/src/sap/fe/core/controllerextensions/Share.ts +4 -4
- package/src/sap/fe/core/controllerextensions/SideEffects.js +1 -1
- package/src/sap/fe/core/controllerextensions/SideEffects.ts +17 -2
- package/src/sap/fe/core/controllerextensions/collaboration/ActivityBase.js +2 -2
- package/src/sap/fe/core/controllerextensions/collaboration/ActivityBase.ts +1 -1
- package/src/sap/fe/core/controllerextensions/editFlow/NotApplicableContextDialog.js +3 -3
- package/src/sap/fe/core/controllerextensions/editFlow/NotApplicableContextDialog.tsx +3 -2
- package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.js +49 -21
- package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.ts +64 -24
- package/src/sap/fe/core/controllerextensions/editFlow/draft.js +37 -3
- package/src/sap/fe/core/controllerextensions/editFlow/draft.ts +41 -8
- package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.js +10 -4
- package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.ts +6 -1
- package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataOperation.js +6 -7
- package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataOperation.ts +5 -5
- package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataStrictHandling.js +2 -2
- package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataStrictHandling.ts +1 -1
- package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationMessage.js +2 -1
- package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationMessage.ts +1 -0
- package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationParameters.js +2 -1
- package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationParameters.ts +1 -0
- package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.js +21 -15
- package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.ts +18 -15
- package/src/sap/fe/core/controllerextensions/routing/RouterProxy.js +7 -6
- package/src/sap/fe/core/controllerextensions/routing/RouterProxy.ts +8 -5
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.js +9 -4
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.tsx +10 -4
- package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.js +3 -2
- package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.tsx +2 -1
- package/src/sap/fe/core/converters/ManifestSettings.js +7 -1
- package/src/sap/fe/core/converters/ManifestSettings.ts +37 -0
- package/src/sap/fe/core/converters/ManifestWrapper.js +29 -9
- package/src/sap/fe/core/converters/ManifestWrapper.ts +29 -11
- package/src/sap/fe/core/converters/MetaModelConverter.js +1 -1
- package/src/sap/fe/core/converters/MetaModelConverter.ts +1 -1
- package/src/sap/fe/core/converters/annotations/DataField.js +46 -19
- package/src/sap/fe/core/converters/annotations/DataField.ts +93 -19
- package/src/sap/fe/core/converters/common/AnnotationConverter.js +118 -39
- package/src/sap/fe/core/converters/controls/Common/Action.js +58 -21
- package/src/sap/fe/core/converters/controls/Common/Action.ts +72 -22
- package/src/sap/fe/core/converters/controls/Common/Chart.js +13 -3
- package/src/sap/fe/core/converters/controls/Common/Chart.ts +20 -4
- package/src/sap/fe/core/converters/controls/Common/Form.js +18 -3
- package/src/sap/fe/core/converters/controls/Common/Form.ts +23 -1
- package/src/sap/fe/core/converters/controls/Common/Table.js +87 -22
- package/src/sap/fe/core/converters/controls/Common/Table.ts +112 -21
- package/src/sap/fe/core/converters/controls/Common/filter/FilterRestrictions.js +243 -0
- package/src/sap/fe/core/converters/controls/Common/filter/FilterRestrictions.ts +309 -0
- package/src/sap/fe/core/converters/controls/Common/table/Columns.js +142 -58
- package/src/sap/fe/core/converters/controls/Common/table/Columns.ts +174 -79
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +7 -16
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +6 -17
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +16 -5
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +16 -5
- package/src/sap/fe/core/converters/helpers/Aggregation.js +12 -2
- package/src/sap/fe/core/converters/helpers/Aggregation.ts +11 -1
- package/src/sap/fe/core/converters/helpers/DataFieldHelper.js +27 -3
- package/src/sap/fe/core/converters/helpers/DataFieldHelper.ts +28 -1
- package/src/sap/fe/core/converters/helpers/ID.js +3 -1
- package/src/sap/fe/core/converters/helpers/ID.ts +1 -0
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +10 -5
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +13 -1
- package/src/sap/fe/core/converters/templates/ListReportConverter.js +11 -3
- package/src/sap/fe/core/converters/templates/ListReportConverter.ts +12 -4
- package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +19 -8
- package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +18 -7
- package/src/sap/fe/core/designtime/AnnotationBasedChanges.js +8 -3
- package/src/sap/fe/core/designtime/AnnotationBasedChanges.ts +7 -2
- package/src/sap/fe/core/flexibility/AppComponent.flexibility.js +55 -0
- package/src/sap/fe/core/flexibility/AppComponent.flexibility.ts +65 -0
- package/src/sap/fe/core/flexibility/XMLTools.js +71 -0
- package/src/sap/fe/core/flexibility/XMLTools.ts +61 -0
- package/src/sap/fe/core/fpm/manifest.json +2 -2
- package/src/sap/fe/core/helpers/AppStartupHelper.js +79 -25
- package/src/sap/fe/core/helpers/AppStartupHelper.ts +92 -32
- package/src/sap/fe/core/helpers/DeleteHelper.js +13 -13
- package/src/sap/fe/core/helpers/DeleteHelper.ts +17 -15
- package/src/sap/fe/core/helpers/ManifestHelper.js +6 -3
- package/src/sap/fe/core/helpers/ManifestHelper.ts +3 -0
- package/src/sap/fe/core/helpers/MetaModelFunction.js +12 -3
- package/src/sap/fe/core/helpers/MetaModelFunction.ts +11 -3
- package/src/sap/fe/core/helpers/ModelHelper.js +47 -11
- package/src/sap/fe/core/helpers/ModelHelper.ts +62 -15
- package/src/sap/fe/core/helpers/PasteHelper.js +6 -2
- package/src/sap/fe/core/helpers/PasteHelper.ts +5 -7
- package/src/sap/fe/core/helpers/TypeGuards.js +12 -2
- package/src/sap/fe/core/helpers/TypeGuards.ts +10 -1
- package/src/sap/fe/core/helpers/WebSocket.js +6 -7
- package/src/sap/fe/core/helpers/WebSocket.ts +10 -6
- package/src/sap/fe/core/library.js +33 -3
- package/src/sap/fe/core/library.ts +31 -1
- package/src/sap/fe/core/messagebundle.properties +8 -1
- package/src/sap/fe/core/messagebundle_ar.properties +8 -1
- package/src/sap/fe/core/messagebundle_bg.properties +10 -3
- package/src/sap/fe/core/messagebundle_ca.properties +7 -0
- package/src/sap/fe/core/messagebundle_cnr.properties +7 -0
- package/src/sap/fe/core/messagebundle_cs.properties +7 -0
- package/src/sap/fe/core/messagebundle_cy.properties +8 -1
- package/src/sap/fe/core/messagebundle_da.properties +7 -0
- package/src/sap/fe/core/messagebundle_de.properties +7 -0
- package/src/sap/fe/core/messagebundle_el.properties +7 -0
- package/src/sap/fe/core/messagebundle_en.properties +8 -1
- package/src/sap/fe/core/messagebundle_en_GB.properties +7 -0
- package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +8 -1
- package/src/sap/fe/core/messagebundle_es.properties +8 -1
- package/src/sap/fe/core/messagebundle_es_MX.properties +7 -0
- package/src/sap/fe/core/messagebundle_et.properties +7 -0
- package/src/sap/fe/core/messagebundle_fi.properties +7 -0
- package/src/sap/fe/core/messagebundle_fr.properties +16 -9
- package/src/sap/fe/core/messagebundle_fr_CA.properties +7 -0
- package/src/sap/fe/core/messagebundle_hi.properties +8 -1
- package/src/sap/fe/core/messagebundle_hr.properties +7 -0
- package/src/sap/fe/core/messagebundle_hu.properties +7 -0
- package/src/sap/fe/core/messagebundle_id.properties +7 -0
- package/src/sap/fe/core/messagebundle_it.properties +7 -0
- package/src/sap/fe/core/messagebundle_iw.properties +7 -0
- package/src/sap/fe/core/messagebundle_ja.properties +8 -1
- package/src/sap/fe/core/messagebundle_kk.properties +7 -0
- package/src/sap/fe/core/messagebundle_ko.properties +7 -0
- package/src/sap/fe/core/messagebundle_lt.properties +7 -0
- package/src/sap/fe/core/messagebundle_lv.properties +7 -0
- package/src/sap/fe/core/messagebundle_mk.properties +7 -0
- package/src/sap/fe/core/messagebundle_ms.properties +7 -0
- package/src/sap/fe/core/messagebundle_nl.properties +7 -0
- package/src/sap/fe/core/messagebundle_no.properties +9 -2
- package/src/sap/fe/core/messagebundle_pl.properties +7 -0
- package/src/sap/fe/core/messagebundle_pt.properties +7 -0
- package/src/sap/fe/core/messagebundle_pt_PT.properties +7 -0
- package/src/sap/fe/core/messagebundle_ro.properties +7 -0
- package/src/sap/fe/core/messagebundle_ru.properties +7 -0
- package/src/sap/fe/core/messagebundle_sh.properties +7 -0
- package/src/sap/fe/core/messagebundle_sk.properties +7 -0
- package/src/sap/fe/core/messagebundle_sl.properties +7 -0
- package/src/sap/fe/core/messagebundle_sr.properties +7 -0
- package/src/sap/fe/core/messagebundle_sv.properties +7 -0
- package/src/sap/fe/core/messagebundle_th.properties +7 -0
- package/src/sap/fe/core/messagebundle_tr.properties +7 -0
- package/src/sap/fe/core/messagebundle_uk.properties +7 -0
- package/src/sap/fe/core/messagebundle_vi.properties +7 -0
- package/src/sap/fe/core/messagebundle_zh_CN.properties +8 -1
- package/src/sap/fe/core/messagebundle_zh_TW.properties +7 -0
- package/src/sap/fe/core/rootView/Fcl.controller.js +21 -7
- package/src/sap/fe/core/rootView/Fcl.controller.ts +22 -5
- package/src/sap/fe/core/rootView/NavContainer.controller.js +1 -1
- package/src/sap/fe/core/rootView/NavContainer.controller.ts +2 -1
- package/src/sap/fe/core/rootView/RootViewBaseController.js +96 -88
- package/src/sap/fe/core/rootView/RootViewBaseController.ts +106 -96
- package/src/sap/fe/core/services/CollaborativeToolsServiceFactory.js +1 -1
- package/src/sap/fe/core/services/CollaborativeToolsServiceFactory.ts +9 -9
- package/src/sap/fe/core/services/EnvironmentServiceFactory.js +14 -10
- package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +15 -10
- package/src/sap/fe/core/services/RoutingServiceFactory.js +9 -4
- package/src/sap/fe/core/services/RoutingServiceFactory.ts +13 -6
- package/src/sap/fe/core/services/SideEffectsServiceFactory.js +9 -7
- package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +13 -8
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +57 -5
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +69 -10
- package/src/sap/fe/core/services/collaborativeDraftServiceFactory.js +33 -15
- package/src/sap/fe/core/services/collaborativeDraftServiceFactory.ts +31 -11
- package/src/sap/fe/core/templating/DisplayModeFormatter.js +4 -5
- package/src/sap/fe/core/templating/DisplayModeFormatter.ts +4 -6
- package/src/sap/fe/core/templating/UIFormatters.js +17 -2
- package/src/sap/fe/core/templating/UIFormatters.ts +25 -1
- package/src/sap/fe/core/types/sap.fe.core-auto-ext.d.js +10 -0
- package/src/sap/fe/core/types/sap.fe.core-auto-ext.d.ts +369 -0
- package/src/sap/fe/core/types/sap.fe.core-manual-ext.d.js +9 -0
- package/src/sap/fe/core/types/sap.fe.core-manual-ext.d.ts +49 -0
- package/ui5.yaml +2 -0
|
@@ -10,11 +10,11 @@ import Component from "sap/ui/core/Component";
|
|
|
10
10
|
import Lib from "sap/ui/core/Lib";
|
|
11
11
|
import type ODataModel from "sap/ui/model/odata/v4/ODataModel";
|
|
12
12
|
// OK since we are in designtime we can ignore that dependency
|
|
13
|
+
import CommonUtils from "sap/fe/core/CommonUtils";
|
|
13
14
|
import { hasCurrency, hasUnit, isCurrency, isUnit } from "sap/fe/core/templating/PropertyHelper";
|
|
14
15
|
import type Field from "sap/fe/macros/Field";
|
|
15
16
|
import type FormElement from "sap/ui/layout/form/FormElement";
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
|
17
|
-
import CommonUtils from "sap/fe/core/CommonUtils";
|
|
18
18
|
import AnnotationTypes from "sap/ui/rta/plugin/annotations/AnnotationTypes";
|
|
19
19
|
|
|
20
20
|
const resourceBundleDesigntime = Lib.getResourceBundleFor("sap.fe.core.designtime")!;
|
|
@@ -95,7 +95,12 @@ function collectProperties(
|
|
|
95
95
|
buildingBlock = buildingBlock.getParent();
|
|
96
96
|
}
|
|
97
97
|
let metaPath = contextPathToUse!;
|
|
98
|
-
if (
|
|
98
|
+
if (control.getBindingContext()) {
|
|
99
|
+
const contextMetaPath = metaModel?.getMetaPath(control.getBindingContext()?.getPath() ?? "");
|
|
100
|
+
if (contextMetaPath) {
|
|
101
|
+
metaPath = contextMetaPath;
|
|
102
|
+
}
|
|
103
|
+
} else if (buildingBlock) {
|
|
99
104
|
metaPath = buildingBlock.getProperty("metaPath") ?? contextPathToUse;
|
|
100
105
|
}
|
|
101
106
|
const properties: { property: Property; entityType: EntityType }[] = [];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* SAP UI development toolkit for HTML5 (SAPUI5)
|
|
3
|
+
* (c) Copyright 2009-2025 SAP SE. All rights reserved
|
|
4
|
+
*/
|
|
5
|
+
sap.ui.define(["sap/base/Log", "sap/fe/core/CommonUtils", "sap/fe/core/flexibility/XMLTools", "sap/ui/core/Component", "sap/ui/fl/apply/api/DelegateMediatorAPI"], function (Log, CommonUtils, XMLTools, Component, DelegateMediatorAPI) {
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
var addGeneratedIdsToControls = XMLTools.addGeneratedIdsToControls;
|
|
9
|
+
/**
|
|
10
|
+
* Runs the provided fragment through the templating engine if the app component is an instance of sap.fe.core.AppComponent
|
|
11
|
+
* This will ensure that all included building blocks will be resolved to their target controls.
|
|
12
|
+
* @param fragment The XML fragment to be processed
|
|
13
|
+
* @param propertyBag An object containing the app component, modifier, view, and optionally componentId
|
|
14
|
+
* @param propertyBag.appComponent
|
|
15
|
+
* @param propertyBag.modifier
|
|
16
|
+
* @param propertyBag.view
|
|
17
|
+
* @param propertyBag.componentId
|
|
18
|
+
* @returns A promise that resolves to the processed XML fragment as a string
|
|
19
|
+
*/
|
|
20
|
+
async function runTemplating(fragment, propertyBag) {
|
|
21
|
+
try {
|
|
22
|
+
if (propertyBag.appComponent.isA("sap.fe.core.AppComponent")) {
|
|
23
|
+
const templateComponent = propertyBag.componentId ? Component.getComponentById(propertyBag.componentId) : Component.getOwnerComponentFor(propertyBag.view);
|
|
24
|
+
const preprocessorContext = templateComponent?.preprocessorContext ?? {};
|
|
25
|
+
const fragmentXML = new DOMParser().parseFromString(fragment, "text/xml");
|
|
26
|
+
const templatedResult = await CommonUtils.templateControlFragment(fragmentXML.firstElementChild, {
|
|
27
|
+
models: preprocessorContext.models,
|
|
28
|
+
bindingContexts: preprocessorContext.bindingContexts
|
|
29
|
+
}, {
|
|
30
|
+
view: propertyBag.view,
|
|
31
|
+
isXML: true
|
|
32
|
+
}, propertyBag.modifier);
|
|
33
|
+
if (templatedResult instanceof Element) {
|
|
34
|
+
addGeneratedIdsToControls(templatedResult);
|
|
35
|
+
return templatedResult.outerHTML;
|
|
36
|
+
}
|
|
37
|
+
// If something goes wrong, fallback to the original fragment
|
|
38
|
+
return fragment;
|
|
39
|
+
} else {
|
|
40
|
+
return fragment;
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
Log.error("Error during Fiori Elements XML Templating in flexibility handler:", error);
|
|
44
|
+
return fragment;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Register a hook onto the addXML handler from Flex that will run the templating if the conditions are right
|
|
49
|
+
DelegateMediatorAPI.registerAddXMLAdjustFragmentHandler({
|
|
50
|
+
key: "FEXMLTemplating",
|
|
51
|
+
handler: runTemplating,
|
|
52
|
+
reference: "sap.fe.macros.BaseAddXMLAdjustFragmentHandler"
|
|
53
|
+
});
|
|
54
|
+
}, false);
|
|
55
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJydW5UZW1wbGF0aW5nIiwiZnJhZ21lbnQiLCJwcm9wZXJ0eUJhZyIsImFwcENvbXBvbmVudCIsImlzQSIsInRlbXBsYXRlQ29tcG9uZW50IiwiY29tcG9uZW50SWQiLCJDb21wb25lbnQiLCJnZXRDb21wb25lbnRCeUlkIiwiZ2V0T3duZXJDb21wb25lbnRGb3IiLCJ2aWV3IiwicHJlcHJvY2Vzc29yQ29udGV4dCIsImZyYWdtZW50WE1MIiwiRE9NUGFyc2VyIiwicGFyc2VGcm9tU3RyaW5nIiwidGVtcGxhdGVkUmVzdWx0IiwiQ29tbW9uVXRpbHMiLCJ0ZW1wbGF0ZUNvbnRyb2xGcmFnbWVudCIsImZpcnN0RWxlbWVudENoaWxkIiwibW9kZWxzIiwiYmluZGluZ0NvbnRleHRzIiwiaXNYTUwiLCJtb2RpZmllciIsIkVsZW1lbnQiLCJhZGRHZW5lcmF0ZWRJZHNUb0NvbnRyb2xzIiwib3V0ZXJIVE1MIiwiZXJyb3IiLCJMb2ciLCJEZWxlZ2F0ZU1lZGlhdG9yQVBJIiwicmVnaXN0ZXJBZGRYTUxBZGp1c3RGcmFnbWVudEhhbmRsZXIiLCJrZXkiLCJoYW5kbGVyIiwicmVmZXJlbmNlIl0sInNvdXJjZVJvb3QiOiIuIiwic291cmNlcyI6WyJBcHBDb21wb25lbnQuZmxleGliaWxpdHkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IExvZyBmcm9tIFwic2FwL2Jhc2UvTG9nXCI7XG5pbXBvcnQgdHlwZSBBcHBDb21wb25lbnQgZnJvbSBcInNhcC9mZS9jb3JlL0FwcENvbXBvbmVudFwiO1xuaW1wb3J0IHR5cGUgeyBGRVZpZXcgfSBmcm9tIFwic2FwL2ZlL2NvcmUvQmFzZUNvbnRyb2xsZXJcIjtcbmltcG9ydCB0eXBlIHsgQmFzZVRyZWVNb2RpZmllciB9IGZyb20gXCJzYXAvZmUvY29yZS9Db21tb25VdGlsc1wiO1xuaW1wb3J0IENvbW1vblV0aWxzIGZyb20gXCJzYXAvZmUvY29yZS9Db21tb25VdGlsc1wiO1xuaW1wb3J0IHsgYWRkR2VuZXJhdGVkSWRzVG9Db250cm9scyB9IGZyb20gXCJzYXAvZmUvY29yZS9mbGV4aWJpbGl0eS9YTUxUb29sc1wiO1xuaW1wb3J0IHR5cGUgVGVtcGxhdGVDb21wb25lbnQgZnJvbSBcInNhcC9mZS9jb3JlL1RlbXBsYXRlQ29tcG9uZW50XCI7XG5pbXBvcnQgdHlwZSB7IFhNTFByZXByb2Nlc3NvckNvbnRleHQgfSBmcm9tIFwic2FwL2ZlL2NvcmUvVGVtcGxhdGVDb21wb25lbnRcIjtcbmltcG9ydCBDb21wb25lbnQgZnJvbSBcInNhcC91aS9jb3JlL0NvbXBvbmVudFwiO1xuaW1wb3J0IERlbGVnYXRlTWVkaWF0b3JBUEkgZnJvbSBcInNhcC91aS9mbC9hcHBseS9hcGkvRGVsZWdhdGVNZWRpYXRvckFQSVwiO1xuXG4vKipcbiAqIFJ1bnMgdGhlIHByb3ZpZGVkIGZyYWdtZW50IHRocm91Z2ggdGhlIHRlbXBsYXRpbmcgZW5naW5lIGlmIHRoZSBhcHAgY29tcG9uZW50IGlzIGFuIGluc3RhbmNlIG9mIHNhcC5mZS5jb3JlLkFwcENvbXBvbmVudFxuICogVGhpcyB3aWxsIGVuc3VyZSB0aGF0IGFsbCBpbmNsdWRlZCBidWlsZGluZyBibG9ja3Mgd2lsbCBiZSByZXNvbHZlZCB0byB0aGVpciB0YXJnZXQgY29udHJvbHMuXG4gKiBAcGFyYW0gZnJhZ21lbnQgVGhlIFhNTCBmcmFnbWVudCB0byBiZSBwcm9jZXNzZWRcbiAqIEBwYXJhbSBwcm9wZXJ0eUJhZyBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgYXBwIGNvbXBvbmVudCwgbW9kaWZpZXIsIHZpZXcsIGFuZCBvcHRpb25hbGx5IGNvbXBvbmVudElkXG4gKiBAcGFyYW0gcHJvcGVydHlCYWcuYXBwQ29tcG9uZW50XG4gKiBAcGFyYW0gcHJvcGVydHlCYWcubW9kaWZpZXJcbiAqIEBwYXJhbSBwcm9wZXJ0eUJhZy52aWV3XG4gKiBAcGFyYW0gcHJvcGVydHlCYWcuY29tcG9uZW50SWRcbiAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBwcm9jZXNzZWQgWE1MIGZyYWdtZW50IGFzIGEgc3RyaW5nXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJ1blRlbXBsYXRpbmcoXG5cdGZyYWdtZW50OiBzdHJpbmcsXG5cdHByb3BlcnR5QmFnOiB7IGFwcENvbXBvbmVudDogQXBwQ29tcG9uZW50OyBtb2RpZmllcjogQmFzZVRyZWVNb2RpZmllcjsgdmlldzogRkVWaWV3OyBjb21wb25lbnRJZD86IHN0cmluZyB9XG4pOiBQcm9taXNlPHN0cmluZz4ge1xuXHR0cnkge1xuXHRcdGlmIChwcm9wZXJ0eUJhZy5hcHBDb21wb25lbnQuaXNBKFwic2FwLmZlLmNvcmUuQXBwQ29tcG9uZW50XCIpKSB7XG5cdFx0XHRjb25zdCB0ZW1wbGF0ZUNvbXBvbmVudCA9IChcblx0XHRcdFx0cHJvcGVydHlCYWcuY29tcG9uZW50SWRcblx0XHRcdFx0XHQ/IENvbXBvbmVudC5nZXRDb21wb25lbnRCeUlkKHByb3BlcnR5QmFnLmNvbXBvbmVudElkKVxuXHRcdFx0XHRcdDogQ29tcG9uZW50LmdldE93bmVyQ29tcG9uZW50Rm9yKHByb3BlcnR5QmFnLnZpZXcpXG5cdFx0XHQpIGFzIFRlbXBsYXRlQ29tcG9uZW50IHwgdW5kZWZpbmVkO1xuXHRcdFx0Y29uc3QgcHJlcHJvY2Vzc29yQ29udGV4dCA9ICh0ZW1wbGF0ZUNvbXBvbmVudD8ucHJlcHJvY2Vzc29yQ29udGV4dCA/PyB7fSkgYXMgWE1MUHJlcHJvY2Vzc29yQ29udGV4dDtcblx0XHRcdGNvbnN0IGZyYWdtZW50WE1MID0gbmV3IERPTVBhcnNlcigpLnBhcnNlRnJvbVN0cmluZyhmcmFnbWVudCwgXCJ0ZXh0L3htbFwiKTtcblx0XHRcdGNvbnN0IHRlbXBsYXRlZFJlc3VsdCA9IGF3YWl0IENvbW1vblV0aWxzLnRlbXBsYXRlQ29udHJvbEZyYWdtZW50KFxuXHRcdFx0XHRmcmFnbWVudFhNTC5maXJzdEVsZW1lbnRDaGlsZCxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG1vZGVsczogcHJlcHJvY2Vzc29yQ29udGV4dC5tb2RlbHMsXG5cdFx0XHRcdFx0YmluZGluZ0NvbnRleHRzOiBwcmVwcm9jZXNzb3JDb250ZXh0LmJpbmRpbmdDb250ZXh0c1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR7IHZpZXc6IHByb3BlcnR5QmFnLnZpZXcsIGlzWE1MOiB0cnVlIH0sXG5cdFx0XHRcdHByb3BlcnR5QmFnLm1vZGlmaWVyXG5cdFx0XHQpO1xuXHRcdFx0aWYgKHRlbXBsYXRlZFJlc3VsdCBpbnN0YW5jZW9mIEVsZW1lbnQpIHtcblx0XHRcdFx0YWRkR2VuZXJhdGVkSWRzVG9Db250cm9scyh0ZW1wbGF0ZWRSZXN1bHQpO1xuXHRcdFx0XHRyZXR1cm4gdGVtcGxhdGVkUmVzdWx0Lm91dGVySFRNTDtcblx0XHRcdH1cblx0XHRcdC8vIElmIHNvbWV0aGluZyBnb2VzIHdyb25nLCBmYWxsYmFjayB0byB0aGUgb3JpZ2luYWwgZnJhZ21lbnRcblx0XHRcdHJldHVybiBmcmFnbWVudDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIGZyYWdtZW50O1xuXHRcdH1cblx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRMb2cuZXJyb3IoXCJFcnJvciBkdXJpbmcgRmlvcmkgRWxlbWVudHMgWE1MIFRlbXBsYXRpbmcgaW4gZmxleGliaWxpdHkgaGFuZGxlcjpcIiwgZXJyb3IgYXMgRXJyb3IpO1xuXHRcdHJldHVybiBmcmFnbWVudDtcblx0fVxufVxuXG4vLyBSZWdpc3RlciBhIGhvb2sgb250byB0aGUgYWRkWE1MIGhhbmRsZXIgZnJvbSBGbGV4IHRoYXQgd2lsbCBydW4gdGhlIHRlbXBsYXRpbmcgaWYgdGhlIGNvbmRpdGlvbnMgYXJlIHJpZ2h0XG5EZWxlZ2F0ZU1lZGlhdG9yQVBJLnJlZ2lzdGVyQWRkWE1MQWRqdXN0RnJhZ21lbnRIYW5kbGVyKHtcblx0a2V5OiBcIkZFWE1MVGVtcGxhdGluZ1wiLFxuXHRoYW5kbGVyOiBydW5UZW1wbGF0aW5nLFxuXHRyZWZlcmVuY2U6IFwic2FwLmZlLm1hY3Jvcy5CYXNlQWRkWE1MQWRqdXN0RnJhZ21lbnRIYW5kbGVyXCJcbn0pO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztFQVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDQSxlQUFlQSxhQUFhQSxDQUMzQkMsUUFBZ0IsRUFDaEJDLFdBQTJHLEVBQ3pGO0lBQ2xCLElBQUk7TUFDSCxJQUFJQSxXQUFXLENBQUNDLFlBQVksQ0FBQ0MsR0FBRyxDQUFDLDBCQUEwQixDQUFDLEVBQUU7UUFDN0QsTUFBTUMsaUJBQWlCLEdBQ3RCSCxXQUFXLENBQUNJLFdBQVcsR0FDcEJDLFNBQVMsQ0FBQ0MsZ0JBQWdCLENBQUNOLFdBQVcsQ0FBQ0ksV0FBVyxDQUFDLEdBQ25EQyxTQUFTLENBQUNFLG9CQUFvQixDQUFDUCxXQUFXLENBQUNRLElBQUksQ0FDakI7UUFDbEMsTUFBTUMsbUJBQW1CLEdBQUlOLGlCQUFpQixFQUFFTSxtQkFBbUIsSUFBSSxDQUFDLENBQTRCO1FBQ3BHLE1BQU1DLFdBQVcsR0FBRyxJQUFJQyxTQUFTLENBQUMsQ0FBQyxDQUFDQyxlQUFlLENBQUNiLFFBQVEsRUFBRSxVQUFVLENBQUM7UUFDekUsTUFBTWMsZUFBZSxHQUFHLE1BQU1DLFdBQVcsQ0FBQ0MsdUJBQXVCLENBQ2hFTCxXQUFXLENBQUNNLGlCQUFpQixFQUM3QjtVQUNDQyxNQUFNLEVBQUVSLG1CQUFtQixDQUFDUSxNQUFNO1VBQ2xDQyxlQUFlLEVBQUVULG1CQUFtQixDQUFDUztRQUN0QyxDQUFDLEVBQ0Q7VUFBRVYsSUFBSSxFQUFFUixXQUFXLENBQUNRLElBQUk7VUFBRVcsS0FBSyxFQUFFO1FBQUssQ0FBQyxFQUN2Q25CLFdBQVcsQ0FBQ29CLFFBQ2IsQ0FBQztRQUNELElBQUlQLGVBQWUsWUFBWVEsT0FBTyxFQUFFO1VBQ3ZDQyx5QkFBeUIsQ0FBQ1QsZUFBZSxDQUFDO1VBQzFDLE9BQU9BLGVBQWUsQ0FBQ1UsU0FBUztRQUNqQztRQUNBO1FBQ0EsT0FBT3hCLFFBQVE7TUFDaEIsQ0FBQyxNQUFNO1FBQ04sT0FBT0EsUUFBUTtNQUNoQjtJQUNELENBQUMsQ0FBQyxPQUFPeUIsS0FBSyxFQUFFO01BQ2ZDLEdBQUcsQ0FBQ0QsS0FBSyxDQUFDLG9FQUFvRSxFQUFFQSxLQUFjLENBQUM7TUFDL0YsT0FBT3pCLFFBQVE7SUFDaEI7RUFDRDs7RUFFQTtFQUNBMkIsbUJBQW1CLENBQUNDLG1DQUFtQyxDQUFDO0lBQ3ZEQyxHQUFHLEVBQUUsaUJBQWlCO0lBQ3RCQyxPQUFPLEVBQUUvQixhQUFhO0lBQ3RCZ0MsU0FBUyxFQUFFO0VBQ1osQ0FBQyxDQUFDO0FBQUMiLCJpZ25vcmVMaXN0IjpbXX0=
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Log from "sap/base/Log";
|
|
2
|
+
import type AppComponent from "sap/fe/core/AppComponent";
|
|
3
|
+
import type { FEView } from "sap/fe/core/BaseController";
|
|
4
|
+
import type { BaseTreeModifier } from "sap/fe/core/CommonUtils";
|
|
5
|
+
import CommonUtils from "sap/fe/core/CommonUtils";
|
|
6
|
+
import { addGeneratedIdsToControls } from "sap/fe/core/flexibility/XMLTools";
|
|
7
|
+
import type TemplateComponent from "sap/fe/core/TemplateComponent";
|
|
8
|
+
import type { XMLPreprocessorContext } from "sap/fe/core/TemplateComponent";
|
|
9
|
+
import Component from "sap/ui/core/Component";
|
|
10
|
+
import DelegateMediatorAPI from "sap/ui/fl/apply/api/DelegateMediatorAPI";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Runs the provided fragment through the templating engine if the app component is an instance of sap.fe.core.AppComponent
|
|
14
|
+
* This will ensure that all included building blocks will be resolved to their target controls.
|
|
15
|
+
* @param fragment The XML fragment to be processed
|
|
16
|
+
* @param propertyBag An object containing the app component, modifier, view, and optionally componentId
|
|
17
|
+
* @param propertyBag.appComponent
|
|
18
|
+
* @param propertyBag.modifier
|
|
19
|
+
* @param propertyBag.view
|
|
20
|
+
* @param propertyBag.componentId
|
|
21
|
+
* @returns A promise that resolves to the processed XML fragment as a string
|
|
22
|
+
*/
|
|
23
|
+
async function runTemplating(
|
|
24
|
+
fragment: string,
|
|
25
|
+
propertyBag: { appComponent: AppComponent; modifier: BaseTreeModifier; view: FEView; componentId?: string }
|
|
26
|
+
): Promise<string> {
|
|
27
|
+
try {
|
|
28
|
+
if (propertyBag.appComponent.isA("sap.fe.core.AppComponent")) {
|
|
29
|
+
const templateComponent = (
|
|
30
|
+
propertyBag.componentId
|
|
31
|
+
? Component.getComponentById(propertyBag.componentId)
|
|
32
|
+
: Component.getOwnerComponentFor(propertyBag.view)
|
|
33
|
+
) as TemplateComponent | undefined;
|
|
34
|
+
const preprocessorContext = (templateComponent?.preprocessorContext ?? {}) as XMLPreprocessorContext;
|
|
35
|
+
const fragmentXML = new DOMParser().parseFromString(fragment, "text/xml");
|
|
36
|
+
const templatedResult = await CommonUtils.templateControlFragment(
|
|
37
|
+
fragmentXML.firstElementChild,
|
|
38
|
+
{
|
|
39
|
+
models: preprocessorContext.models,
|
|
40
|
+
bindingContexts: preprocessorContext.bindingContexts
|
|
41
|
+
},
|
|
42
|
+
{ view: propertyBag.view, isXML: true },
|
|
43
|
+
propertyBag.modifier
|
|
44
|
+
);
|
|
45
|
+
if (templatedResult instanceof Element) {
|
|
46
|
+
addGeneratedIdsToControls(templatedResult);
|
|
47
|
+
return templatedResult.outerHTML;
|
|
48
|
+
}
|
|
49
|
+
// If something goes wrong, fallback to the original fragment
|
|
50
|
+
return fragment;
|
|
51
|
+
} else {
|
|
52
|
+
return fragment;
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
Log.error("Error during Fiori Elements XML Templating in flexibility handler:", error as Error);
|
|
56
|
+
return fragment;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Register a hook onto the addXML handler from Flex that will run the templating if the conditions are right
|
|
61
|
+
DelegateMediatorAPI.registerAddXMLAdjustFragmentHandler({
|
|
62
|
+
key: "FEXMLTemplating",
|
|
63
|
+
handler: runTemplating,
|
|
64
|
+
reference: "sap.fe.macros.BaseAddXMLAdjustFragmentHandler"
|
|
65
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* SAP UI development toolkit for HTML5 (SAPUI5)
|
|
3
|
+
* (c) Copyright 2009-2025 SAP SE. All rights reserved
|
|
4
|
+
*/
|
|
5
|
+
sap.ui.define([], function () {
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
var _exports = {};
|
|
9
|
+
/**
|
|
10
|
+
* Traverses a DOM element and adds generated ID properties to nodes representing controls that are missing IDs.
|
|
11
|
+
* Controls are identified by local names starting with an uppercase letter.
|
|
12
|
+
* @param element The root DOM element to traverse
|
|
13
|
+
* @param prefix Optional prefix for generated IDs
|
|
14
|
+
* @returns The number of IDs that were generated and added
|
|
15
|
+
*/
|
|
16
|
+
function addGeneratedIdsToControls(element) {
|
|
17
|
+
let prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "generatedId";
|
|
18
|
+
let idCounter = 0;
|
|
19
|
+
const generatedIds = new Set();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Recursively traverses the DOM tree and processes each element.
|
|
23
|
+
* @param node The current element being processed
|
|
24
|
+
*/
|
|
25
|
+
function traverse(node) {
|
|
26
|
+
// Check if this is a control (local name starts with uppercase) and missing an ID
|
|
27
|
+
if (isControl(node) && !node.hasAttribute("id")) {
|
|
28
|
+
const generatedId = generateUniqueId(prefix, generatedIds);
|
|
29
|
+
node.setAttribute("id", generatedId);
|
|
30
|
+
generatedIds.add(generatedId);
|
|
31
|
+
idCounter++;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Recursively process all child elements
|
|
35
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
36
|
+
traverse(node.children[i]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Determines if an element represents a UI5 control based on its local name.
|
|
42
|
+
* @param controlElement The element to check
|
|
43
|
+
* @returns True if the element represents a control
|
|
44
|
+
*/
|
|
45
|
+
function isControl(controlElement) {
|
|
46
|
+
const localName = controlElement.localName ?? controlElement.tagName.toLowerCase();
|
|
47
|
+
return localName.length > 0 && localName.charAt(0) === localName.charAt(0).toUpperCase();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generates a unique ID that doesn't conflict with existing IDs.
|
|
52
|
+
* @param basePrefix The base prefix for the ID
|
|
53
|
+
* @param existingIds Set of already generated IDs
|
|
54
|
+
* @returns A unique ID string
|
|
55
|
+
*/
|
|
56
|
+
function generateUniqueId(basePrefix, existingIds) {
|
|
57
|
+
let counter = 1;
|
|
58
|
+
let candidateId = `${basePrefix}_${counter}`;
|
|
59
|
+
while (existingIds.has(candidateId) || document.getElementById(candidateId)) {
|
|
60
|
+
counter++;
|
|
61
|
+
candidateId = `${basePrefix}_${counter}`;
|
|
62
|
+
}
|
|
63
|
+
return candidateId;
|
|
64
|
+
}
|
|
65
|
+
traverse(element);
|
|
66
|
+
return idCounter;
|
|
67
|
+
}
|
|
68
|
+
_exports.addGeneratedIdsToControls = addGeneratedIdsToControls;
|
|
69
|
+
return _exports;
|
|
70
|
+
}, false);
|
|
71
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhZGRHZW5lcmF0ZWRJZHNUb0NvbnRyb2xzIiwiZWxlbWVudCIsInByZWZpeCIsImFyZ3VtZW50cyIsImxlbmd0aCIsInVuZGVmaW5lZCIsImlkQ291bnRlciIsImdlbmVyYXRlZElkcyIsIlNldCIsInRyYXZlcnNlIiwibm9kZSIsImlzQ29udHJvbCIsImhhc0F0dHJpYnV0ZSIsImdlbmVyYXRlZElkIiwiZ2VuZXJhdGVVbmlxdWVJZCIsInNldEF0dHJpYnV0ZSIsImFkZCIsImkiLCJjaGlsZHJlbiIsImNvbnRyb2xFbGVtZW50IiwibG9jYWxOYW1lIiwidGFnTmFtZSIsInRvTG93ZXJDYXNlIiwiY2hhckF0IiwidG9VcHBlckNhc2UiLCJiYXNlUHJlZml4IiwiZXhpc3RpbmdJZHMiLCJjb3VudGVyIiwiY2FuZGlkYXRlSWQiLCJoYXMiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwiX2V4cG9ydHMiXSwic291cmNlUm9vdCI6Ii4iLCJzb3VyY2VzIjpbIlhNTFRvb2xzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVHJhdmVyc2VzIGEgRE9NIGVsZW1lbnQgYW5kIGFkZHMgZ2VuZXJhdGVkIElEIHByb3BlcnRpZXMgdG8gbm9kZXMgcmVwcmVzZW50aW5nIGNvbnRyb2xzIHRoYXQgYXJlIG1pc3NpbmcgSURzLlxuICogQ29udHJvbHMgYXJlIGlkZW50aWZpZWQgYnkgbG9jYWwgbmFtZXMgc3RhcnRpbmcgd2l0aCBhbiB1cHBlcmNhc2UgbGV0dGVyLlxuICogQHBhcmFtIGVsZW1lbnQgVGhlIHJvb3QgRE9NIGVsZW1lbnQgdG8gdHJhdmVyc2VcbiAqIEBwYXJhbSBwcmVmaXggT3B0aW9uYWwgcHJlZml4IGZvciBnZW5lcmF0ZWQgSURzXG4gKiBAcmV0dXJucyBUaGUgbnVtYmVyIG9mIElEcyB0aGF0IHdlcmUgZ2VuZXJhdGVkIGFuZCBhZGRlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkR2VuZXJhdGVkSWRzVG9Db250cm9scyhlbGVtZW50OiBFbGVtZW50LCBwcmVmaXggPSBcImdlbmVyYXRlZElkXCIpOiBudW1iZXIge1xuXHRsZXQgaWRDb3VudGVyID0gMDtcblx0Y29uc3QgZ2VuZXJhdGVkSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cblx0LyoqXG5cdCAqIFJlY3Vyc2l2ZWx5IHRyYXZlcnNlcyB0aGUgRE9NIHRyZWUgYW5kIHByb2Nlc3NlcyBlYWNoIGVsZW1lbnQuXG5cdCAqIEBwYXJhbSBub2RlIFRoZSBjdXJyZW50IGVsZW1lbnQgYmVpbmcgcHJvY2Vzc2VkXG5cdCAqL1xuXHRmdW5jdGlvbiB0cmF2ZXJzZShub2RlOiBFbGVtZW50KTogdm9pZCB7XG5cdFx0Ly8gQ2hlY2sgaWYgdGhpcyBpcyBhIGNvbnRyb2wgKGxvY2FsIG5hbWUgc3RhcnRzIHdpdGggdXBwZXJjYXNlKSBhbmQgbWlzc2luZyBhbiBJRFxuXHRcdGlmIChpc0NvbnRyb2wobm9kZSkgJiYgIW5vZGUuaGFzQXR0cmlidXRlKFwiaWRcIikpIHtcblx0XHRcdGNvbnN0IGdlbmVyYXRlZElkID0gZ2VuZXJhdGVVbmlxdWVJZChwcmVmaXgsIGdlbmVyYXRlZElkcyk7XG5cdFx0XHRub2RlLnNldEF0dHJpYnV0ZShcImlkXCIsIGdlbmVyYXRlZElkKTtcblx0XHRcdGdlbmVyYXRlZElkcy5hZGQoZ2VuZXJhdGVkSWQpO1xuXHRcdFx0aWRDb3VudGVyKys7XG5cdFx0fVxuXG5cdFx0Ly8gUmVjdXJzaXZlbHkgcHJvY2VzcyBhbGwgY2hpbGQgZWxlbWVudHNcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IG5vZGUuY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcblx0XHRcdHRyYXZlcnNlKG5vZGUuY2hpbGRyZW5baV0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBEZXRlcm1pbmVzIGlmIGFuIGVsZW1lbnQgcmVwcmVzZW50cyBhIFVJNSBjb250cm9sIGJhc2VkIG9uIGl0cyBsb2NhbCBuYW1lLlxuXHQgKiBAcGFyYW0gY29udHJvbEVsZW1lbnQgVGhlIGVsZW1lbnQgdG8gY2hlY2tcblx0ICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgZWxlbWVudCByZXByZXNlbnRzIGEgY29udHJvbFxuXHQgKi9cblx0ZnVuY3Rpb24gaXNDb250cm9sKGNvbnRyb2xFbGVtZW50OiBFbGVtZW50KTogYm9vbGVhbiB7XG5cdFx0Y29uc3QgbG9jYWxOYW1lID0gY29udHJvbEVsZW1lbnQubG9jYWxOYW1lID8/IGNvbnRyb2xFbGVtZW50LnRhZ05hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRyZXR1cm4gbG9jYWxOYW1lLmxlbmd0aCA+IDAgJiYgbG9jYWxOYW1lLmNoYXJBdCgwKSA9PT0gbG9jYWxOYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBJRCB0aGF0IGRvZXNuJ3QgY29uZmxpY3Qgd2l0aCBleGlzdGluZyBJRHMuXG5cdCAqIEBwYXJhbSBiYXNlUHJlZml4IFRoZSBiYXNlIHByZWZpeCBmb3IgdGhlIElEXG5cdCAqIEBwYXJhbSBleGlzdGluZ0lkcyBTZXQgb2YgYWxyZWFkeSBnZW5lcmF0ZWQgSURzXG5cdCAqIEByZXR1cm5zIEEgdW5pcXVlIElEIHN0cmluZ1xuXHQgKi9cblx0ZnVuY3Rpb24gZ2VuZXJhdGVVbmlxdWVJZChiYXNlUHJlZml4OiBzdHJpbmcsIGV4aXN0aW5nSWRzOiBTZXQ8c3RyaW5nPik6IHN0cmluZyB7XG5cdFx0bGV0IGNvdW50ZXIgPSAxO1xuXHRcdGxldCBjYW5kaWRhdGVJZCA9IGAke2Jhc2VQcmVmaXh9XyR7Y291bnRlcn1gO1xuXG5cdFx0d2hpbGUgKGV4aXN0aW5nSWRzLmhhcyhjYW5kaWRhdGVJZCkgfHwgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoY2FuZGlkYXRlSWQpKSB7XG5cdFx0XHRjb3VudGVyKys7XG5cdFx0XHRjYW5kaWRhdGVJZCA9IGAke2Jhc2VQcmVmaXh9XyR7Y291bnRlcn1gO1xuXHRcdH1cblxuXHRcdHJldHVybiBjYW5kaWRhdGVJZDtcblx0fVxuXG5cdHRy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
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traverses a DOM element and adds generated ID properties to nodes representing controls that are missing IDs.
|
|
3
|
+
* Controls are identified by local names starting with an uppercase letter.
|
|
4
|
+
* @param element The root DOM element to traverse
|
|
5
|
+
* @param prefix Optional prefix for generated IDs
|
|
6
|
+
* @returns The number of IDs that were generated and added
|
|
7
|
+
*/
|
|
8
|
+
export function addGeneratedIdsToControls(element: Element, prefix = "generatedId"): number {
|
|
9
|
+
let idCounter = 0;
|
|
10
|
+
const generatedIds = new Set<string>();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Recursively traverses the DOM tree and processes each element.
|
|
14
|
+
* @param node The current element being processed
|
|
15
|
+
*/
|
|
16
|
+
function traverse(node: Element): void {
|
|
17
|
+
// Check if this is a control (local name starts with uppercase) and missing an ID
|
|
18
|
+
if (isControl(node) && !node.hasAttribute("id")) {
|
|
19
|
+
const generatedId = generateUniqueId(prefix, generatedIds);
|
|
20
|
+
node.setAttribute("id", generatedId);
|
|
21
|
+
generatedIds.add(generatedId);
|
|
22
|
+
idCounter++;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Recursively process all child elements
|
|
26
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
27
|
+
traverse(node.children[i]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Determines if an element represents a UI5 control based on its local name.
|
|
33
|
+
* @param controlElement The element to check
|
|
34
|
+
* @returns True if the element represents a control
|
|
35
|
+
*/
|
|
36
|
+
function isControl(controlElement: Element): boolean {
|
|
37
|
+
const localName = controlElement.localName ?? controlElement.tagName.toLowerCase();
|
|
38
|
+
return localName.length > 0 && localName.charAt(0) === localName.charAt(0).toUpperCase();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generates a unique ID that doesn't conflict with existing IDs.
|
|
43
|
+
* @param basePrefix The base prefix for the ID
|
|
44
|
+
* @param existingIds Set of already generated IDs
|
|
45
|
+
* @returns A unique ID string
|
|
46
|
+
*/
|
|
47
|
+
function generateUniqueId(basePrefix: string, existingIds: Set<string>): string {
|
|
48
|
+
let counter = 1;
|
|
49
|
+
let candidateId = `${basePrefix}_${counter}`;
|
|
50
|
+
|
|
51
|
+
while (existingIds.has(candidateId) || document.getElementById(candidateId)) {
|
|
52
|
+
counter++;
|
|
53
|
+
candidateId = `${basePrefix}_${counter}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return candidateId;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
traverse(element);
|
|
60
|
+
return idCounter;
|
|
61
|
+
}
|