@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
444 lines (380 loc) • 12.5 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.m.Tree.
sap.ui.define([
'./ListBase',
'./library',
'sap/ui/model/ClientTreeBindingAdapter',
'sap/ui/model/TreeBindingCompatibilityAdapter',
'./TreeRenderer',
"sap/base/Log",
"sap/base/assert",
"sap/ui/model/controlhelper/TreeBindingProxy"
],
function(
ListBase,
library,
ClientTreeBindingAdapter,
TreeBindingCompatibilityAdapter,
TreeRenderer,
Log,
assert,
TreeBindingProxy
) {
"use strict";
/**
* Constructor for a new Tree.
*
* @param {string} [sId] ID for the new control, generated automatically if no id is given
* @param {object} [mSettings] Initial settings for the new control
*
* @class
* The <code>Tree</code> control provides a tree structure for displaying data in a hierarchy.
* <b>Note:</b> Growing feature is not supported by <code>Tree</code>.
* @extends sap.m.ListBase
*
* @author SAP SE
* @version 1.117.4
*
* @constructor
* @public
* @since 1.42
* @alias sap.m.Tree
* @see {@link fiori:/tree/ Tree}
*/
var Tree = ListBase.extend("sap.m.Tree", {
metadata : {
library : "sap.m",
events : {
/**
* Fired when an item has been expanded or collapsed by user interaction.
* @since 1.50
*/
toggleOpenState : {
parameters : {
/**
* Index of the expanded/collapsed item
*/
itemIndex : {type : "int"},
/**
* Binding context of the item
*/
itemContext : {type : "object"},
/**
* Flag that indicates whether the item has been expanded or collapsed
*/
expanded : {type : "boolean"}
}
}
}
},
renderer: TreeRenderer
});
Tree.prototype.init = function() {
ListBase.prototype.init.apply(this, arguments);
this._oProxy = new TreeBindingProxy(this, "items");
};
Tree.prototype.isTreeBinding = function(sName) {
return (sName == "items");
};
Tree.prototype.getBinding = function(sName) {
// adapt TreeBindingAdapter for Tree
sName = sName || "items";
var oBinding = ListBase.prototype.getBinding.call(this, sName);
if (oBinding && sName === "items" && !oBinding.getLength) {
// try to resolve optional dependencies
if (oBinding.isA("sap.ui.model.odata.v2.ODataTreeBinding")) {
oBinding.applyAdapterInterface();
} else if (oBinding.isA("sap.ui.model.ClientTreeBinding")) {
ClientTreeBindingAdapter.apply(oBinding);
} else if (oBinding.isA("sap.ui.model.odata.ODataTreeBinding")) {
// use legacy tree binding adapter
TreeBindingCompatibilityAdapter(oBinding, this);
} else {
Log.error("TreeBinding is not supported for the " + this);
}
}
return oBinding;
};
Tree.prototype.updateAggregation = function(sName) {
if (sName != "items") {
return ListBase.prototype.updateAggregation.apply(this, arguments);
}
// Reuse the ListBinding from ManagedObject.updataAggregation
var oBindingInfo = this.getBindingInfo("items"),
fnFactory = oBindingInfo.factory,
aContexts;
// Update a single aggregation with the array of contexts. Reuse existing children
// and just append or remove at the end, if some are missing or too many.
function update(oControl, aContexts) {
var aChildren = oControl.getItems() || [],
oContext,
oClone;
if (aChildren.length > aContexts.length) {
for (var i = aContexts.length; i < aChildren.length; i++) {
oControl.removeItem(aChildren[i]);
aChildren[i].destroy("KeepDom");
}
}
for (var i = 0; i < aContexts.length; i++) {
oContext = aContexts[i];
oClone = aChildren[i];
if (oClone) {
oClone.setBindingContext(oContext, oBindingInfo.model);
} else {
oClone = fnFactory(oControl.getId() + "-" + i, oContext);
oClone.setBindingContext(oContext, oBindingInfo.model);
oControl.addItem(oClone);
}
}
}
// Context length will be filled by model.
aContexts = this._oProxy.getContexts(0);
// If factory function is used without extended change detection, destroy aggregation
if (!oBindingInfo.template) {
this.destroyItems();
}
update(this, aContexts);
};
Tree.prototype.validateAggregation = function(sAggregationName, oObject, bMultiple) {
var oResult = ListBase.prototype.validateAggregation.apply(this, arguments);
if (sAggregationName === "items" && !oObject.isA("sap.m.TreeItemBase")) {
throw new Error(oObject + " is not a valid items aggregation of " + this + ". Items aggregation in Tree control only supports TreeItemBase-based objects, e.g. StandardTreeItem.");
}
return oResult;
};
Tree.prototype.invalidate = function() {
ListBase.prototype.invalidate.apply(this, arguments);
this._bInvalidated = true;
};
Tree.prototype.onAfterRendering = function() {
ListBase.prototype.onAfterRendering.apply(this, arguments);
this._bInvalidated = false;
};
Tree.prototype.exit = function() {
ListBase.prototype.exit.apply(this, arguments);
this._oProxy = null;
};
Tree.prototype._updateDeepestLevel = function(oItem) {
// for level change action, e.g. expand
if (oItem.getLevel() + 1 > this.getDeepestLevel()) {
this._iDeepestLevel = oItem.getLevel() + 1;
}
};
Tree.prototype.onItemExpanderPressed = function(oItem, bExpand) {
var iIndex = this.indexOfItem(oItem);
var oBindingInfo = this.getBindingInfo("items");
var oItemContext = oItem && oItem.getBindingContext(oBindingInfo.model);
if (oBindingInfo && oItemContext) {
var bExpandedBeforePress = oItem.getExpanded();
var bExpandedAfterPress;
// make sure when rendering is called, the padding calc uses the correct deepest level
this._updateDeepestLevel(oItem);
if (bExpand == undefined) {
this._oProxy.toggleExpandedState(iIndex);
} else if (bExpand) {
this._oProxy.expand(iIndex);
} else {
this._oProxy.collapse(iIndex);
}
bExpandedAfterPress = this._oProxy.isExpanded(iIndex);
if (bExpandedBeforePress !== bExpandedAfterPress && !oItem.isLeaf()) {
this.fireToggleOpenState({
itemIndex: iIndex,
itemContext: oItemContext,
expanded: bExpandedAfterPress
});
}
}
};
/**
* The <code>growing</code> property is not supported for control <code>Tree</code>.
* @public
* @param {boolean} bValue New value for the <code>growing</code> property, ignored.
* @returns {this} Returns <code>this</code> to allow method chaining
* @deprecated As of version 1.46.
*/
Tree.prototype.setGrowing = function(bValue) {
Log.error("Growing feature of " + this + " is not supported!");
return this;
};
/**
* The <code>growingThreshold</code> property is not supported for control <code>Tree</code>.
* @public
* @param {int} iValue New value for the <code>growingThreshold</code> property, ignored.
* @returns {this} Returns <code>this</code> to allow method chaining
* @deprecated As of version 1.46.
*/
Tree.prototype.setGrowingThreshold = function(iValue) {
Log.error("GrowingThreshold of " + this + " is not supported!");
return this;
};
/**
* The <code>growingTriggerText</code> property is not supported for control <code>Tree</code>.
* @public
* @param {string} sValue New value for the <code>growingTriggerText</code> property, ignored.
* @returns {this} Returns <code>this</code> to allow method chaining
* @deprecated As of version 1.46.
*/
Tree.prototype.setGrowingTriggerText = function(sValue) {
Log.error("GrowingTriggerText of " + this + " is not supported!");
return this;
};
/**
* The <code>growingScrollToLoad</code> property is not supported for control <code>Tree</code>.
* @public
* @param {boolean} bValue New value for the <code>growingScrollToLoad</code> property, ignored.
* @returns {this} Returns <code>this</code> to allow method chaining
* @deprecated As of version 1.46.
*/
Tree.prototype.setGrowingScrollToLoad = function(bValue) {
Log.error("GrowingScrollToLoad of " + this + " is not supported!");
return this;
};
/**
* The <code>growingDirection</code> property is not supported for control <code>Tree</code>.
* @public
* @param {sap.m.ListGrowingDirection} sValue New value for the <code>growingDirection</code> property, ignored.
* @returns {this} Returns <code>this</code> to allow method chaining
* @deprecated As of version 1.46.
*/
Tree.prototype.setGrowingDirection = function(sValue) {
Log.error("GrowingDirection of " + this + " is not supported!");
return this;
};
/**
* Defines the level to which the tree is expanded.
* The function can be used to define the initial expanding state. An alternative way to define the initial expanding state is to set the parameter <code>numberOfExpandedLevels</code> of the binding.
*
* Example:
* <pre>
* oTree.bindItems({
* path: "...",
* parameters: {
* numberOfExpandedLevels: 1
* }
* });
* </pre>
* @returns {this} Returns <code>this</code> to allow method chaining
* @public
* @param {int} iLevel The level to which the data is expanded
* @since 1.48.0
*/
Tree.prototype.expandToLevel = function (iLevel) {
this._oProxy.expandToLevel(iLevel);
return this;
};
Tree.prototype.getNumberOfExpandedLevel = function() {
return this.getBinding("items").getNumberOfExpandedLevels();
};
Tree.prototype.getDeepestLevel = function() {
if (this._iDeepestLevel === undefined) {
this._iDeepestLevel = this.getNumberOfExpandedLevel();
}
return this._iDeepestLevel;
};
/**
* Collapses all nodes.
*
* @returns {this} A reference to the Tree control
* @public
* @since 1.48.0
*/
Tree.prototype.collapseAll = function () {
this._oProxy.collapseAll();
return this;
};
Tree.prototype._sortHelper = function (vParam) {
var aIndices = [];
if ( typeof vParam === "number" ) {
aIndices.push(vParam);
} else if ( Array.isArray(vParam) ) {
//sort
aIndices = vParam.sort().reverse();
}
return aIndices;
};
Tree.prototype._removeLeaf = function(aSortedIndices) {
var oItem = null,
iItemIndex,
aIndices = [];
for (var i = 0; i < aSortedIndices.length; i++) {
iItemIndex = aSortedIndices[i];
oItem = this.getItems()[iItemIndex];
if (oItem && !oItem.isLeaf()) {
aIndices.push(iItemIndex);
}
}
return aIndices;
};
Tree.prototype._preExpand = function(vParam) {
var aIndices = this._sortHelper(vParam);
aIndices = this._removeLeaf(aIndices);
return aIndices;
};
/**
*
* Expands one or multiple items. Note that items that are hidden at the time of calling this API can't be expanded.
*
* @returns {this} A reference to the Tree control
* @public
* @param {int|int[]} vParam The index or indices of the item to be expanded
* @since 1.56.0
*/
Tree.prototype.expand = function(vParam) {
this._oProxy.expand(vParam);
return this;
};
/**
*
* Collapses one or multiple items.
*
* @returns {this} A reference to the Tree control
* @public
* @param {int|int[]} vParam The index or indices of the tree items to be collapsed
* @since 1.56.0
*/
Tree.prototype.collapse = function(vParam) {
this._oProxy.collapse(vParam);
return this;
};
Tree.prototype.getAccessibilityType = function() {
return sap.ui.getCore().getLibraryResourceBundle("sap.m").getText("ACC_CTR_TYPE_TREE");
};
Tree.prototype.getAccessbilityPosition = function(oItem) {
var iIndex = this.indexOfItem(oItem);
return {
setSize: this._oProxy.getSiblingCount(iIndex),
posInset: this._oProxy.getPositionInParent(iIndex) + 1
};
};
Tree.prototype.onItemLongDragOver = function(oItem) {
var iIndex = this.indexOfItem(oItem),
oBindingInfo = this.getBindingInfo("items"),
oItemContext = oItem && oItem.getBindingContext(oBindingInfo.model);
// toggleOpenState event should be fired when an item is expand via DnD interaction
if (oItem) {
this._updateDeepestLevel(oItem);
if (!oItem.isLeaf()) {
this._oProxy.expand(iIndex);
this.fireToggleOpenState({
itemIndex: iIndex,
itemContext: oItemContext,
expanded: this._oProxy.isExpanded(iIndex)
});
}
}
};
Tree.prototype.isGrouped = function() {
return false;
};
Tree.prototype.getAriaRole = function() {
return "tree";
};
// items and groupHeader mapping is not required for the table control
Tree.prototype.setLastGroupHeader = function() {};
return Tree;
});