UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

140 lines (130 loc) 5.06 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ /* eslint-disable no-loop-func */ sap.ui.define([ "sap/base/Log", "sap/ui/test/matchers/Matcher" ], function (Log, Matcher) { "use strict"; var oLogger = Log.getLogger("sap.ui.test.matchers.Sibling"); var oMatcher = new Matcher(); /** * @class * Checks if a control has a defined sibling. * Available as a declarative matcher with the following syntax: * <code><pre>{ * sibling: "object" // where "object" is a declarative matcher for the sibling * } * </code></pre> * The declarative matcher for Sibling does not support <b>oOptions</b> parameters. * * @param {object|string} vSibling the sibling control to check. Can be a control or a control ID. If undefined, the result will always be true. * @param {object} [oOptions] specifies how to match * @param {boolean} oOptions.useDom whether to match by relationships of the DOM references. false by default * @param {boolean} oOptions.prev match only if control's DOM reference is before the sibling's in the DOM tree * @param {boolean} oOptions.next match only if control's DOM reference is after the sibling's in the DOM tree, * @param {boolean} oOptions.level how many levels of ancestors to search * @public * @name sap.ui.test.matchers.Sibling * @author SAP SE * @since 1.91 */ return function (vSibling, oOptions) { return function (oControl) { if (!vSibling) { oLogger.debug("No sibling was defined so no controls will be filtered."); return true; } var bResult = false; var oSiblingControl; if (typeof vSibling === "string") { // declarative matchers: // sibling is already resolved by opa or controlfinder - here we deal only with the id var oAppWindow = oMatcher._getApplicationWindow(); oSiblingControl = oAppWindow.sap.ui.require("sap/ui/test/OpaPlugin") .getElementById(vSibling); } else { oSiblingControl = vSibling; } if (oOptions && oOptions.useDom) { // sibling-only relationships; similar to vyper siblings (could be useful for e2e script reuse) var iSiblingIndex = -1; var iControlIndex = -1; var parent = oSiblingControl.getDomRef().parentNode; // filter the direct children that have a UI5 ID for (var i = 0; i < parent.children.length; i += 1) { var sId = parent.children[i].getAttribute("data-sap-ui"); if (sId === oSiblingControl.getId()) { iSiblingIndex = i; } if (sId === oControl.getId()) { iControlIndex = i; } } // compare control position to the sibling position (even more precise filtering) if (iControlIndex > -1) { if (oOptions.prev) { if (iControlIndex < iSiblingIndex) { bResult = true; } else { oLogger.debug("Control '" + oControl + "' has sibling '" + oSiblingControl + "' but it isn't ordered before the sibling"); } } else if (oOptions.next) { if (iControlIndex > iSiblingIndex) { bResult = true; } else { oLogger.debug("Control '" + oControl + "' has sibling '" + oSiblingControl + "' but it isn't ordered after the sibling"); } } else { oLogger.debug("Sibling order should be defined"); // or default to next? } } } else { var oParent = oSiblingControl.getParent(); var iLevel = 0; var iLimit = oOptions && oOptions.level >= 0 && oOptions.level || Number.MAX_SAFE_INTEGER; while (iLevel < iLimit && oParent && !bResult) { // for non-direct parents, go though their aggregated controls to find a relative var aAggregated = _getAggregatedControls(oParent.mAggregations); aAggregated.forEach(function (oAggregatedControl) { if (oAggregatedControl !== oSiblingControl) { if (oAggregatedControl === oControl) { bResult = true; } else { // look "down" through the aggregated controls' aggregations if (_getAggregatedControls(oAggregatedControl.mAggregations).includes(oControl)) { bResult = true; } } } }); iLevel += 1; oParent = oParent.getParent(); } } oLogger.debug("Control '" + oControl + "' " + (bResult ? "has" : "does not have") + " sibling '" + oSiblingControl); return bResult; }; }; // get all controls in an aggregations object function _getAggregatedControls(mAggregations) { var aResult = []; for (var sAggregation in mAggregations) { var vAggregation = mAggregations[sAggregation]; if (Array.isArray(vAggregation)) { // "width limit" - check only the first 20 controls in 1 aggregation aResult = aResult.concat(vAggregation.slice(0, 20)); } else if (vAggregation) { aResult.push(vAggregation); } } aResult = aResult.filter(function (oControl) { // filter out non-control aggregations e.g. layoutData or dnd return oControl.getMetadata && oControl.getMetadata().getName() && oControl.$().length; }); return aResult; } }, /* bExport= */ true);