UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

322 lines (278 loc) 12.2 kB
/*! * OpenUI5 * (c) Copyright 2009-2023 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ "sap/base/util/merge", "sap/ui/core/util/reflection/JsControlTreeModifier" ], function(merge, JsControlTreeModifier) { "use strict"; /** * @namespace * @private * @alias sap.m.p13n.modules.xConfigAPI */ var xConfigAPI = {}; /** * Enhances the xConfig object for a given mdc control instance. * * @param {sap.ui.core.Element} oControl The according element which should be checked * @param {object} oModificationPayload An object providing a modification handler specific payload * @param {object} oModificationPayload.key The affected metadata property key * @param {object} oModificationPayload.controlMeta Object describing which config is affected * @param {object} oModificationPayload.controlMeta.aggregation The affected aggregation name (such as <code>columns</code> or <code>filterItems</code>) * @param {object} oModificationPayload.property The affected property name (such as <code>width</code> or <code>lable</code>) * @param {object} oModificationPayload.value The value that should be written in nthe xConfig * @param {object} [oModificationPayload.propertyBag] Optional propertybag for different modification handler derivations * * @returns {Promise<object>} Promise resolving to the adapted xConfig object */ xConfigAPI.enhanceConfig = function(oControl, oModificationPayload) { var mPropertyBag = oModificationPayload.propertyBag; var oModifier = mPropertyBag ? mPropertyBag.modifier : JsControlTreeModifier; var oControlMetadata; var oXConfig; return oModifier.getControlMetadata(oControl) .then(function(oRetrievedControlMetadata) { oControlMetadata = oRetrievedControlMetadata; oModificationPayload.controlMetadata = oControlMetadata; return oModifier.getAggregation(oControl, "customData"); }) .then(function(aCustomData) { return Promise.all(aCustomData.map(function(oCustomData){ return oModifier.getProperty(oCustomData, "key"); })).then(function(aCustomDataKeys){ return aCustomData.reduce(function(oResult, mCustomData, iIndex){ return aCustomDataKeys[iIndex] === "xConfig" ? mCustomData : oResult; }, undefined); }); }) .then(function(oRetrievedXConfig) { oXConfig = oRetrievedXConfig; if (oXConfig) { return oModifier.getProperty(oXConfig, "value") .then(function(sConfig){ return merge({}, JSON.parse(sConfig.replace(/\\/g, ''))); }); } return {}; }) .then(function(oExistingConfig) { var oConfig; if (oModificationPayload.controlMeta && oModificationPayload.controlMeta.aggregation) { oConfig = xConfigAPI.createAggregationConfig(oControl, oModificationPayload, oExistingConfig); } else { oConfig = xConfigAPI.createPropertyConfig(oControl, oModificationPayload, oExistingConfig); } var oAppComponent = mPropertyBag ? mPropertyBag.appComponent : undefined; var pDelete = Promise.resolve(); if (oXConfig && oControl.isA) { pDelete = oModifier.removeAggregation(oControl, "customData", oXConfig) .then(function(){ return oModifier.destroy(oXConfig); }); } return pDelete.then(function(){ return oModifier.createAndAddCustomData(oControl, "xConfig", JSON.stringify(oConfig), oAppComponent) .then(function(){ return merge({}, oConfig); }); }); }); }; /** * Returns a copy of the xConfig object * * @param {sap.ui.core.Element} oControl The according element which should be checked * @param {object} [oModificationPayload] An object providing a modification handler specific payload * @param {object} [oModificationPayload.propertyBag] Optional propertybag for different modification handler derivations * * @returns {Promise<object>|object} A promise resolving to the adapted xConfig object or the object directly */ xConfigAPI.readConfig = function(oControl, oModificationPayload) { var oConfig, oAggregationConfig; if (oModificationPayload) { var oModifier = oModificationPayload.propertyBag ? oModificationPayload.propertyBag.modifier : JsControlTreeModifier; return oModifier.getAggregation(oControl, "customData") .then(function(aCustomData) { return Promise.all(aCustomData.map(function(oCustomData){ return oModifier.getProperty(oCustomData, "key"); })).then(function(aCustomDataKeys){ return aCustomData.reduce(function(oResult, mCustomData, iIndex){ return aCustomDataKeys[iIndex] === "xConfig" ? mCustomData : oResult; }, undefined); }); }) .then(function(oAggregationConfig) { if (oAggregationConfig) { return oModifier.getProperty(oAggregationConfig, "value") .then(function(sValue) { return merge({}, JSON.parse(sValue.replace(/\\/g, ''))); }); } return null; }); } // These functions are used instead of the modifier to avoid that the // entire call stack is changed to async when it's not needed var fnGetAggregationSync = function(oParent, sAggregationName) { var fnFindAggregation = function(oControl, sAggregationName) { if (oControl) { if (oControl.getMetadata) { var oMetadata = oControl.getMetadata(); var oAggregations = oMetadata.getAllAggregations(); if (oAggregations) { return oAggregations[sAggregationName]; } } } return undefined; }; var oAggregation = fnFindAggregation(oParent, sAggregationName); if (oAggregation) { return oParent[oAggregation._sGetter](); } return undefined; }; var fnGetPropertySync = function(oControl, sPropertyName) { var oMetadata = oControl.getMetadata().getPropertyLikeSetting(sPropertyName); if (oMetadata) { var sPropertyGetter = oMetadata._sGetter; return oControl[sPropertyGetter](); } return undefined; }; oAggregationConfig = fnGetAggregationSync(oControl, "customData").find(function(oCustomData){ return fnGetPropertySync(oCustomData, "key") == "xConfig"; }); oConfig = oAggregationConfig ? merge({}, JSON.parse(fnGetPropertySync(oAggregationConfig, "value").replace(/\\/g, ''))) : null; return oConfig; }; /** * Enhances the xConfig object for a given mdc control instance. * * @param {sap.ui.core.Element} oControl The according element which should be checked * @param {object} oModificationPayload An object providing a modification handler specific payload * @param {object} oModificationPayload.key The affected property name * @param {object} oModificationPayload.controlMeta Object describing which config is affected * @param {object} oModificationPayload.controlMeta.aggregation The affected aggregation name (such as <code>columns</code> or <code>filterItems</code>) * @param {object} oModificationPayload.property The affected property name (such as <code>width</code> or <code>lable</code>) * @param {object} oModificationPayload.value The value that should be written in nthe xConfig * @param {object} [oExistingConfig] Already existing config to be enhanced by the payload * * @returns {object} The adapted xConfig object */ xConfigAPI.createAggregationConfig = function(oControl, oModificationPayload, oExistingConfig) { var sPropertyInfoKey = oModificationPayload.key || oModificationPayload.name; var mControlMeta = oModificationPayload.controlMeta; var sAffectedProperty = oModificationPayload.property; var vValue = oModificationPayload.value; var oControlMetadata = oModificationPayload.controlMetadata || oControl.getMetadata(); var sAffectedAggregation = mControlMeta.aggregation; var sAggregationName = sAffectedAggregation ? sAffectedAggregation : oControlMetadata.getDefaultAggregation().name; var oConfig = oExistingConfig || {}; if (!oConfig.hasOwnProperty("aggregations")) { oConfig.aggregations = {}; } if (!oConfig.aggregations.hasOwnProperty(sAggregationName)) { if (oControlMetadata.hasAggregation(sAggregationName)) { oConfig.aggregations[sAggregationName] = {}; } else { throw new Error("The aggregation " + sAggregationName + " does not exist for" + oControl); } } if (!oConfig.aggregations[sAggregationName].hasOwnProperty(sPropertyInfoKey)) { oConfig.aggregations[sAggregationName][sPropertyInfoKey] = {}; } if (vValue !== null) { switch (oModificationPayload.operation) { case "move": Object.entries(oConfig.aggregations[sAggregationName]).forEach((aEntry) => { if ( aEntry[0] !== sPropertyInfoKey && aEntry[1].position !== undefined ){ var newIndex = vValue.index; var currentState = oModificationPayload.currentState; var currentItemState = currentState?.find((item) => item.key == sPropertyInfoKey); var currentItemIndex = currentState?.indexOf(currentItemState); //In case of move changes, we also need to ensure that existing xConfig position changes //are adapted accordingly to avoid index mismatches if (newIndex < aEntry[1].position) { aEntry[1].position++; } if (newIndex > aEntry[1].position && currentItemIndex < aEntry[1].position) { aEntry[1].position--; } if (aEntry[1].position == newIndex) { currentItemIndex > aEntry[1].position ? aEntry[1].position++ : aEntry[1].position--; } } }); oConfig.aggregations[sAggregationName][sPropertyInfoKey][sAffectedProperty] = vValue.index; break; case "remove": case "add": default: /*TODO*/ if (vValue.hasOwnProperty("value")) { oConfig.aggregations[sAggregationName][sPropertyInfoKey][sAffectedProperty] = vValue.value; oConfig.aggregations[sAggregationName][sPropertyInfoKey]["position"] = vValue.index; } else { oConfig.aggregations[sAggregationName][sPropertyInfoKey][sAffectedProperty] = vValue; } /*TODO*/ break; } } else { delete oConfig.aggregations[sAggregationName][sPropertyInfoKey][sAffectedProperty]; //Delete empty property name object if (Object.keys(oConfig.aggregations[sAggregationName][sPropertyInfoKey]).length === 0) { delete oConfig.aggregations[sAggregationName][sPropertyInfoKey]; //Delete empty aggregation name object if (Object.keys(oConfig.aggregations[sAggregationName]).length === 0) { delete oConfig.aggregations[sAggregationName]; } } } return oConfig; }; /** * Enhances the xConfig object for a given mdc control instance. * * @param {sap.ui.core.Element} oControl The according element which should be checked * @param {object} oModificationPayload An object providing a modification handler specific payload * @param {object} oModificationPayload.key The affected property name * @param {object} oModificationPayload.property Object describing which config is affected * @param {object} oModificationPayload.value The value that should be written in nthe xConfig * @param {object} [oExistingConfig] Already existing config to be enhanced by the payload * * @returns {object} The adapted xConfig object */ xConfigAPI.createPropertyConfig = function(oControl, oModificationPayload, oExistingConfig) { //var sDataKey = oModificationPayload.key; var vValue = oModificationPayload.value; //var oControlMetadata = oModificationPayload.controlMetadata || oControl.getMetadata(); var sAffectedProperty = oModificationPayload.property; var oConfig = oExistingConfig || {}; if (!oConfig.properties) { oConfig.properties = {}; } if (!oConfig.properties.hasOwnProperty(sAffectedProperty)) { oConfig.properties[sAffectedProperty] = []; } var sOperation = oModificationPayload.operation; var oItem = oConfig.properties[sAffectedProperty].find(function(oEntry){ return oEntry.key === oModificationPayload.key; }); if (oItem) { oConfig.properties[sAffectedProperty].splice(oConfig.properties[sAffectedProperty].indexOf(oItem), 1); } if (sOperation !== "remove") { oConfig.properties[sAffectedProperty].splice(oModificationPayload.value.index, 0, vValue); } return oConfig; }; return xConfigAPI; });