@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
152 lines (137 loc) • 6.56 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define(["sap/base/util/ObjectPath"], function(ObjectPath) {
"use strict";
// indicator if the reference can't be resolved
var oNotFound = Object.create(null);
/**
* Resolve the path segments under the given root context
*
* @param {array} aParts The path segments
* @param {object} oRoot The root context
* @param {object} [mOptions] Options
* @param {boolean} [mOptions.bindContext] When the resolved value is a
* function, whether the resolved function is bound to a context
* @param {boolean} [mOptions.rootContext] When the resolved value is a
* function and a rootContext is given, the resolved function is bound
* to this context instead of the object to which it belongs. If
* <code>mOptions.bindContext=false</code>, this option has no effect
* @return {any} The resolved value. If the value can't be resolved under the
* given root context, it returns <code>oNotFound</code>.
*/
function _resolve(aParts, oRoot, mOptions) {
var vRef, oContext;
if (oRoot && (aParts[0] in oRoot)) {
// the path consists of at least two segments
// e.g. key "Module.namespace.function" -> function() {...}
oContext = aParts.length > 1 ? ObjectPath.get(aParts.slice(0, -1), oRoot) : oRoot;
vRef = oContext && oContext[aParts[aParts.length - 1]];
if (typeof vRef === "function" && mOptions.bindContext) {
vRef = vRef.bind(mOptions.rootContext || oContext);
}
return vRef;
}
return oNotFound;
}
/**
* Returns a value located in the provided path using the given
* <code>mVariables</code> object.
*
* If the provided path cannot be resolved completely, <code>undefined</code> is returned.
*
* How <code>mVariables</code> are checked for resolving the path depends on
* the syntax of the path:
* <ul>
* <li><i>absolute</i>: paths not starting with a dot ('.') are checked through
* <code>mVariables</code>.</li>
* <li><i>relative</i>: paths starting with a dot ('.') are only checked through the
* dot variable <code>mVariables["."]</code> and don't fallback to global scope
* <code>window</code>.</li>
* <li><i>legacy</i>: when <code>mOptions.preferDotContext=true</code>, paths not starting
* with a dot ('.') are first checked through the dot Variable
* <code>mVariables["."]</code> and then - if nothing is found - through the other
* Variables in <code>mVariables</code> and eventually fallback to global scope
* <code>window</code>.</li>
* </ul>
*
* When the resolved value is a function, a context may be bound to it with the following
* conditions:
* <ul>
* <li><i>No bound</i>: if the function is resolved from the global scope (not from any
* given variables in <code>mVariables</code>, it's not bound to any context. If the
* function exists directly under <code>mVariables</code>, nothing is bound.</li>
* <li><i>Bound</i>: otherwise, the resolved function is bound to the object to which it
* belongs</li>
* <li><i>mOptions.bindContext</i>: when this option is set to <code>false</code>, no
* context is bound to the resolved function regardless where the function is resolved
* </li>
* <li><i>mOptions.bindDotContext</i>: for paths starting with a dot ('.'),
* <code>mOptions.bindDotContext=false</code> turns off the automatic binding to the
* dot variable <code>mVariables["."]</code>. <code>mOptions.bindDotContext</code> has
* no effect when <code>mOptions.bindContext=false</code>.</li>
* </ul>
*
* @function
* @private
* @ui5-restricted sap.ui.core
* @since 1.69
*
* @param {string} sPath Path
* @param {object} [mVariables] An object containing the mapping of variable name to object or function
* @param {object} [mOptions] Options
* @param {boolean} [mOptions.preferDotContext=false] Whether the path not starting with a dot ('.') is
* resolved under the dot variable when it can not be resolved through the given variables object.
* @param {boolean} [mOptions.bindContext=true] When the resolved value is a function, whether the
* resolved function is bound to a context. When this property is set to false, the
* mOptions.bindDotContext has no effect anymore.
* @param {boolean} [mOptions.bindDotContext=true] When the resolved value is a function, whether the
* resolved function from a path which starts with a dot ('.') should be bound to the dot context
* @returns {any} Returns the value located in the provided path, or <code>undefined</code> if the path
* does not exist completely.
* @alias module:sap/base/util/resolveReference
*/
var resolveReference = function(sPath, mVariables, mOptions) {
// fill the default values
mVariables = mVariables || {};
mOptions = mOptions || {};
mOptions.bindContext = mOptions.bindContext !== false;
mOptions.bindDotContext = mOptions.bindDotContext !== false;
var aParts = sPath.split("."),
// if sPath starts with ".", split returns an empty string
// at the first position and the dot is used as variable
sVariable = aParts.shift() || ".",
bDotCase = sVariable === ".",
vRef = oNotFound;
// push the first part back to the array
aParts.unshift(sVariable);
// if preferDotContext, resolve the sPath under the dot context first for sPath which doesn't begin with "."
if (mOptions.preferDotContext && !bDotCase) {
vRef = _resolve(aParts, mVariables["."], {
bindContext: mOptions.bindContext && mOptions.bindDotContext,
// resolve function in dot variable should always bind the dot variable
rootContext: mVariables["."]
});
}
// If sPath isn't resolved yet, resolve the path under mVariables
if (vRef === oNotFound) {
vRef = _resolve(aParts, mVariables, {
bindContext: mOptions.bindContext
// dot case: mOptions.bindDotContext determins whether context should be bound
// non dot case: bind context if sPath contains more than one segment
&& (bDotCase ? mOptions.bindDotContext : (aParts.length > 1)),
rootContext: bDotCase ? mVariables["."] : undefined
});
}
// resolve the path under global scope, only when it can't be resolved under mVariables
if (vRef === oNotFound) {
// fallback if no value could be found under the given sPath's first segment
// otherwise resolve under global namespace
vRef = ObjectPath.get(sPath);
}
return vRef;
};
return resolveReference;
});