@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
274 lines (254 loc) • 9.84 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
/*eslint-disable max-len */
// Provides an abstraction for BindingInfos
sap.ui.define([
"sap/base/config",
"sap/ui/base/DesignTime",
"sap/ui/core/getCompatibilityVersion",
"sap/ui/base/BindingParser",
"sap/ui/model/BindingMode",
"sap/base/Log"
],
function(BaseConfig, DesignTime, getCompatibilityVersion, BindingParser, BindingMode) {
"use strict";
// Marker that is used for aggregation binding. It's set on the instance
// cloned from the given template with value pointing to the original
// parent where the aggregation is defined. In case the aggregation is
// forwarded to another control, the original parent isn't changed and still
// points to the control before the aggregation gets forwarded.
const ORIGINAL_PARENT = Symbol("OriginalParent");
// Marker symbol for BindingInfos which already have extracted a
// named model from their path
const MODEL_NAME_EXTRACTED = Symbol("ModelNameExtracted");
/**
* Checks if the "path" of the given BindingInfo/part contains
* a model name and if so extracts it accordingly.
* @param {sap.ui.base.BindingInfo} oPart the BindingInfo to check for a model name
* @returns {sap.ui.base.BindingInfo} the modified BindingInfo
*/
function extractModelName(oPart) {
if (!oPart[MODEL_NAME_EXTRACTED]) {
// if a model separator is found in the path, extract model name and path
const iSeparatorPos = oPart.path.indexOf(">");
if (iSeparatorPos > 0) {
oPart.model = oPart.path.substr(0, iSeparatorPos);
oPart.path = oPart.path.substr(iSeparatorPos + 1);
oPart[MODEL_NAME_EXTRACTED] = true;
}
}
return oPart;
}
/**
* This module is responsible for the following tasks:
* - extracting and parsing binding-info objects
* - creating Property, Object and Aggregation binding-infos
* - providing the UI5-object marker symbol
* - exposing and defaulting the BindingParser
*
* @alias sap.ui.base.BindingInfo
* @namespace
* @private
* @ui5-restricted sap.ui.base, sap.ui.core, sap.ui.model, sap.m, sap.ui.integration, sap.ui.fl, sap.fe
*/
var BindingInfo = {
/**
* Creates a new property binding-info object based on the given raw definition.
* @param {sap.ui.base.ManagedObject.PropertyBindingInfo} oBindingInfo raw binding info object
* @returns {object} valid property binding-info
* @private
* @ui5-restricted sap.ui.base, sap.ui.core
*/
createProperty: function(oBindingInfo) {
// only one binding object with one binding specified
if (!oBindingInfo.parts) {
oBindingInfo.parts = [];
oBindingInfo.parts[0] = {
path: oBindingInfo.path,
targetType: oBindingInfo.targetType,
type: oBindingInfo.type,
suspended: oBindingInfo.suspended,
formatOptions: oBindingInfo.formatOptions,
constraints: oBindingInfo.constraints,
model: oBindingInfo.model,
mode: oBindingInfo.mode,
value: oBindingInfo.value
};
delete oBindingInfo.path;
delete oBindingInfo.targetType;
delete oBindingInfo.mode;
delete oBindingInfo.model;
delete oBindingInfo.value;
}
for ( var i = 0; i < oBindingInfo.parts.length; i++ ) {
// Plain strings as parts are taken as paths of bindings
var oPart = oBindingInfo.parts[i];
if (typeof oPart == "string") {
oPart = { path: oPart };
oBindingInfo.parts[i] = oPart;
}
// if a model separator is found in the path, extract model name and path
if (oPart.path !== undefined) {
extractModelName(oPart);
}
// if a formatter exists the binding mode can be one way or one time only
if (oBindingInfo.formatter &&
oPart.mode != BindingMode.OneWay &&
oPart.mode != BindingMode.OneTime) {
oPart.mode = BindingMode.OneWay;
}
}
//Initialize skip properties
oBindingInfo.skipPropertyUpdate = 0;
oBindingInfo.skipModelUpdate = 0;
return oBindingInfo;
},
/**
* Creates a new aggregation binding-info object based on the given raw definition.
* @param {sap.ui.base.ManagedObject.AggregationBindingInfo} oBindingInfo raw binding info object
* @returns {object} valid aggregation binding-info
* @private
* @ui5-restricted sap.ui.base, sap.ui.core
*/
createAggregation: function(oBindingInfo, bDoesNotRequireFactory) {
if (!(oBindingInfo.template || oBindingInfo.factory)) {
// If aggregation is marked correspondingly in the metadata, factory can be omitted (usually requires an updateXYZ method)
if ( bDoesNotRequireFactory ) {
// add a dummy factory as property 'factory' is used to distinguish between property- and list-binding
oBindingInfo.factory = function() {
throw new Error("dummy factory called unexpectedly ");
};
}
} else if (oBindingInfo.template) {
// if we have a template we will create a factory function
oBindingInfo.factory = function(sId) {
const oClone = oBindingInfo.template.clone(sId);
// This flag is currently used by FieldHelp.js and it needs to be set only when a binding template is given.
// When a custom factory method is provided, it's not guaranteed that all instances created from the factory
// are bound to the same sub-path under the given aggregation path. Therefore we can't use the parent
// control for showing the header of the field help.
oClone[ORIGINAL_PARENT] = oBindingInfo[ORIGINAL_PARENT];
return oClone;
};
}
// if a model separator is found in the path, extract model name and path
extractModelName(oBindingInfo);
return oBindingInfo;
},
/**
* Creates a new object binding-info object based on the given raw definition.
* @param {sap.ui.base.ManagedObject.ObjectBindingInfo} oBindingInfo raw binding info object
* @returns {object} valid object binding-info
* @private
* @ui5-restricted sap.ui.base, sap.ui.core
*/
createObject: function(oBindingInfo) {
// if a model separator is found in the path, extract model name and path
extractModelName(oBindingInfo);
return oBindingInfo;
},
/**
* See {@link sap.ui.base.ManagedObject#extractBindingInfo}
*/
extract: function(oValue, oScope, bDetectValue) {
var oBindingInfo;
// property:{path:"path", template:oTemplate}
if (oValue && typeof oValue === "object") {
if (oValue.Type) {
// if value contains the 'Type' property (capital 'T'), this is not a binding info.
oBindingInfo = undefined;
} else if (oValue[this.UI5ObjectMarker]) {
// no bindingInfo, delete marker
delete oValue[this.UI5ObjectMarker];
} else if (oValue.ui5object) {
// if value contains ui5object property, this is not a binding info,
// remove it and not check for path or parts property
delete oValue.ui5object;
} else if (oValue.path != undefined || oValue.parts
|| (bDetectValue || oValue[this.UI5ObjectMarker] === false) && oValue.value != undefined) {
oBindingInfo = oValue;
}
}
// property:"{path}" or "\{path\}"
if (typeof oValue === "string") {
// either returns a binding info or an unescaped string or undefined - depending on binding syntax
const args = [oValue, oScope, true];
// provide variable "$control" to be used with ".bind()" in the binding string
// see BindingParser.complexParser
args[8] = { "$control": null };
oBindingInfo = BindingInfo.parse(...args);
}
return oBindingInfo;
},
escape: function () {
return BindingInfo.parse.escape.apply(this, arguments);
},
/**
* Checks whether a BindingInfo is ready to create its Binding.
*
* @param {sap.ui.base.ManagedObject.PropertyBindingInfo
* | sap.ui.base.ManagedObject.AggregationBindingInfo
* | sap.ui.base.ManagedObject.ObjectBindingInfo} oBindingInfo The BindingInfo to check
* @param {sap.ui.base.ManagedObject} oObject The bound ManagedObject
* @returns {boolean} if the BindingInfo is ready or not
* @private
* @ui5-restricted sap.ui.base, sap.ui.core, sap.ui.model
*/
isReady: function(oBindingInfo, oObject) {
const aParts = oBindingInfo.parts;
if (aParts) { // PropertyBinding
return oBindingInfo.parts.every((oPart) => {
return oPart.value !== undefined || oObject.getModel(oPart.model);
});
} else { // AggregationBinding or ObjectBinding
return !!oObject.getModel(oBindingInfo.model);
}
},
UI5ObjectMarker: BindingParser.UI5ObjectMarker,
OriginalParent: ORIGINAL_PARENT
};
/**
* @deprecated As of Version 1.119
*/
function getBindingSyntax() {
var sBindingSyntax = BaseConfig.get({
name: "sapUiBindingSyntax",
type: BaseConfig.Type.String,
defaultValue: "default",
freeze: true
});
if ( sBindingSyntax === "default" ) {
sBindingSyntax = (getCompatibilityVersion("sapCoreBindingSyntax").compareTo("1.26") < 0) ? "simple" : "complex";
}
return sBindingSyntax;
}
/**
* Parses the given binding info string and returns a binding info object if valid.
* @see sap.ui.base.BindingParser
* @private
* @ui5-restricted sap.ui.base, sap.ui.core, sap.ui.model, sap.m, sap.ui.integration, sap.ui.fl, sap.fe
*/
Object.defineProperty(BindingInfo, "parse", {
get: function () {
if (!this.oParser) {
this.oParser = BindingParser.complexParser;
/**
* Note: "simple" binding syntax is deprecated since 1.24
* @deprecated As of Version 1.119
*/
this.oParser = getBindingSyntax() === "simple" ? BindingParser.simpleParser : BindingParser.complexParser;
if (DesignTime.isDesignModeEnabled() == true) {
BindingParser._keepBindingStrings = true;
}
}
return this.oParser;
},
set: function (parser) {
this.oParser = parser;
}
});
return BindingInfo;
});