@sapui5/sap.fe.core 1.100.0 → 1.102.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 +4 -4
- package/src/sap/fe/core/.library +2 -3
- package/src/sap/fe/core/AppComponent.js +23 -30
- package/src/sap/fe/core/AppComponent.ts +35 -40
- package/src/sap/fe/core/AppStateHandler.js +8 -8
- package/src/sap/fe/core/AppStateHandler.ts +11 -11
- package/src/sap/fe/core/BaseController.js +9 -9
- package/src/sap/fe/core/BaseController.ts +3 -4
- package/src/sap/fe/core/CommonUtils.js +122 -101
- package/src/sap/fe/core/CommonUtils.ts +239 -193
- package/src/sap/fe/core/ExtensionAPI.js +12 -13
- package/src/sap/fe/core/ExtensionAPI.ts +21 -31
- package/src/sap/fe/core/PageController.js +19 -13
- package/src/sap/fe/core/PageController.ts +40 -34
- package/src/sap/fe/core/TemplateComponent.js +198 -123
- package/src/sap/fe/core/TemplateComponent.ts +109 -121
- package/src/sap/fe/core/TemplateModel.js +7 -9
- package/src/sap/fe/core/TemplateModel.ts +3 -3
- package/src/sap/fe/core/buildingBlocks/AttributeModel.js +60 -0
- package/src/sap/fe/core/buildingBlocks/AttributeModel.ts +37 -0
- package/src/sap/fe/core/buildingBlocks/BuildingBlock.js +165 -0
- package/src/sap/fe/core/buildingBlocks/BuildingBlock.ts +178 -0
- package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.js +935 -0
- package/src/sap/fe/core/buildingBlocks/BuildingBlockRuntime.ts +837 -0
- package/src/sap/fe/core/buildingBlocks/TraceInfo.js +436 -0
- package/src/sap/fe/core/buildingBlocks/TraceInfo.ts +431 -0
- package/src/sap/fe/core/{BusyLocker.js → controllerextensions/BusyLocker.js} +1 -1
- package/src/sap/fe/core/{BusyLocker.ts → controllerextensions/BusyLocker.ts} +7 -7
- package/src/sap/fe/core/controllerextensions/EditFlow.js +660 -288
- package/src/sap/fe/core/controllerextensions/EditFlow.ts +513 -331
- package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +11 -11
- package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.ts +6 -7
- package/src/sap/fe/core/controllerextensions/InternalEditFlow.js +43 -25
- package/src/sap/fe/core/controllerextensions/InternalEditFlow.ts +132 -103
- package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +16 -16
- package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +64 -55
- package/src/sap/fe/core/controllerextensions/InternalRouting.js +166 -99
- package/src/sap/fe/core/controllerextensions/InternalRouting.ts +187 -149
- package/src/sap/fe/core/controllerextensions/KPIManagement.js +14 -14
- package/src/sap/fe/core/controllerextensions/KPIManagement.ts +12 -11
- package/src/sap/fe/core/controllerextensions/MassEdit.js +13 -12
- package/src/sap/fe/core/controllerextensions/MassEdit.ts +22 -22
- package/src/sap/fe/core/controllerextensions/MessageHandler.js +14 -26
- package/src/sap/fe/core/controllerextensions/MessageHandler.ts +20 -30
- package/src/sap/fe/core/controllerextensions/PageReady.js +25 -23
- package/src/sap/fe/core/controllerextensions/PageReady.ts +49 -47
- package/src/sap/fe/core/controllerextensions/Paginator.js +24 -15
- package/src/sap/fe/core/controllerextensions/Paginator.ts +35 -20
- package/src/sap/fe/core/controllerextensions/Placeholder.js +10 -10
- package/src/sap/fe/core/controllerextensions/Placeholder.ts +12 -14
- package/src/sap/fe/core/controllerextensions/Routing.js +11 -11
- package/src/sap/fe/core/controllerextensions/Routing.ts +12 -13
- package/src/sap/fe/core/controllerextensions/Share.js +34 -16
- package/src/sap/fe/core/controllerextensions/Share.ts +50 -32
- package/src/sap/fe/core/controllerextensions/SideEffects.js +15 -15
- package/src/sap/fe/core/controllerextensions/SideEffects.ts +64 -65
- package/src/sap/fe/core/controllerextensions/ViewState.js +27 -31
- package/src/sap/fe/core/controllerextensions/ViewState.ts +103 -102
- package/src/sap/fe/core/controllerextensions/collaboration/ActivityBase.js +105 -0
- package/src/sap/fe/core/controllerextensions/collaboration/ActivityBase.ts +98 -0
- package/src/sap/fe/core/controllerextensions/collaboration/ActivitySync.js +360 -0
- package/src/sap/fe/core/{actions → controllerextensions}/collaboration/ActivitySync.ts +90 -132
- package/src/sap/fe/core/controllerextensions/collaboration/CollaborationCommon.js +146 -0
- package/src/sap/fe/core/{actions → controllerextensions}/collaboration/CollaborationCommon.ts +18 -8
- package/src/sap/fe/core/controllerextensions/collaboration/Manage.js +264 -0
- package/src/sap/fe/core/{actions → controllerextensions}/collaboration/Manage.ts +35 -33
- package/src/sap/fe/core/controllerextensions/collaboration/ManageDialog.fragment.xml +100 -0
- package/src/sap/fe/core/{actions → controllerextensions}/collaboration/UserDetails.fragment.xml +5 -7
- package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.js +1584 -0
- package/src/sap/fe/core/{TransactionHelper.ts → controllerextensions/editFlow/TransactionHelper.ts} +190 -159
- package/src/sap/fe/core/controllerextensions/editFlow/draft.js +780 -0
- package/src/sap/fe/core/{actions → controllerextensions/editFlow}/draft.ts +329 -76
- package/src/sap/fe/core/controllerextensions/editFlow/operations.js +1149 -0
- package/src/sap/fe/core/{actions → controllerextensions/editFlow}/operations.ts +169 -97
- package/src/sap/fe/core/controllerextensions/editFlow/sticky.js +190 -0
- package/src/sap/fe/core/{actions → controllerextensions/editFlow}/sticky.ts +76 -12
- package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.js +592 -0
- package/src/sap/fe/core/{actions → controllerextensions/messageHandler}/messageHandling.ts +83 -60
- package/src/sap/fe/core/controllerextensions/routing/RouterProxy.js +940 -0
- package/src/sap/fe/core/{RouterProxy.ts → controllerextensions/routing/RouterProxy.ts} +52 -36
- package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +21 -18
- package/src/sap/fe/core/controls/Any.js +28 -0
- package/src/sap/fe/core/controls/Any.ts +30 -0
- package/src/sap/fe/core/controls/CommandExecution.js +50 -16
- package/src/sap/fe/core/controls/CommandExecution.ts +31 -22
- package/src/sap/fe/core/controls/ConditionalWrapper.js +136 -65
- package/src/sap/fe/core/controls/ConditionalWrapper.ts +49 -58
- package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.js +371 -0
- package/src/sap/fe/core/controls/CustomFilterFieldContentWrapper.ts +282 -0
- package/src/sap/fe/core/controls/CustomQuickViewPage.js +74 -36
- package/src/sap/fe/core/controls/CustomQuickViewPage.ts +23 -32
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossDraft.fragment.xml +52 -5
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.js +127 -67
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.ts +127 -67
- package/src/sap/fe/core/controls/FieldWrapper.js +171 -87
- package/src/sap/fe/core/controls/FieldWrapper.ts +69 -80
- package/src/sap/fe/core/controls/FileWrapper.js +360 -0
- package/src/sap/fe/core/controls/FileWrapper.ts +202 -0
- package/src/sap/fe/core/controls/FilterBar.js +154 -119
- package/src/sap/fe/core/controls/FilterBar.ts +128 -123
- package/src/sap/fe/core/controls/FormElementWrapper.js +102 -37
- package/src/sap/fe/core/controls/FormElementWrapper.ts +43 -35
- package/src/sap/fe/core/controls/MassEditSelect.js +33 -0
- package/src/sap/fe/core/controls/MassEditSelect.ts +45 -0
- package/src/sap/fe/core/controls/filterbar/FilterContainer.js +111 -89
- package/src/sap/fe/core/controls/filterbar/FilterContainer.ts +86 -82
- package/src/sap/fe/core/controls/filterbar/VisualFilter.js +242 -193
- package/src/sap/fe/core/controls/filterbar/VisualFilter.ts +211 -204
- package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.js +152 -116
- package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.ts +105 -105
- package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.js +2 -2
- package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.ts +23 -28
- package/src/sap/fe/core/controls/massEdit/MassEditDialog.fragment.xml +41 -81
- package/src/sap/fe/core/controls/massEdit/MassEditField.fragment.xml +107 -0
- package/src/sap/fe/core/controls/massEdit/MassEditHandlers.js +550 -35
- package/src/sap/fe/core/controls/massEdit/MassEditHandlers.ts +604 -35
- package/src/sap/fe/core/converters/ManifestSettings.js +3 -1
- package/src/sap/fe/core/converters/ManifestSettings.ts +9 -2
- package/src/sap/fe/core/converters/MetaModelConverter.js +11 -40
- package/src/sap/fe/core/converters/MetaModelConverter.ts +56 -84
- package/src/sap/fe/core/converters/annotations/DataField.js +20 -5
- package/src/sap/fe/core/converters/annotations/DataField.ts +27 -6
- package/src/sap/fe/core/converters/controls/Common/Action.js +14 -21
- package/src/sap/fe/core/converters/controls/Common/Action.ts +23 -28
- package/src/sap/fe/core/converters/controls/Common/Chart.js +17 -10
- package/src/sap/fe/core/converters/controls/Common/Chart.ts +20 -14
- package/src/sap/fe/core/converters/controls/Common/Form.js +16 -18
- package/src/sap/fe/core/converters/controls/Common/Form.ts +20 -20
- package/src/sap/fe/core/converters/controls/Common/KPI.js +1 -1
- package/src/sap/fe/core/converters/controls/Common/KPI.ts +2 -3
- package/src/sap/fe/core/converters/controls/Common/Table.js +389 -173
- package/src/sap/fe/core/converters/controls/Common/Table.ts +440 -244
- package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +26 -16
- package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +27 -19
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +78 -47
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +146 -107
- package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.js +6 -6
- package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.ts +20 -18
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +30 -25
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +39 -34
- package/src/sap/fe/core/converters/helpers/Aggregation.js +10 -2
- package/src/sap/fe/core/converters/helpers/Aggregation.ts +18 -13
- package/src/sap/fe/core/converters/helpers/BindingHelper.js +3 -2
- package/src/sap/fe/core/converters/helpers/BindingHelper.ts +6 -5
- package/src/sap/fe/core/converters/objectPage/FormMenuActions.js +1 -1
- package/src/sap/fe/core/converters/objectPage/FormMenuActions.ts +0 -4
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +27 -24
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +49 -40
- package/src/sap/fe/core/converters/templates/ListReportConverter.js +33 -22
- package/src/sap/fe/core/converters/templates/ListReportConverter.ts +77 -62
- package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +28 -28
- package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +38 -45
- package/src/sap/fe/core/designtime/AppComponent.designtime.js +3 -3
- package/src/sap/fe/core/designtime/AppComponent.designtime.ts +8 -6
- package/src/sap/fe/core/formatters/KPIFormatter.js +3 -12
- package/src/sap/fe/core/formatters/KPIFormatter.ts +3 -2
- package/src/sap/fe/core/formatters/TableFormatter.js +74 -13
- package/src/sap/fe/core/formatters/TableFormatter.ts +71 -16
- package/src/sap/fe/core/formatters/ValueFormatter.js +4 -4
- package/src/sap/fe/core/formatters/ValueFormatter.ts +4 -7
- package/src/sap/fe/core/fpm/Component.js +46 -17
- package/src/sap/fe/core/fpm/Component.ts +11 -16
- package/src/sap/fe/core/helpers/AppStartupHelper.js +4 -4
- package/src/sap/fe/core/helpers/AppStartupHelper.ts +3 -3
- package/src/sap/fe/core/helpers/BindingExpression.js +10 -7
- package/src/sap/fe/core/helpers/BindingExpression.ts +37 -35
- package/src/sap/fe/core/helpers/ClassSupport.js +273 -256
- package/src/sap/fe/core/helpers/ClassSupport.ts +315 -237
- package/src/sap/fe/core/helpers/FPMHelper.js +3 -2
- package/src/sap/fe/core/helpers/FPMHelper.ts +9 -8
- package/src/sap/fe/core/helpers/MassEditHelper.js +522 -147
- package/src/sap/fe/core/helpers/MassEditHelper.ts +563 -236
- package/src/sap/fe/core/helpers/ModelHelper.js +29 -1
- package/src/sap/fe/core/helpers/ModelHelper.ts +39 -26
- package/src/sap/fe/core/helpers/PasteHelper.js +4 -4
- package/src/sap/fe/core/helpers/PasteHelper.ts +4 -3
- package/src/sap/fe/core/helpers/SemanticDateOperators.js +3 -3
- package/src/sap/fe/core/helpers/SemanticDateOperators.ts +3 -1
- package/src/sap/fe/core/helpers/SemanticKeyHelper.js +1 -1
- package/src/sap/fe/core/helpers/SemanticKeyHelper.ts +1 -1
- package/src/sap/fe/core/helpers/StableIdHelper.js +5 -7
- package/src/sap/fe/core/helpers/StableIdHelper.ts +8 -8
- package/src/sap/fe/core/{Synchronization.js → helpers/Synchronization.js} +1 -1
- package/src/sap/fe/core/{Synchronization.ts → helpers/Synchronization.ts} +1 -1
- package/src/sap/fe/core/jsx-runtime/jsx.js +35 -5
- package/src/sap/fe/core/jsx-runtime/jsx.ts +22 -8
- package/src/sap/fe/core/library.js +13 -5
- package/src/sap/fe/core/library.ts +26 -17
- package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.js +1 -1
- package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.ts +0 -3
- package/src/sap/fe/core/messagebundle.properties +135 -180
- package/src/sap/fe/core/messagebundle_ar.properties +31 -64
- package/src/sap/fe/core/messagebundle_bg.properties +31 -64
- package/src/sap/fe/core/messagebundle_ca.properties +31 -64
- package/src/sap/fe/core/messagebundle_cs.properties +31 -64
- package/src/sap/fe/core/messagebundle_cy.properties +32 -65
- package/src/sap/fe/core/messagebundle_da.properties +31 -64
- package/src/sap/fe/core/messagebundle_de.properties +29 -62
- package/src/sap/fe/core/messagebundle_el.properties +32 -65
- package/src/sap/fe/core/messagebundle_en.properties +32 -65
- package/src/sap/fe/core/messagebundle_en_GB.properties +29 -62
- package/src/sap/fe/core/messagebundle_en_US_sappsd.properties +41 -74
- package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +32 -65
- package/src/sap/fe/core/messagebundle_en_US_saptrc.properties +20 -6
- package/src/sap/fe/core/messagebundle_es.properties +31 -64
- package/src/sap/fe/core/messagebundle_es_MX.properties +31 -64
- package/src/sap/fe/core/messagebundle_et.properties +31 -64
- package/src/sap/fe/core/messagebundle_fi.properties +29 -62
- package/src/sap/fe/core/messagebundle_fr.properties +36 -69
- package/src/sap/fe/core/messagebundle_fr_CA.properties +33 -66
- package/src/sap/fe/core/messagebundle_hi.properties +29 -62
- package/src/sap/fe/core/messagebundle_hr.properties +32 -65
- package/src/sap/fe/core/messagebundle_hu.properties +30 -63
- package/src/sap/fe/core/messagebundle_id.properties +32 -65
- package/src/sap/fe/core/messagebundle_it.properties +31 -64
- package/src/sap/fe/core/messagebundle_iw.properties +31 -64
- package/src/sap/fe/core/messagebundle_ja.properties +29 -62
- package/src/sap/fe/core/messagebundle_kk.properties +31 -64
- package/src/sap/fe/core/messagebundle_ko.properties +31 -64
- package/src/sap/fe/core/messagebundle_lt.properties +31 -64
- package/src/sap/fe/core/messagebundle_lv.properties +32 -65
- package/src/sap/fe/core/messagebundle_ms.properties +31 -64
- package/src/sap/fe/core/messagebundle_nl.properties +31 -64
- package/src/sap/fe/core/messagebundle_no.properties +31 -64
- package/src/sap/fe/core/messagebundle_pl.properties +34 -67
- package/src/sap/fe/core/messagebundle_pt.properties +32 -65
- package/src/sap/fe/core/messagebundle_pt_PT.properties +31 -64
- package/src/sap/fe/core/messagebundle_ro.properties +33 -66
- package/src/sap/fe/core/messagebundle_ru.properties +33 -66
- package/src/sap/fe/core/messagebundle_sh.properties +31 -64
- package/src/sap/fe/core/messagebundle_sk.properties +31 -64
- package/src/sap/fe/core/messagebundle_sl.properties +29 -62
- package/src/sap/fe/core/messagebundle_sv.properties +30 -63
- package/src/sap/fe/core/messagebundle_th.properties +31 -64
- package/src/sap/fe/core/messagebundle_tr.properties +31 -64
- package/src/sap/fe/core/messagebundle_uk.properties +32 -65
- package/src/sap/fe/core/messagebundle_vi.properties +31 -64
- package/src/sap/fe/core/messagebundle_zh_CN.properties +32 -65
- package/src/sap/fe/core/messagebundle_zh_TW.properties +34 -67
- package/src/sap/fe/core/services/AsyncComponentServiceFactory.js +4 -4
- package/src/sap/fe/core/services/AsyncComponentServiceFactory.ts +1 -1
- package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +5 -5
- package/src/sap/fe/core/services/CacheHandlerServiceFactory.ts +1 -2
- package/src/sap/fe/core/services/EnvironmentServiceFactory.js +11 -8
- package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +15 -13
- package/src/sap/fe/core/services/NavigationServiceFactory.js +5 -5
- package/src/sap/fe/core/services/NavigationServiceFactory.ts +9 -5
- package/src/sap/fe/core/services/ResourceModelServiceFactory.js +4 -4
- package/src/sap/fe/core/services/ResourceModelServiceFactory.ts +1 -1
- package/src/sap/fe/core/services/RoutingServiceFactory.js +105 -66
- package/src/sap/fe/core/services/RoutingServiceFactory.ts +59 -49
- package/src/sap/fe/core/services/ShellServicesFactory.js +104 -29
- package/src/sap/fe/core/services/ShellServicesFactory.ts +64 -30
- package/src/sap/fe/core/services/SideEffectsServiceFactory.js +4 -4
- package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +1 -1
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +11 -10
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +38 -51
- package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.js +43 -5
- package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.ts +6 -3
- package/src/sap/fe/core/support/CommonHelper.js +1 -1
- package/src/sap/fe/core/support/CommonHelper.ts +0 -3
- package/src/sap/fe/core/templating/DataModelPathHelper.js +2 -9
- package/src/sap/fe/core/templating/DataModelPathHelper.ts +32 -38
- package/src/sap/fe/core/templating/DisplayModeFormatter.js +23 -3
- package/src/sap/fe/core/templating/DisplayModeFormatter.ts +27 -6
- package/src/sap/fe/core/templating/EntitySetHelper.js +1 -9
- package/src/sap/fe/core/templating/EntitySetHelper.ts +11 -13
- package/src/sap/fe/core/templating/FilterHelper.js +4 -4
- package/src/sap/fe/core/templating/FilterHelper.ts +6 -5
- package/src/sap/fe/core/templating/PropertyHelper.js +70 -33
- package/src/sap/fe/core/templating/PropertyHelper.ts +49 -27
- package/src/sap/fe/core/templating/UIFormatters.js +133 -22
- package/src/sap/fe/core/templating/UIFormatters.ts +144 -50
- package/src/sap/fe/core/type/DateTimeWithTimezone.js +47 -0
- package/src/sap/fe/core/type/DateTimeWithTimezone.ts +23 -0
- package/src/sap/fe/core/type/Email.js +26 -8
- package/src/sap/fe/core/type/Email.ts +8 -7
- package/src/sap/fe/core/AnnotationHelper.js +0 -312
- package/src/sap/fe/core/AnnotationHelper.ts +0 -315
- package/src/sap/fe/core/RouterProxy.js +0 -926
- package/src/sap/fe/core/TransactionHelper.js +0 -1562
- package/src/sap/fe/core/actions/collaboration/ActivitySync.js +0 -392
- package/src/sap/fe/core/actions/collaboration/CollaborationCommon.js +0 -136
- package/src/sap/fe/core/actions/collaboration/Manage.js +0 -262
- package/src/sap/fe/core/actions/collaboration/ManageDialog.fragment.xml +0 -103
- package/src/sap/fe/core/actions/draft.js +0 -523
- package/src/sap/fe/core/actions/messageHandling.js +0 -567
- package/src/sap/fe/core/actions/nonDraft.js +0 -20
- package/src/sap/fe/core/actions/nonDraft.ts +0 -12
- package/src/sap/fe/core/actions/operations.js +0 -1096
- package/src/sap/fe/core/actions/sticky.js +0 -130
- package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.js +0 -78
- package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.ts +0 -65
- package/src/sap/fe/core/formatters/CriticalityFormatter.js +0 -77
- package/src/sap/fe/core/formatters/CriticalityFormatter.ts +0 -58
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
import Log from "sap/base/Log";
|
|
2
|
+
import uid from "sap/base/util/uid";
|
|
3
|
+
import AttributeModel from "sap/fe/core/buildingBlocks/AttributeModel";
|
|
4
|
+
import {
|
|
5
|
+
BuildingBlockAggregationDefinition,
|
|
6
|
+
BuildingBlockBase,
|
|
7
|
+
BuildingBlockDefinition,
|
|
8
|
+
BuildingBlockDefinitionV1,
|
|
9
|
+
BuildingBlockMetadata,
|
|
10
|
+
BuildingBlockMetadataContextDefinition,
|
|
11
|
+
BuildingBlockPropertyDefinition
|
|
12
|
+
} from "sap/fe/core/buildingBlocks/BuildingBlock";
|
|
13
|
+
import { compileBinding } from "sap/fe/core/helpers/BindingExpression";
|
|
14
|
+
import ResourceModel from "sap/fe/macros/ResourceModel";
|
|
15
|
+
import BindingParser from "sap/ui/base/BindingParser";
|
|
16
|
+
import XMLPreprocessor from "sap/ui/core/util/XMLPreprocessor";
|
|
17
|
+
import Context from "sap/ui/model/Context";
|
|
18
|
+
import JSONModel from "sap/ui/model/json/JSONModel";
|
|
19
|
+
import TraceInfo from "./TraceInfo";
|
|
20
|
+
|
|
21
|
+
const LOGGER_SCOPE = "sap.fe.core.buildingBlocks.BuildingBlockRuntime";
|
|
22
|
+
const DOMParserInstance = new DOMParser();
|
|
23
|
+
let isTraceMode = false;
|
|
24
|
+
|
|
25
|
+
type ResolvedBuildingBlockMetadata = {
|
|
26
|
+
properties: Record<string, BuildingBlockPropertyDefinition>;
|
|
27
|
+
aggregations: Record<string, BuildingBlockAggregationDefinition>;
|
|
28
|
+
metadataContexts: Record<string, BuildingBlockMetadataContextDefinition>;
|
|
29
|
+
isOpen: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type ICallback = {
|
|
33
|
+
getSettings(): any;
|
|
34
|
+
/**
|
|
35
|
+
* Visits the given node and either processes a template instruction, calls
|
|
36
|
+
* a visitor, or simply calls both {@link
|
|
37
|
+
* sap.ui.core.util.XMLPreprocessor.ICallback.visitAttributes visitAttributes}
|
|
38
|
+
* and {@link sap.ui.core.util.XMLPreprocessor.ICallback.visitChildNodes
|
|
39
|
+
* visitChildNodes}.
|
|
40
|
+
*
|
|
41
|
+
* @param {Node} oNode
|
|
42
|
+
* The XML DOM node
|
|
43
|
+
* @returns {sap.ui.base.SyncPromise}
|
|
44
|
+
* A thenable which resolves with <code>undefined</code> as soon as visiting
|
|
45
|
+
* is done, or is rejected with a corresponding error if visiting fails
|
|
46
|
+
**/
|
|
47
|
+
visitNode(oNode: Node): Promise<void>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Inserts the fragment with the given name in place of the given element. Loads the
|
|
51
|
+
* fragment, takes care of caching (for the current pre-processor run) and visits the
|
|
52
|
+
* fragment's content once it has been imported into the element's owner document and
|
|
53
|
+
* put into place. Loading of fragments is asynchronous if the template view is
|
|
54
|
+
* asynchronous.
|
|
55
|
+
*
|
|
56
|
+
* @param {string} sFragmentName
|
|
57
|
+
* the fragment's resolved name
|
|
58
|
+
* @param {Element} oElement
|
|
59
|
+
* the XML DOM element, e.g. <sap.ui.core:Fragment> or <core:ExtensionPoint>
|
|
60
|
+
* @param {sap.ui.core.util._with} oWithControl
|
|
61
|
+
* the parent's "with" control
|
|
62
|
+
* @returns {sap.ui.base.SyncPromise}
|
|
63
|
+
* A sync promise which resolves with <code>undefined</code> as soon as the fragment
|
|
64
|
+
* has been inserted, or is rejected with a corresponding error if loading or visiting
|
|
65
|
+
* fails.
|
|
66
|
+
*/
|
|
67
|
+
insertFragment(sFragment: string, oElement: Element, oWith?: any): Promise<void>;
|
|
68
|
+
visitAttribute(oNode: Element, oAttribute: Attr): Promise<void>;
|
|
69
|
+
visitChildNodes(oNode: Node): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Interprets the given XML DOM attribute value as a binding and returns the
|
|
72
|
+
* resulting value.
|
|
73
|
+
* @param {string} sValue
|
|
74
|
+
* An XML DOM attribute value
|
|
75
|
+
* @param {Element} [oElement]
|
|
76
|
+
* The XML DOM element the attribute value belongs to (needed only for
|
|
77
|
+
* warnings which are logged to the console)
|
|
78
|
+
* @returns {sap.ui.base.SyncPromise|null}
|
|
79
|
+
* A thenable which resolves with the resulting value, or is rejected with a
|
|
80
|
+
* corresponding error (for example, an error thrown by a formatter) or
|
|
81
|
+
* <code>null</code> in case the binding is not ready (because it refers to a
|
|
82
|
+
* model which is not available) (since 1.57.0)
|
|
83
|
+
*/
|
|
84
|
+
getResult(sValue: string, element?: Element): Promise<any> | null;
|
|
85
|
+
getContext(sPath: string): Context;
|
|
86
|
+
/**
|
|
87
|
+
* Returns a callback interface instance for the given map of variables which
|
|
88
|
+
* override currently known variables of the same name in <code>this</code>
|
|
89
|
+
* parent interface or replace them altogether. Each variable name becomes a
|
|
90
|
+
* named model with a corresponding object binding and can be used inside the
|
|
91
|
+
* XML template in the usual way, that is, with a binding expression like
|
|
92
|
+
* <code>"{var>some/relative/path}"</code> (see example).
|
|
93
|
+
*
|
|
94
|
+
* @param {object} [mVariables={}]
|
|
95
|
+
* Map from variable name (string) to value ({@link sap.ui.model.Context})
|
|
96
|
+
* @param {boolean} [bReplace]
|
|
97
|
+
* Whether only the given variables are known in the new callback interface
|
|
98
|
+
* instance, no inherited ones
|
|
99
|
+
* @returns {sap.ui.core.util.XMLPreprocessor.ICallback}
|
|
100
|
+
* A callback interface instance
|
|
101
|
+
* @param mVariables
|
|
102
|
+
* @param bReplace
|
|
103
|
+
*/
|
|
104
|
+
"with"(mVariables?: any, bReplace?: boolean): ICallback;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Typeguard for checking if a building block use API 1.
|
|
109
|
+
*
|
|
110
|
+
* @param buildingBlockDefinition
|
|
111
|
+
* @returns `true` if the building block is using API 1.
|
|
112
|
+
*/
|
|
113
|
+
function isV1MacroDef(buildingBlockDefinition: BuildingBlockDefinition): buildingBlockDefinition is BuildingBlockDefinitionV1 {
|
|
114
|
+
return buildingBlockDefinition.apiVersion === undefined || buildingBlockDefinition.apiVersion === 1;
|
|
115
|
+
}
|
|
116
|
+
function validateMacroMetadataContext(
|
|
117
|
+
sName: string,
|
|
118
|
+
mContexts: any,
|
|
119
|
+
oContextSettings: BuildingBlockMetadataContextDefinition,
|
|
120
|
+
sKey: string
|
|
121
|
+
) {
|
|
122
|
+
const oContext = mContexts[sKey];
|
|
123
|
+
const oContextObject = oContext?.getObject();
|
|
124
|
+
|
|
125
|
+
if (oContextSettings.required && (!oContext || oContextObject === null)) {
|
|
126
|
+
throw new Error(`${sName}: Required metadataContext '${sKey}' is missing`);
|
|
127
|
+
} else if (oContextObject) {
|
|
128
|
+
// If context object has $kind property, $Type should not be checked
|
|
129
|
+
// Therefore remove from context settings
|
|
130
|
+
if (oContextObject.hasOwnProperty("$kind") && oContextSettings.$kind) {
|
|
131
|
+
// Check if the $kind is part of the allowed ones
|
|
132
|
+
if (oContextSettings.$kind.indexOf(oContextObject["$kind"]) === -1) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`${sName}: '${sKey}' must be '$kind' '${oContextSettings["$kind"]}' but is '${
|
|
135
|
+
oContextObject.$kind
|
|
136
|
+
}': ${oContext.getPath()}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
} else if (oContextObject.hasOwnProperty("$Type") && oContextSettings.$Type) {
|
|
140
|
+
// Check only $Type
|
|
141
|
+
if (oContextSettings.$Type.indexOf(oContextObject["$Type"]) === -1) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`${sName}: '${sKey}' must be '$Type' '${oContextSettings["$Type"]}' but is '${
|
|
144
|
+
oContextObject.$Type
|
|
145
|
+
}': ${oContext.getPath()}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export function validateMacroSignature(sName: any, oMetadata: any, mContexts: any, oNode: any) {
|
|
152
|
+
const aMetadataContextKeys = (oMetadata.metadataContexts && Object.keys(oMetadata.metadataContexts)) || [],
|
|
153
|
+
aProperties = (oMetadata.properties && Object.keys(oMetadata.properties)) || [],
|
|
154
|
+
oAttributeNames: any = {};
|
|
155
|
+
|
|
156
|
+
// collect all attributes to find unchecked properties
|
|
157
|
+
Object.keys(oNode.attributes).forEach(function (iKey: string) {
|
|
158
|
+
const sKey = oNode.attributes[iKey].name;
|
|
159
|
+
oAttributeNames[sKey] = true;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
//Check metadataContexts
|
|
163
|
+
aMetadataContextKeys.forEach(function (sKey: any) {
|
|
164
|
+
const oContextSettings = oMetadata.metadataContexts[sKey];
|
|
165
|
+
|
|
166
|
+
validateMacroMetadataContext(sName, mContexts, oContextSettings, sKey);
|
|
167
|
+
delete oAttributeNames[sKey];
|
|
168
|
+
});
|
|
169
|
+
//Check properties
|
|
170
|
+
aProperties.forEach(function (sKey: any) {
|
|
171
|
+
const oPropertySettings = oMetadata.properties[sKey];
|
|
172
|
+
if (!oNode.hasAttribute(sKey)) {
|
|
173
|
+
if (oPropertySettings.required && !oPropertySettings.hasOwnProperty("defaultValue")) {
|
|
174
|
+
throw new Error(sName + ": " + "Required property '" + sKey + "' is missing");
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
delete oAttributeNames[sKey];
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Unchecked properties
|
|
182
|
+
Object.keys(oAttributeNames).forEach(function (sKey: string) {
|
|
183
|
+
// no check for properties which start with underscore "_" or contain a colon ":" (different namespace), e.g. xmlns:trace, trace:macroID, unittest:id
|
|
184
|
+
if (sKey.indexOf(":") < 0 && !sKey.startsWith("xmlns")) {
|
|
185
|
+
Log.warning(`Unchecked parameter: ${sName}: ${sKey}`, undefined, LOGGER_SCOPE);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Ensures that the metadata for the building block are properly defined.
|
|
192
|
+
*
|
|
193
|
+
* @param buildingBlockMetadata The metadata received from the input
|
|
194
|
+
* @param isOpen Whether the building block is open or not
|
|
195
|
+
* @returns A set of completed metadata for further processing
|
|
196
|
+
*/
|
|
197
|
+
function prepareMetadata(buildingBlockMetadata?: BuildingBlockMetadata, isOpen = false): ResolvedBuildingBlockMetadata {
|
|
198
|
+
if (buildingBlockMetadata) {
|
|
199
|
+
const oProperties: any = {};
|
|
200
|
+
const oAggregations: any = {
|
|
201
|
+
"dependents": {
|
|
202
|
+
type: "sap.ui.core.Element"
|
|
203
|
+
},
|
|
204
|
+
"customData": {
|
|
205
|
+
type: "sap.ui.core.Element"
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const oMetadataContexts: Record<string, BuildingBlockPropertyDefinition> = {};
|
|
209
|
+
|
|
210
|
+
Object.keys(buildingBlockMetadata.properties).forEach(function (sPropertyName: string) {
|
|
211
|
+
if (buildingBlockMetadata.properties[sPropertyName].type !== "sap.ui.model.Context") {
|
|
212
|
+
oProperties[sPropertyName] = buildingBlockMetadata.properties[sPropertyName];
|
|
213
|
+
} else {
|
|
214
|
+
oMetadataContexts[sPropertyName] = buildingBlockMetadata.properties[sPropertyName];
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
// Merge events into properties as they are handled identically
|
|
218
|
+
if (buildingBlockMetadata.events) {
|
|
219
|
+
Object.keys(buildingBlockMetadata.events).forEach(function (sEventName: string) {
|
|
220
|
+
oProperties[sEventName] = buildingBlockMetadata.events[sEventName];
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (buildingBlockMetadata.aggregations) {
|
|
224
|
+
Object.keys(buildingBlockMetadata.aggregations).forEach(function (sPropertyName: string) {
|
|
225
|
+
oAggregations[sPropertyName] = buildingBlockMetadata.aggregations[sPropertyName];
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
properties: oProperties,
|
|
230
|
+
aggregations: oAggregations,
|
|
231
|
+
metadataContexts: oMetadataContexts,
|
|
232
|
+
isOpen: isOpen
|
|
233
|
+
};
|
|
234
|
+
} else {
|
|
235
|
+
return {
|
|
236
|
+
metadataContexts: {},
|
|
237
|
+
aggregations: {
|
|
238
|
+
"dependents": {
|
|
239
|
+
type: "sap.ui.core.Element"
|
|
240
|
+
},
|
|
241
|
+
"customData": {
|
|
242
|
+
type: "sap.ui.core.Element"
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
properties: {},
|
|
246
|
+
isOpen: isOpen
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function _getMetadataContext(
|
|
252
|
+
oSettings: any,
|
|
253
|
+
oNode: Element,
|
|
254
|
+
sAttributeName: string,
|
|
255
|
+
oVisitor: ICallback,
|
|
256
|
+
bDoNotResolve: boolean,
|
|
257
|
+
isOpen: boolean
|
|
258
|
+
) {
|
|
259
|
+
let oMetadataContext;
|
|
260
|
+
if (!bDoNotResolve && oNode.hasAttribute(sAttributeName)) {
|
|
261
|
+
const sAttributeValue = oNode.getAttribute(sAttributeName) as string;
|
|
262
|
+
let sMetaPath;
|
|
263
|
+
// oVisitor.getResult(sAttributeValue, oNode);
|
|
264
|
+
oMetadataContext = BindingParser.complexParser(sAttributeValue);
|
|
265
|
+
if (!oMetadataContext) {
|
|
266
|
+
if (sAttributeValue.startsWith("uid--")) {
|
|
267
|
+
const oData = myStore[sAttributeValue];
|
|
268
|
+
const sContextPath = "/" + sAttributeValue;
|
|
269
|
+
oSettings.models.converterContext.setProperty(sContextPath, oData);
|
|
270
|
+
oMetadataContext = {
|
|
271
|
+
model: "converterContext",
|
|
272
|
+
path: sContextPath
|
|
273
|
+
};
|
|
274
|
+
} else if ((sAttributeName === "metaPath" && oSettings.currentContextPath) || sAttributeName === "contextPath") {
|
|
275
|
+
if (sAttributeValue && sAttributeValue.startsWith("/")) {
|
|
276
|
+
// absolute path - we just use this one
|
|
277
|
+
sMetaPath = sAttributeValue;
|
|
278
|
+
} else {
|
|
279
|
+
let sContextPath = oSettings.currentContextPath.getPath();
|
|
280
|
+
if (!sContextPath.endsWith("/")) {
|
|
281
|
+
sContextPath += "/";
|
|
282
|
+
}
|
|
283
|
+
sMetaPath = sContextPath + sAttributeValue;
|
|
284
|
+
}
|
|
285
|
+
oMetadataContext = {
|
|
286
|
+
model: "metaModel",
|
|
287
|
+
path: sMetaPath
|
|
288
|
+
};
|
|
289
|
+
} else {
|
|
290
|
+
oMetadataContext = {
|
|
291
|
+
model: "metaModel",
|
|
292
|
+
path: oSettings.bindingContexts.entitySet
|
|
293
|
+
? oSettings.bindingContexts.entitySet.getPath(sAttributeValue)
|
|
294
|
+
: sAttributeValue
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else if (oSettings.bindingContexts.hasOwnProperty(sAttributeName)) {
|
|
299
|
+
oMetadataContext = {
|
|
300
|
+
model: sAttributeName,
|
|
301
|
+
path: ""
|
|
302
|
+
};
|
|
303
|
+
} else if (isOpen) {
|
|
304
|
+
try {
|
|
305
|
+
if (oVisitor.getContext(`${sAttributeName}>`)) {
|
|
306
|
+
oMetadataContext = {
|
|
307
|
+
model: sAttributeName,
|
|
308
|
+
path: ""
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
} catch (e) {
|
|
312
|
+
oMetadataContext = undefined;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return oMetadataContext;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function processProperties(
|
|
319
|
+
oMetadata: ResolvedBuildingBlockMetadata,
|
|
320
|
+
oSettings: any,
|
|
321
|
+
oNode: Element,
|
|
322
|
+
isPublic: boolean,
|
|
323
|
+
oVisitor: ICallback,
|
|
324
|
+
mContexts: any,
|
|
325
|
+
oMetadataContexts: any
|
|
326
|
+
) {
|
|
327
|
+
const mMissingContext: any = {};
|
|
328
|
+
const oDefinitionProperties = oMetadata.properties;
|
|
329
|
+
const oDefinitionContexts = oMetadata.metadataContexts;
|
|
330
|
+
oSettings.currentContextPath = oSettings.bindingContexts.contextPath;
|
|
331
|
+
|
|
332
|
+
// Retrieve properties values
|
|
333
|
+
const aDefinitionPropertiesKeys = Object.keys(oDefinitionProperties);
|
|
334
|
+
let aDefinitionContextsKeys = Object.keys(oDefinitionContexts);
|
|
335
|
+
const propertyValues: Record<string, any> = {};
|
|
336
|
+
for (let j = 0; j < aDefinitionPropertiesKeys.length; j++) {
|
|
337
|
+
const sKeyValue = aDefinitionPropertiesKeys[j];
|
|
338
|
+
if (oDefinitionProperties[sKeyValue].type === "object") {
|
|
339
|
+
propertyValues[sKeyValue] = {}; // To avoid vales being reused accross macros
|
|
340
|
+
} else {
|
|
341
|
+
propertyValues[sKeyValue] = oDefinitionProperties[sKeyValue].defaultValue;
|
|
342
|
+
}
|
|
343
|
+
if (oNode.hasAttribute(sKeyValue) && isPublic && !oDefinitionProperties[sKeyValue].isPublic) {
|
|
344
|
+
Log.error(`Property ${sKeyValue} was ignored as it is not intended for public usage`);
|
|
345
|
+
} else if (oNode.hasAttribute(sKeyValue)) {
|
|
346
|
+
await oVisitor.visitAttribute(oNode, oNode.attributes.getNamedItem(sKeyValue) as Attr);
|
|
347
|
+
const vValue = oNode.getAttribute(sKeyValue);
|
|
348
|
+
if (vValue !== undefined) {
|
|
349
|
+
propertyValues[sKeyValue] = vValue;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Sort keys to be sure contextPath is before metaPath ( yes I'm desperate )
|
|
354
|
+
aDefinitionContextsKeys = aDefinitionContextsKeys.sort(function (a: string, b: string) {
|
|
355
|
+
return a > b ? 1 : -1;
|
|
356
|
+
});
|
|
357
|
+
for (const sAttributeName of aDefinitionContextsKeys) {
|
|
358
|
+
const bDoNotResolve = isPublic && !oDefinitionContexts[sAttributeName].isPublic && oNode.hasAttribute(sAttributeName);
|
|
359
|
+
const oMetadataContext = _getMetadataContext(oSettings, oNode, sAttributeName, oVisitor, bDoNotResolve, oMetadata.isOpen);
|
|
360
|
+
if (oMetadataContext) {
|
|
361
|
+
oMetadataContext.name = sAttributeName;
|
|
362
|
+
addSingleContext(mContexts, oVisitor, oMetadataContext, oMetadataContexts);
|
|
363
|
+
if (
|
|
364
|
+
(sAttributeName === "entitySet" && !oSettings.bindingContexts.hasOwnProperty(sAttributeName)) ||
|
|
365
|
+
(sAttributeName === "contextPath" && !oSettings.bindingContexts.hasOwnProperty(sAttributeName))
|
|
366
|
+
) {
|
|
367
|
+
oSettings.bindingContexts[sAttributeName] = mContexts[sAttributeName];
|
|
368
|
+
}
|
|
369
|
+
if (sAttributeName === "contextPath") {
|
|
370
|
+
oSettings.currentContextPath = mContexts[sAttributeName];
|
|
371
|
+
}
|
|
372
|
+
propertyValues[sAttributeName] = mContexts[sAttributeName];
|
|
373
|
+
} else {
|
|
374
|
+
mMissingContext[sAttributeName] = true;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return { mMissingContext, propertyValues: propertyValues };
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function processChildren(
|
|
381
|
+
oNode: Element,
|
|
382
|
+
oVisitor: ICallback,
|
|
383
|
+
oMetadata: ResolvedBuildingBlockMetadata,
|
|
384
|
+
isPublic: boolean,
|
|
385
|
+
propertyValues: Record<string, any>
|
|
386
|
+
) {
|
|
387
|
+
const oAggregations: any = {};
|
|
388
|
+
if (oNode.firstElementChild !== null) {
|
|
389
|
+
// If there are aggregation we need to visit the childNodes first and foremost
|
|
390
|
+
await oVisitor.visitChildNodes(oNode);
|
|
391
|
+
let oFirstElementChild: Element | null = oNode.firstElementChild;
|
|
392
|
+
while (oFirstElementChild !== null) {
|
|
393
|
+
const sChildName = oFirstElementChild.localName;
|
|
394
|
+
if (
|
|
395
|
+
Object.keys(oMetadata.aggregations).indexOf(sChildName) !== -1 &&
|
|
396
|
+
(!isPublic || oMetadata.aggregations[sChildName].isPublic)
|
|
397
|
+
) {
|
|
398
|
+
oAggregations[oFirstElementChild.localName] = oFirstElementChild;
|
|
399
|
+
} else if (Object.keys(oMetadata.properties).indexOf(sChildName) !== -1) {
|
|
400
|
+
// Object Type properties
|
|
401
|
+
propertyValues[sChildName] = {};
|
|
402
|
+
for (const attributeIndex of Object.keys(oFirstElementChild.attributes)) {
|
|
403
|
+
propertyValues[sChildName][oFirstElementChild.attributes[attributeIndex as any].localName] =
|
|
404
|
+
oFirstElementChild.attributes[attributeIndex as any].value;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
oFirstElementChild = oFirstElementChild.nextElementSibling;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return oAggregations;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function processBuildingBlock(
|
|
415
|
+
buildingBLockDefinition: BuildingBlockDefinition,
|
|
416
|
+
oNode: Element,
|
|
417
|
+
oVisitor: ICallback,
|
|
418
|
+
isPublic = false
|
|
419
|
+
) {
|
|
420
|
+
const sFragmentName = buildingBLockDefinition.fragment || `${buildingBLockDefinition.namespace}.${buildingBLockDefinition.name}`;
|
|
421
|
+
|
|
422
|
+
const sName = "this";
|
|
423
|
+
|
|
424
|
+
const mContexts: any = {};
|
|
425
|
+
const oMetadataContexts: any = {};
|
|
426
|
+
const oSettings = oVisitor.getSettings();
|
|
427
|
+
// TODO 0001 Move this elsewhere this is weird :)
|
|
428
|
+
if (oSettings.models["sap.fe.i18n"]) {
|
|
429
|
+
oSettings.models["sap.fe.i18n"]
|
|
430
|
+
.getResourceBundle()
|
|
431
|
+
.then(function (oResourceBundle: any) {
|
|
432
|
+
ResourceModel.setApplicationI18nBundle(oResourceBundle);
|
|
433
|
+
})
|
|
434
|
+
.catch(function (error: any) {
|
|
435
|
+
Log.error(error);
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
const oMetadata = prepareMetadata(buildingBLockDefinition.metadata, buildingBLockDefinition.isOpen);
|
|
439
|
+
|
|
440
|
+
//Inject storage for macros
|
|
441
|
+
if (!oSettings[sFragmentName]) {
|
|
442
|
+
oSettings[sFragmentName] = {};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// First of all we need to visit the attributes
|
|
446
|
+
const { mMissingContext, propertyValues } = await processProperties(
|
|
447
|
+
oMetadata,
|
|
448
|
+
oSettings,
|
|
449
|
+
oNode,
|
|
450
|
+
isPublic,
|
|
451
|
+
oVisitor,
|
|
452
|
+
mContexts,
|
|
453
|
+
oMetadataContexts
|
|
454
|
+
);
|
|
455
|
+
const initialKeys = Object.keys(propertyValues);
|
|
456
|
+
try {
|
|
457
|
+
// Aggregation and complex type support
|
|
458
|
+
const oAggregations = await processChildren(oNode, oVisitor, oMetadata, isPublic, propertyValues);
|
|
459
|
+
let oInstance: any;
|
|
460
|
+
let oControlConfig = {};
|
|
461
|
+
|
|
462
|
+
if (oSettings.models.viewData) {
|
|
463
|
+
// Only used in the Field macro and even then maybe not really useful
|
|
464
|
+
oControlConfig = oSettings.models.viewData.getProperty("/controlConfiguration");
|
|
465
|
+
}
|
|
466
|
+
let processedPropertyValues = propertyValues;
|
|
467
|
+
if (isV1MacroDef(buildingBLockDefinition) && buildingBLockDefinition.create) {
|
|
468
|
+
processedPropertyValues = buildingBLockDefinition.create.call(
|
|
469
|
+
buildingBLockDefinition,
|
|
470
|
+
propertyValues,
|
|
471
|
+
oControlConfig,
|
|
472
|
+
oSettings,
|
|
473
|
+
oAggregations,
|
|
474
|
+
isPublic
|
|
475
|
+
);
|
|
476
|
+
Object.keys(oMetadata.metadataContexts).forEach(function (sMetadataName: string) {
|
|
477
|
+
if (oMetadata.metadataContexts[sMetadataName].computed) {
|
|
478
|
+
mContexts[sMetadataName] = processedPropertyValues[sMetadataName];
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
Object.keys(mMissingContext).forEach(function (sContextName: string) {
|
|
482
|
+
if (processedPropertyValues.hasOwnProperty(sContextName)) {
|
|
483
|
+
mContexts[sContextName] = processedPropertyValues[sContextName];
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
} else if (buildingBLockDefinition.apiVersion === 2) {
|
|
487
|
+
Object.keys(propertyValues).forEach((propName) => {
|
|
488
|
+
const oData = propertyValues[propName];
|
|
489
|
+
if (
|
|
490
|
+
oData &&
|
|
491
|
+
oData.isA &&
|
|
492
|
+
oData.isA("sap.ui.model.Context") &&
|
|
493
|
+
!oData.getModel().isA("sap.ui.model.odata.v4.ODataMetaModel")
|
|
494
|
+
) {
|
|
495
|
+
propertyValues[propName] = oData.getObject();
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
const BuildingBlockClass = buildingBLockDefinition as typeof BuildingBlockBase;
|
|
499
|
+
oInstance = new BuildingBlockClass(propertyValues /*, oControlConfig, oSettings, oAggregations, isPublic*/);
|
|
500
|
+
}
|
|
501
|
+
const oAttributesModel: JSONModel = new AttributeModel(oNode, processedPropertyValues, buildingBLockDefinition);
|
|
502
|
+
mContexts[sName] = oAttributesModel.createBindingContext("/");
|
|
503
|
+
|
|
504
|
+
let oPreviousMacroInfo: any;
|
|
505
|
+
|
|
506
|
+
// Keep track
|
|
507
|
+
if (TraceInfo.isTraceInfoActive()) {
|
|
508
|
+
const oTraceInfo = TraceInfo.traceMacroCalls(sFragmentName, oMetadata, mContexts, oNode, oVisitor);
|
|
509
|
+
if (oTraceInfo) {
|
|
510
|
+
oPreviousMacroInfo = oSettings["_macroInfo"];
|
|
511
|
+
oSettings["_macroInfo"] = oTraceInfo.macroInfo;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
validateMacroSignature(sFragmentName, oMetadata, mContexts, oNode);
|
|
515
|
+
|
|
516
|
+
const oContextVisitor = oVisitor.with(
|
|
517
|
+
mContexts,
|
|
518
|
+
buildingBLockDefinition.isOpen !== undefined ? !buildingBLockDefinition.isOpen : true
|
|
519
|
+
);
|
|
520
|
+
const oParent = oNode.parentNode;
|
|
521
|
+
|
|
522
|
+
let iChildIndex: number;
|
|
523
|
+
let oPromise;
|
|
524
|
+
if (oParent) {
|
|
525
|
+
iChildIndex = Array.from(oParent.children).indexOf(oNode);
|
|
526
|
+
|
|
527
|
+
if (
|
|
528
|
+
(isV1MacroDef(buildingBLockDefinition) && buildingBLockDefinition.getTemplate) ||
|
|
529
|
+
buildingBLockDefinition.apiVersion === 2
|
|
530
|
+
) {
|
|
531
|
+
let oTemplate;
|
|
532
|
+
let addDefaultNamespace = false;
|
|
533
|
+
if (buildingBLockDefinition.apiVersion === 2) {
|
|
534
|
+
oTemplate = oInstance.getTemplate();
|
|
535
|
+
addDefaultNamespace = true;
|
|
536
|
+
} else if (buildingBLockDefinition.getTemplate) {
|
|
537
|
+
oTemplate = buildingBLockDefinition.getTemplate(processedPropertyValues);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
let hasError = "";
|
|
541
|
+
if (oTemplate) {
|
|
542
|
+
if (!oTemplate.firstElementChild) {
|
|
543
|
+
oTemplate = parseXMLString(oTemplate, addDefaultNamespace);
|
|
544
|
+
// For safety purpose we try to detect trailing text in between XML Tags
|
|
545
|
+
const iter = document.createNodeIterator(oTemplate, NodeFilter.SHOW_TEXT);
|
|
546
|
+
let textnode = iter.nextNode();
|
|
547
|
+
while (textnode) {
|
|
548
|
+
if (textnode.textContent && textnode.textContent.trim().length > 0) {
|
|
549
|
+
hasError = textnode.textContent;
|
|
550
|
+
}
|
|
551
|
+
textnode = iter.nextNode();
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (oTemplate.localName === "parsererror") {
|
|
556
|
+
// If there is a parseerror while processing the XML it means the XML itself is malformed, as such we rerun the template process
|
|
557
|
+
// Setting isTraceMode true will make it so that each xml` expression is checked for validity from XML perspective and if an error is found it's returned instead of the normal fragment
|
|
558
|
+
Log.error(`Error while processing building block ${buildingBLockDefinition.name}`);
|
|
559
|
+
try {
|
|
560
|
+
isTraceMode = true;
|
|
561
|
+
oTemplate = oInstance?.getTemplate
|
|
562
|
+
? oInstance.getTemplate()
|
|
563
|
+
: (buildingBLockDefinition as any).getTemplate(processedPropertyValues);
|
|
564
|
+
oTemplate = parseXMLString(oTemplate, true);
|
|
565
|
+
} finally {
|
|
566
|
+
isTraceMode = false;
|
|
567
|
+
}
|
|
568
|
+
} else if (hasError.length > 0) {
|
|
569
|
+
// If there is trailing text we create a standard error and display it.
|
|
570
|
+
Log.error(`Error while processing building block ${buildingBLockDefinition.name}`);
|
|
571
|
+
const oErrorText = createErrorXML(
|
|
572
|
+
[
|
|
573
|
+
`Error while processing building block ${buildingBLockDefinition.name}`,
|
|
574
|
+
`Trailing text was found in the XML: ${hasError}`
|
|
575
|
+
],
|
|
576
|
+
oTemplate.outerHTML
|
|
577
|
+
);
|
|
578
|
+
oTemplate = parseXMLString(oErrorText, true);
|
|
579
|
+
}
|
|
580
|
+
oNode.replaceWith(oTemplate);
|
|
581
|
+
oNode = oParent.children[iChildIndex];
|
|
582
|
+
oPromise = oContextVisitor.visitNode(oNode);
|
|
583
|
+
} else {
|
|
584
|
+
oNode.remove();
|
|
585
|
+
oPromise = Promise.resolve();
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
oPromise = oContextVisitor.insertFragment(sFragmentName, oNode);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
await oPromise;
|
|
592
|
+
const oMacroElement = oParent.children[iChildIndex];
|
|
593
|
+
|
|
594
|
+
if (Object.keys(oAggregations).length > 0) {
|
|
595
|
+
Object.keys(oAggregations).forEach(function (sAggregationName: string) {
|
|
596
|
+
const oAggregationElement = oAggregations[sAggregationName];
|
|
597
|
+
if (oMacroElement !== null && oMacroElement !== undefined) {
|
|
598
|
+
const oNewChild = document.createElementNS(oMacroElement.namespaceURI, sAggregationName);
|
|
599
|
+
let oElementChild = oAggregationElement.firstElementChild;
|
|
600
|
+
while (oElementChild) {
|
|
601
|
+
const oNextChild = oElementChild.nextElementSibling;
|
|
602
|
+
oNewChild.appendChild(oElementChild);
|
|
603
|
+
oElementChild = oNextChild;
|
|
604
|
+
}
|
|
605
|
+
if (sAggregationName !== "customData" && sAggregationName !== "dependents") {
|
|
606
|
+
const sSlotName =
|
|
607
|
+
(oMetadata.aggregations[sAggregationName] && oMetadata.aggregations[sAggregationName].slot) ||
|
|
608
|
+
sAggregationName;
|
|
609
|
+
const oTargetElement = oMacroElement.querySelector("slot[name='" + sSlotName + "']") as Element;
|
|
610
|
+
if (oTargetElement) {
|
|
611
|
+
oTargetElement.replaceWith(...(oNewChild.children as any));
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
oMacroElement.appendChild(oNewChild);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
if (oMacroElement) {
|
|
620
|
+
const oRemainingSlots = oMacroElement.querySelectorAll("slot");
|
|
621
|
+
oRemainingSlots.forEach(function (oSlotElement: any) {
|
|
622
|
+
oSlotElement.remove();
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (oPreviousMacroInfo) {
|
|
627
|
+
//restore macro info if available
|
|
628
|
+
oSettings["_macroInfo"] = oPreviousMacroInfo;
|
|
629
|
+
} else {
|
|
630
|
+
delete oSettings["_macroInfo"];
|
|
631
|
+
}
|
|
632
|
+
} catch (e) {
|
|
633
|
+
// In case there is a generic error (usually code error), we retrieve the current context information and create a dedicated error message
|
|
634
|
+
const traceDetails = {
|
|
635
|
+
initialProperties: {} as any,
|
|
636
|
+
resolvedProperties: {} as any,
|
|
637
|
+
missingContexts: mMissingContext
|
|
638
|
+
};
|
|
639
|
+
for (const propertyName of initialKeys) {
|
|
640
|
+
const propertyValue = propertyValues[propertyName];
|
|
641
|
+
if (propertyValue && propertyValue.isA && propertyValue.isA("sap.ui.model.Context")) {
|
|
642
|
+
traceDetails.initialProperties[propertyName] = {
|
|
643
|
+
path: propertyValue.getPath(),
|
|
644
|
+
value: propertyValue.getObject()
|
|
645
|
+
};
|
|
646
|
+
} else {
|
|
647
|
+
traceDetails.initialProperties[propertyName] = propertyValue;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
for (const propertyName in propertyValues) {
|
|
651
|
+
const propertyValue = propertyValues[propertyName];
|
|
652
|
+
if (!initialKeys.includes(propertyName)) {
|
|
653
|
+
if (propertyValue && propertyValue.isA && propertyValue.isA("sap.ui.model.Context")) {
|
|
654
|
+
traceDetails.resolvedProperties[propertyName] = {
|
|
655
|
+
path: propertyValue.getPath(),
|
|
656
|
+
value: propertyValue.getObject()
|
|
657
|
+
};
|
|
658
|
+
} else {
|
|
659
|
+
traceDetails.resolvedProperties[propertyName] = propertyValue;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const errorAny = e as any;
|
|
664
|
+
Log.error(errorAny, errorAny);
|
|
665
|
+
const oError = createErrorXML(
|
|
666
|
+
[`Error while processing building block ${buildingBLockDefinition.name}`, errorAny.stack],
|
|
667
|
+
oNode.outerHTML,
|
|
668
|
+
traceDetails
|
|
669
|
+
);
|
|
670
|
+
const oTemplate = parseXMLString(oError, true);
|
|
671
|
+
oNode.replaceWith(oTemplate as any);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
function addSingleContext(mContexts: any, oVisitor: any, oCtx: any, oMetadataContexts: any) {
|
|
675
|
+
const sKey = oCtx.name || oCtx.model || undefined;
|
|
676
|
+
|
|
677
|
+
if (oMetadataContexts[sKey]) {
|
|
678
|
+
return; // do not add twice
|
|
679
|
+
}
|
|
680
|
+
try {
|
|
681
|
+
let sContextPath = oCtx.path;
|
|
682
|
+
if (oCtx.model != null) {
|
|
683
|
+
sContextPath = oCtx.model + ">" + sContextPath;
|
|
684
|
+
}
|
|
685
|
+
const mSetting = oVisitor.getSettings();
|
|
686
|
+
if (!mSetting.bindingContexts[oCtx.model] && mSetting.models[oCtx.model]) {
|
|
687
|
+
mContexts[sKey] = mSetting.models[oCtx.model].getContext(oCtx.path); // add the context to the visitor
|
|
688
|
+
} else {
|
|
689
|
+
mContexts[sKey] = oVisitor.getContext(sContextPath); // add the context to the visitor
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
oMetadataContexts[sKey] = mContexts[sKey]; // make it available inside metadataContexts JSON object
|
|
693
|
+
} catch (ex) {
|
|
694
|
+
//console.error(ex);
|
|
695
|
+
// ignore the context as this can only be the case if the model is not ready, i.e. not a preprocessing model but maybe a model for
|
|
696
|
+
// providing afterwards
|
|
697
|
+
// TODO 0002 not yet implemented
|
|
698
|
+
//mContexts["_$error"].oModel.setProperty("/" + sKey, ex);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Register a building block definition to be used inside the xml template processor.
|
|
704
|
+
*
|
|
705
|
+
* @param buildingBlockDefinition The building block definition
|
|
706
|
+
*/
|
|
707
|
+
export function registerBuildingBlock(buildingBlockDefinition: BuildingBlockDefinition): void {
|
|
708
|
+
XMLPreprocessor.plugIn(
|
|
709
|
+
(oNode: Element, oVisitor: ICallback) => processBuildingBlock(buildingBlockDefinition, oNode, oVisitor),
|
|
710
|
+
buildingBlockDefinition.namespace,
|
|
711
|
+
buildingBlockDefinition.xmlTag || buildingBlockDefinition.name
|
|
712
|
+
);
|
|
713
|
+
if (buildingBlockDefinition.publicNamespace) {
|
|
714
|
+
XMLPreprocessor.plugIn(
|
|
715
|
+
(oNode: Element, oVisitor: ICallback) => processBuildingBlock(buildingBlockDefinition, oNode, oVisitor, true),
|
|
716
|
+
buildingBlockDefinition.publicNamespace,
|
|
717
|
+
buildingBlockDefinition.xmlTag || buildingBlockDefinition.name
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function createErrorXML(errorMessages: string[], xmlFragment: string, additionalData?: object): string {
|
|
723
|
+
const errorLabels = errorMessages.map((errorMessage) => xml`<m:Label text="${escapeXML(errorMessage)}"/>`);
|
|
724
|
+
let additionalText = "";
|
|
725
|
+
if (additionalData) {
|
|
726
|
+
additionalText = xml`<m:VBox>
|
|
727
|
+
<m:Label text="Trace Info"/>
|
|
728
|
+
<code:CodeEditor type="json" value="${escapeXML(JSON.stringify(additionalData, null, 4))}" height="300px" width="100vh"/>
|
|
729
|
+
</m:VBox>`;
|
|
730
|
+
}
|
|
731
|
+
return xml`<m:VBox xmlns:m="sap.m" xmlns:code="sap.ui.codeeditor">
|
|
732
|
+
${errorLabels}
|
|
733
|
+
<m:HBox>
|
|
734
|
+
<m:VBox>
|
|
735
|
+
<m:Label text="How the building block was called"/>
|
|
736
|
+
<code:CodeEditor type="xml" value="${escapeXML(xmlFragment)}" height="300px" width="100vh"/>
|
|
737
|
+
</m:VBox>
|
|
738
|
+
${additionalText}
|
|
739
|
+
</m:HBox>
|
|
740
|
+
</m:VBox>`;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const myStore: Record<string, any> = {};
|
|
744
|
+
function storeValue(values: any) {
|
|
745
|
+
const propertyUID = `uid--${uid()}`;
|
|
746
|
+
myStore[propertyUID] = values;
|
|
747
|
+
return propertyUID;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Parse an XML string and return the associated document.
|
|
752
|
+
*
|
|
753
|
+
* @param xmlString The xml string
|
|
754
|
+
* @param addDefaultNamespaces Whether or not we should add default namespace
|
|
755
|
+
* @returns The XML document.
|
|
756
|
+
*/
|
|
757
|
+
function parseXMLString(xmlString: string, addDefaultNamespaces = false): Element {
|
|
758
|
+
if (addDefaultNamespaces) {
|
|
759
|
+
xmlString = `<template
|
|
760
|
+
xmlns:template="http://schemas.sap.com/sapui5/extension/sap.ui.core.template/1"
|
|
761
|
+
xmlns:m="sap.m"
|
|
762
|
+
xmlns:core="sap.ui.core"
|
|
763
|
+
xmlns:customData="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1">${xmlString}</template>`;
|
|
764
|
+
}
|
|
765
|
+
const xmlDocument = DOMParserInstance.parseFromString(xmlString, "text/xml");
|
|
766
|
+
let output = xmlDocument.firstElementChild;
|
|
767
|
+
while (output?.localName === "template") {
|
|
768
|
+
output = output.firstElementChild;
|
|
769
|
+
}
|
|
770
|
+
return output as Element;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Escape an XML string to include it in an XML fragment.
|
|
775
|
+
*
|
|
776
|
+
* @param str The string to escape
|
|
777
|
+
* @returns The escaped string.
|
|
778
|
+
*/
|
|
779
|
+
function escapeXML(str: string): string {
|
|
780
|
+
return str
|
|
781
|
+
.replace(/&/g, "&")
|
|
782
|
+
.replace(/</g, "<")
|
|
783
|
+
.replace(/\n/g, " ")
|
|
784
|
+
.replace(/\{/g, "\\{")
|
|
785
|
+
.replace(/>/g, ">")
|
|
786
|
+
.replace(/"/g, """)
|
|
787
|
+
.replace(/'/g, "'");
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Escape an XML attribute value.
|
|
792
|
+
*
|
|
793
|
+
* @param val The attribute value to escape.
|
|
794
|
+
* @returns The escaped string.
|
|
795
|
+
*/
|
|
796
|
+
function escapeXMLAttributeValue(val: string): string {
|
|
797
|
+
return val.replace(/&/g, "&").replace(/</g, "<");
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Create a string representation of the template literal while handling special object case.
|
|
802
|
+
*
|
|
803
|
+
* @param strings The string parts of the template literal
|
|
804
|
+
* @param values The values part of the template literal
|
|
805
|
+
* @returns The XML string document representing the string that was used.
|
|
806
|
+
*/
|
|
807
|
+
export const xml = (strings: TemplateStringsArray, ...values: any[]) => {
|
|
808
|
+
let outStr = "";
|
|
809
|
+
let i;
|
|
810
|
+
for (i = 0; i < values.length; i++) {
|
|
811
|
+
outStr += strings[i];
|
|
812
|
+
// Handle the different case of object, if it's an array we join them, if it's a binding expression (determined by _type) then we compile it.
|
|
813
|
+
if (Array.isArray(values[i])) {
|
|
814
|
+
outStr += values[i].flat(5).join("").trim();
|
|
815
|
+
} else if (values[i]?._type) {
|
|
816
|
+
const compiledExpression = compileBinding(values[i]);
|
|
817
|
+
outStr += compiledExpression !== undefined ? escapeXMLAttributeValue(compiledExpression) : undefined;
|
|
818
|
+
} else if (values[i]?.getTemplate) {
|
|
819
|
+
outStr += values[i].getTemplate();
|
|
820
|
+
} else if (typeof values[i] === "object") {
|
|
821
|
+
const propertyUId = storeValue(values[i]);
|
|
822
|
+
outStr += `${propertyUId}`;
|
|
823
|
+
} else {
|
|
824
|
+
outStr += values[i];
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
outStr += strings[i];
|
|
828
|
+
outStr = outStr.trim();
|
|
829
|
+
if (isTraceMode) {
|
|
830
|
+
const xmlResult = parseXMLString(outStr, true);
|
|
831
|
+
if (xmlResult && xmlResult?.localName === "parsererror") {
|
|
832
|
+
const errorMessage = (xmlResult as any).innerText || (xmlResult as any).innerHTML;
|
|
833
|
+
return createErrorXML([errorMessage.split("\n")[0]], outStr);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return outStr;
|
|
837
|
+
};
|