devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
127 lines (126 loc) • 4.96 kB
JavaScript
/**
* DevExtreme (esm/__internal/scheduler/appointments/m_appointments_kbn.js)
* Version: 25.2.8
* Build date: Mon Jun 08 2026
*
* Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import $ from "../../../core/renderer";
import {
getPublicElement
} from "../../core/m_element";
import eventsEngine from "../../events/core/m_events_engine";
import {
getRawAppointmentGroupValues
} from "../utils/resource_manager/appointment_groups_utils";
export class AppointmentsKeyboardNavigation {
constructor(collection) {
this.focusedItemSortIndex = -1;
this.isNavigating = false;
this._collection = collection
}
getFocusableItems() {
const appts = this._collection._itemElements().not(".dx-state-disabled");
const collectors = this._collection.$element().find(".dx-scheduler-appointment-collector");
return appts.add(collectors)
}
focus($item) {
const $target = $item ?? this.$focusTarget();
if ($target.length) {
eventsEngine.trigger($target, "focus")
}
}
$focusTarget() {
const $items = this._collection.$itemBySortedIndex;
if (!$items) {
return $()
}
const $item = $items[this.focusedItemSortIndex];
return $item || $()
}
resetTabIndex($item) {
const $target = $item ?? this.$focusTarget();
this.getFocusableItems().attr("tabIndex", -1);
$target.attr("tabIndex", this._collection.option("tabIndex"))
}
focusInHandler(e) {
const $target = $(e.target);
const itemData = this._collection.getAppointmentSettings($target);
if (!itemData) {
return
}
this.focusedItemSortIndex = itemData.sortedIndex;
this._collection.option("focusedElement", getPublicElement(e.target))
}
focusOutHandler() {
this._collection.option("focusedElement", getPublicElement(this.getFirstVisibleItem()))
}
getSupportedKeys() {
return {
escape: this.escHandler.bind(this),
del: this.delHandler.bind(this),
tab: this.tabHandler.bind(this)
}
}
delHandler(e) {
if (this._collection.option("allowDelete")) {
e.preventDefault();
const data = this._collection.getAppointmentSettings($(e.target)).itemData;
this._collection.notifyObserver("onDeleteButtonPress", {
data: data,
target: e.target
})
}
}
escHandler() {
if (!this._collection.isResizing) {
return
}
this._collection.moveAppointmentBack();
const resizableInstance = this.$focusTarget().dxResizable("instance");
if (resizableInstance) {
resizableInstance._detachEventHandlers();
resizableInstance._attachEventHandlers();
resizableInstance._toggleResizingClass(false)
}
}
tabHandler(e) {
const items = this._collection.sortedItems;
const nextIndex = this.focusedItemSortIndex + (e.shiftKey ? -1 : 1);
const nextItemData = items[nextIndex];
if (!nextItemData) {
return
}
e.preventDefault();
this.focusByItemData(nextItemData)
}
focusByItemData(itemData) {
this.focusedItemSortIndex = itemData.sortedIndex;
if (this._collection.isVirtualScrolling) {
this.isNavigating = true;
this.scrollToByItemData(itemData)
}
this.focus()
}
scrollToByItemData(itemData) {
const date = new Date(Math.max(this._collection.invoke("getStartViewDate").getTime(), itemData.source.startDate));
const group = getRawAppointmentGroupValues(itemData.itemData, this._collection.getResourceManager().resources);
this._collection.option("scrollTo")(date, {
group: group,
allDay: itemData.allDay
})
}
getFirstVisibleItem() {
const $items = this._collection.$itemBySortedIndex;
const $itemsPlainArray = Object.values($items);
const $firstItem = this._collection.isVirtualScrolling ? $itemsPlainArray.find($item => this.isItemVisibleInViewport($item)) ?? $() : $($itemsPlainArray[0]);
return $firstItem
}
isItemVisibleInViewport($item) {
const $container = this._collection.$element().closest(".dx-scrollable-container");
const containerRect = $container.get(0).getBoundingClientRect();
const itemRect = $item.get(0).getBoundingClientRect();
return itemRect.top < containerRect.bottom && itemRect.bottom > containerRect.top && itemRect.left < containerRect.right && itemRect.right > containerRect.left
}
}