@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
384 lines (329 loc) • 14.6 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.
*/
/**
* Contains functionality that is used in sap.m.IconTabBar Drag&Drop
*/
sap.ui.define([
'sap/ui/core/dnd/DragInfo',
'sap/ui/core/dnd/DropInfo',
"sap/ui/events/KeyCodes",
'sap/ui/core/library',
'sap/ui/core/Configuration'
],
function(DragInfo, DropInfo, KeyCodes, coreLibrary, Configuration) {
"use strict";
// shortcut for sap.ui.core.dnd.DropPosition
var DropPosition = coreLibrary.dnd.DropPosition;
var INSERT_POSITION_BEFORE = "Before",
INSERT_BEFORE = "insertBefore",
INSERT_AFTER = "insertAfter",
sInsertAfterBeforePosition,
DRAG_DROP_GROUP_NAME = "IconTabReorder",
DRAG_DIRECTION_FORWARD = "Forward",
DRAG_DIRECTION_BACKWARD = "Backward";
var IconTabBarDragAndDropUtil = {
/**
* Inserts control at correct place in the DOM.
* @param {string} sInsertAfterBeforePosition comes from drop event, it can be "Before" or "After"
* @param {object} oDraggedControl control that is being dragged
* @param {object} oDroppedControl control that the dragged control will be dropped on
* @param {boolean} bIsOverflow
*/
_insertControl: function(sInsertAfterBeforePosition, oDraggedControl, oDroppedControl, bIsOverflow) {
var $DraggedControl = oDraggedControl.$(),
$DroppedControl = oDroppedControl.$(),
aDraggedControlSubItems = [],
aDroppedControlSubItems = [];
if (oDraggedControl._getNestedLevel() > 1 && oDroppedControl._getNestedLevel() > 1) {
aDraggedControlSubItems = oDraggedControl._getRootTab()._getSelectList().getItems().filter(function (oItem) {
return oDraggedControl._getRealTab()._isParentOf(oItem._getRealTab());
});
aDroppedControlSubItems = oDroppedControl._getRootTab()._getSelectList().getItems().filter(function (oItem) {
return oDroppedControl._getRealTab()._isParentOf(oItem._getRealTab());
});
}
if (bIsOverflow) {
var aOverflowSelectListItems = oDraggedControl._getRootTab().getParent()._getOverflow()._getSelectList().getItems();
aDraggedControlSubItems = aOverflowSelectListItems.filter(function (oItem) {
return oDraggedControl._getRealTab()._isParentOf(oItem._getRealTab());
});
aDroppedControlSubItems = aOverflowSelectListItems.filter(function (oItem) {
return oDroppedControl._getRealTab()._isParentOf(oItem._getRealTab());
});
}
if (sInsertAfterBeforePosition === INSERT_AFTER) {
$DraggedControl.insertAfter($DroppedControl);
} else {
$DraggedControl.insertBefore($DroppedControl);
}
aDraggedControlSubItems.reverse().forEach(function (oChildItem) {
oChildItem.$().insertAfter($DraggedControl);
});
aDroppedControlSubItems.reverse().forEach(function (oChildItem) {
oChildItem.$().insertAfter($DroppedControl);
});
},
/**
* Handles drop event.
* @param {object} oContext from which context function is called (sap.m.IconTabHeader or sap.m.IconTabSelectList)
* @param {string} sDropPosition comes from drop event, it can be "Before", "After", or "On"
* @param {object} oDraggedControl control that is being dragged
* @param {object} oDroppedControl control that the dragged control will be dropped on
* @param {boolean} bIgnoreRTL should RTL configuration be ignored for drag and drop logic
* @param {number} allowedNestingLevels allowed number of nesting tabs via drag and drop
*/
handleDrop: function (oContext, sDropPosition, oDraggedControl, oDroppedControl, bIgnoreRTL, allowedNestingLevels) {
var iBeginDragIndex = oContext.indexOfItem(oDraggedControl),
iDropIndex = oContext.indexOfItem(oDroppedControl),
iAggregationDropIndex = 0,
bRtl = Configuration.getRTL(),
bIsDropPositionBefore = sDropPosition === INSERT_POSITION_BEFORE,
//_getNestedLevel returns 1 there is no nesting
currentNestedLevel = oDroppedControl._getNestedLevel() - 1;
// Prevent cycle
if (oDraggedControl._isParentOf(oDroppedControl)) {
return;
}
if (currentNestedLevel === allowedNestingLevels && sDropPosition === DropPosition.On) {
return;
}
if (bRtl && !bIgnoreRTL) {
if (bIsDropPositionBefore) {
iAggregationDropIndex = iBeginDragIndex < iDropIndex ? iDropIndex : iDropIndex + 1;
sInsertAfterBeforePosition = INSERT_AFTER;
} else {
iAggregationDropIndex = iBeginDragIndex < iDropIndex ? iDropIndex - 1 : iDropIndex;
sInsertAfterBeforePosition = INSERT_BEFORE;
}
} else {
if (bIsDropPositionBefore) {
iAggregationDropIndex = iBeginDragIndex < iDropIndex ? iDropIndex - 1 : iDropIndex;
sInsertAfterBeforePosition = INSERT_BEFORE;
} else {
iAggregationDropIndex = iBeginDragIndex < iDropIndex ? iDropIndex : iDropIndex + 1;
sInsertAfterBeforePosition = INSERT_AFTER;
}
}
if (oContext.isA("sap.m.IconTabFilter") || !oDraggedControl.getParent().isA("sap.m.IconTabHeader")){
if (bIsDropPositionBefore) {
iAggregationDropIndex = iDropIndex;
} else {
iAggregationDropIndex = iDropIndex + 1;
}
}
IconTabBarDragAndDropUtil._insertControl(sInsertAfterBeforePosition, oDraggedControl, oDroppedControl);
if (sDropPosition === DropPosition.On) {
if (oDroppedControl === oDraggedControl) {
return;
}
iAggregationDropIndex = oContext.getAggregation("items").length;
}
IconTabBarDragAndDropUtil._handleConfigurationAfterDragAndDrop.call(oContext, oDraggedControl, iAggregationDropIndex);
},
/**
* Recalculates and sets the correct aria-posinset attribute value.
* @private
*/
_updateAccessibilityInfo: function () {
var oIconTabHeaderItems = this.getItems(),
iAriaPointSet = 1,
oItemDom;
oIconTabHeaderItems.forEach(function (oItem) {
oItemDom = oItem.getDomRef();
if (oItemDom && oItemDom.getAttribute("aria-posinset") !== null) {
oItemDom.setAttribute("aria-posinset", iAriaPointSet++);
}
});
},
/**
* Handles aggregation of control after drag and drop.
* @param {object} oDraggedControl Dragged control
* @param {number} iDropIndex Drop index
* @private
*/
_handleConfigurationAfterDragAndDrop: function (oDraggedControl, iDropIndex) {
var aDraggedControlSubItems = [],
oIconTabHeader = this.isA("sap.m.IconTabHeader") ? this : this._getIconTabHeader();
if (this.isA("sap.m.IconTabBarSelectList")) {
aDraggedControlSubItems = this.getItems().filter(function (oItem) {
return oDraggedControl._getRealTab()._isParentOf(oItem._getRealTab());
});
}
oIconTabHeader._setPreserveSelection(true);
this.removeAggregation('items', oDraggedControl, true);
this.insertAggregation('items', oDraggedControl, iDropIndex, true);
aDraggedControlSubItems.forEach(function (oItem) {
this.removeAggregation('items', oItem, true);
}.bind(this));
var iNewDragIndex = 1 + this.indexOfAggregation('items', oDraggedControl);
aDraggedControlSubItems.reverse().forEach(function (oItem) {
this.insertAggregation('items', oItem, iNewDragIndex, true);
}.bind(this));
oIconTabHeader._setPreserveSelection(false);
IconTabBarDragAndDropUtil._updateAccessibilityInfo.call(this);
},
/**
* Decreases the drop index.
* @param {int} iBeginDragIndex Index of dragged control
* @param {sap.m.IconTabFilter[]} aItems All items in the header/select list
* @returns {int} The new index of the item
* @private
*/
_decreaseDropIndex: function (iBeginDragIndex, aItems) {
var iPrevIndex = iBeginDragIndex - 1;
// Jump over invisible items and sub items
while (iPrevIndex >= 0 &&
(aItems[iBeginDragIndex]._getRealTab()._getNestedLevel() !== aItems[iPrevIndex]._getRealTab()._getNestedLevel() ||
!aItems[iPrevIndex].getVisible() || (!aItems[iBeginDragIndex].$().hasClass("sapMITBFilterHidden") && aItems[iPrevIndex].$().hasClass("sapMITBFilterHidden")))) {
iPrevIndex--;
}
if (iPrevIndex < 0) {
sInsertAfterBeforePosition = INSERT_AFTER;
return iBeginDragIndex;
}
sInsertAfterBeforePosition = INSERT_BEFORE;
return iPrevIndex;
},
/**
* Increases the drop index.
* @param {int} iBeginDragIndex Index of dragged control
* @param {array} aItems All items in the header
* @param {int} iMaxIndex Maximum allowed index. For the header this is the end of the tab strip.
* @returns {int} The new index of the item
* @private
*/
_increaseDropIndex: function (iBeginDragIndex, aItems, iMaxIndex) {
var iNextIndex = iBeginDragIndex + 1;
// Jump over invisible items and sub items
while (iNextIndex < aItems.length &&
(aItems[iBeginDragIndex]._getRealTab()._getNestedLevel() !== aItems[iNextIndex]._getRealTab()._getNestedLevel() || !aItems[iNextIndex].getVisible())) {
iNextIndex++;
}
if (iNextIndex > iMaxIndex) {
sInsertAfterBeforePosition = INSERT_BEFORE;
return iBeginDragIndex;
}
sInsertAfterBeforePosition = INSERT_AFTER;
return iNextIndex;
},
/**
* Moves focused control depending on the combinations of pressed keys.
*
* @param {object} oDraggedControl Control that is going to be moved
* @param {number} iKeyCode Key code
* @param {int} iMaxIndex Maximum allowed index. For the header this is the end of the tab strip.
* @returns {boolean} returns true is scrolling will be needed
*/
moveItem: function (oDraggedControl, iKeyCode, iMaxIndex) {
var aItems = this.getItems(),
iBeginDragIndex = this.indexOfItem(oDraggedControl),
bRtl = Configuration.getRTL(),
iNewDropIndex,
bPrevent;
if (this.isA("sap.m.IconTabFilter")){
aItems = this._getRealTab().getItems();
}
switch (iKeyCode) {
//Handles Ctrl + Home
case KeyCodes.HOME:
iNewDropIndex = 0;
sInsertAfterBeforePosition = INSERT_BEFORE;
break;
//Handles Ctrl + End
case KeyCodes.END:
iNewDropIndex = aItems.length - 1;
sInsertAfterBeforePosition = INSERT_AFTER;
break;
// Handles Ctrl + Left Arrow
case KeyCodes.ARROW_LEFT:
if (bRtl) {
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_FORWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._increaseDropIndex(iBeginDragIndex, aItems, iMaxIndex);
} else {
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_BACKWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._decreaseDropIndex(iBeginDragIndex, aItems);
}
break;
// Handles Ctrl + Right Arrow
case KeyCodes.ARROW_RIGHT:
if (bRtl) {
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_BACKWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._decreaseDropIndex(iBeginDragIndex, aItems);
} else {
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_FORWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._increaseDropIndex(iBeginDragIndex, aItems, iMaxIndex);
}
break;
// Handles Ctrl + Arrow Down
case KeyCodes.ARROW_DOWN:
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_FORWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._increaseDropIndex(iBeginDragIndex, aItems, iMaxIndex);
break;
// Handles Ctrl + Arrow Up
case KeyCodes.ARROW_UP:
bPrevent = IconTabBarDragAndDropUtil.preventDragBetweenSubItems(oDraggedControl, DRAG_DIRECTION_BACKWARD, this);
iNewDropIndex = IconTabBarDragAndDropUtil._decreaseDropIndex(iBeginDragIndex, aItems);
break;
default:
return false;
}
if (bPrevent) {
return false;
}
if (!this.isA("sap.m.IconTabFilter")) {
var oDroppedControl = aItems[iNewDropIndex];
IconTabBarDragAndDropUtil._insertControl(sInsertAfterBeforePosition, oDraggedControl, oDroppedControl, this._oTabFilter && this._oTabFilter._bIsOverflow);
}
IconTabBarDragAndDropUtil._handleConfigurationAfterDragAndDrop.call(this, oDraggedControl, iNewDropIndex);
return true;
},
/**
* Adding aggregations for drag and drop.
* @param {object} context from which context function is called (sap.m.IconTabHeader or sap.m.IconTabSelectList)
* @param {string} sDropLayout Depending on the control we are dragging in, it could be Vertical or Horizontal
* @param {object} oDropPosition Depending on maxNestingLevel, value could be 'On' or 'Between'
*/
setDragDropAggregations: function (context, sDropLayout, oDropPosition) {
var oIconTabHeader = context._oIconTabHeader ? context._oIconTabHeader : context;
var sIconTabHeaderId = oIconTabHeader.getId();
//Adding Drag&Drop configuration to the dragDropConfig aggregation if needed
context.addDragDropConfig(new DragInfo({
sourceAggregation: "items",
groupName: DRAG_DROP_GROUP_NAME + sIconTabHeaderId
}));
context.addDragDropConfig(new DropInfo({
targetAggregation: "items",
dropPosition: oDropPosition,
dropLayout: sDropLayout,
drop: context._handleDragAndDrop.bind(context),
groupName: DRAG_DROP_GROUP_NAME + sIconTabHeaderId
}));
},
/**
* Prevents drag and drop to be executed between different level sub items in sap.m.IconTabBarSelectList.
* @param {object} oDraggedControl Control that is going to be moved
* @param {string} sDirection Depending on the direction of we are dragging in, it could be Forward or Backward
* @param {object} oContext from which context function is called (sap.m.IconTabHeader or sap.m.IconTabSelectList)
*
* @returns {boolean} returns true is scrolling will be needed
*/
preventDragBetweenSubItems: function (oDraggedControl, sDirection, oContext) {
var bPrevent = false;
if (oContext.isA("sap.m.IconTabBarSelectList")) {
var oRealTab = oDraggedControl._getRealTab(),
oParent = oRealTab.getParent(),
aChildren = oParent.getItems();
if ((aChildren.indexOf(oRealTab) === 0 && sDirection === DRAG_DIRECTION_BACKWARD)
|| (aChildren.indexOf(oRealTab) + 1 === aChildren.length && sDirection === DRAG_DIRECTION_FORWARD)
|| aChildren.length === 1) {
bPrevent = true;
}
}
return bPrevent;
}
};
return IconTabBarDragAndDropUtil;
});