Remove this stupid stacking logic
This commit is contained in:
parent
fc884efa71
commit
1a47214831
1 changed files with 11 additions and 469 deletions
|
|
@ -2,16 +2,11 @@
|
|||
|
||||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
import { eventBus } from '../core/EventBus';
|
||||
import { OverlapDetector, OverlapResult } from '../utils/OverlapDetector';
|
||||
import { SwpEventElement } from '../elements/SwpEventElement';
|
||||
import { TimeFormatter } from '../utils/TimeFormatter';
|
||||
import { PositionUtils } from '../utils/PositionUtils';
|
||||
import { DragOffset, StackLinkData } from '../types/DragDropTypes';
|
||||
import { ColumnBounds } from '../utils/ColumnDetectionUtils';
|
||||
import { DragColumnChangeEventPayload, DragMoveEventPayload, DragStartEventPayload } from '../types/EventTypes';
|
||||
import { DateService } from '../utils/DateService';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Interface for event rendering strategies
|
||||
|
|
@ -27,10 +22,6 @@ export interface EventRendererStrategy {
|
|||
handleColumnChange?(payload: DragColumnChangeEventPayload): void;
|
||||
handleNavigationCompleted?(): void;
|
||||
}
|
||||
// Abstract methods that subclasses must implement
|
||||
// private getColumns(container: HTMLElement): HTMLElement[];
|
||||
// private getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[];
|
||||
|
||||
|
||||
/**
|
||||
* Date-based event renderer
|
||||
|
|
@ -38,128 +29,14 @@ export interface EventRendererStrategy {
|
|||
export class DateEventRenderer implements EventRendererStrategy {
|
||||
|
||||
private dateService: DateService;
|
||||
private draggedClone: HTMLElement | null = null;
|
||||
private originalEvent: HTMLElement | null = null;
|
||||
|
||||
constructor() {
|
||||
const timezone = calendarConfig.getTimezone?.();
|
||||
this.dateService = new DateService(timezone);
|
||||
this.setupDragEventListeners();
|
||||
}
|
||||
|
||||
private draggedClone: HTMLElement | null = null;
|
||||
private originalEvent: HTMLElement | null = null;
|
||||
|
||||
|
||||
// ============================================
|
||||
// NEW OVERLAP DETECTION SYSTEM
|
||||
// All new functions prefixed with new_
|
||||
// ============================================
|
||||
|
||||
protected overlapDetector = new OverlapDetector();
|
||||
|
||||
/**
|
||||
* Ny hovedfunktion til at håndtere event overlaps
|
||||
* Finder transitivt overlappende events (hvis A overlapper B og B overlapper C, så er A, B, C i samme gruppe)
|
||||
* @param events - Events der skal renderes i kolonnen
|
||||
* @param container - Container element at rendere i
|
||||
*/
|
||||
protected handleEventOverlaps(events: CalendarEvent[], container: HTMLElement): void {
|
||||
if (events.length === 0) return;
|
||||
|
||||
if (events.length === 1) {
|
||||
const element = this.renderEvent(events[0]);
|
||||
container.appendChild(element);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find alle overlap grupper (transitive overlaps)
|
||||
const overlapGroups = this.findTransitiveOverlapGroups(events);
|
||||
|
||||
// Render hver gruppe
|
||||
overlapGroups.forEach(group => {
|
||||
if (group.length === 1) {
|
||||
// Enkelt event uden overlaps
|
||||
const element = this.renderEvent(group[0]);
|
||||
container.appendChild(element);
|
||||
} else {
|
||||
// Gruppe med overlaps - opret stack links
|
||||
// Tag første event som "current" og resten som "overlapping"
|
||||
const [firstEvent, ...restEvents] = group;
|
||||
const result = this.overlapDetector.decorateWithStackLinks(firstEvent, restEvents);
|
||||
this.renderOverlappingEvents(result, container);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find alle grupper af transitivt overlappende events
|
||||
* Bruger Union-Find algoritme til at finde sammenhængende komponenter
|
||||
*/
|
||||
private findTransitiveOverlapGroups(events: CalendarEvent[]): CalendarEvent[][] {
|
||||
// Byg overlap graf
|
||||
const overlapMap = new Map<string, Set<string>>();
|
||||
|
||||
// Initialiser alle events
|
||||
events.forEach(event => {
|
||||
overlapMap.set(event.id, new Set<string>());
|
||||
});
|
||||
|
||||
// Find alle direkte overlaps
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
for (let j = i + 1; j < events.length; j++) {
|
||||
const event1 = events[i];
|
||||
const event2 = events[j];
|
||||
|
||||
// Check om de overlapper
|
||||
if (event1.start < event2.end && event1.end > event2.start) {
|
||||
overlapMap.get(event1.id)!.add(event2.id);
|
||||
overlapMap.get(event2.id)!.add(event1.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find sammenhængende komponenter via DFS
|
||||
const visited = new Set<string>();
|
||||
const groups: CalendarEvent[][] = [];
|
||||
|
||||
events.forEach(event => {
|
||||
if (visited.has(event.id)) return;
|
||||
|
||||
// Start ny gruppe
|
||||
const group: CalendarEvent[] = [];
|
||||
const stack = [event.id];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const currentId = stack.pop()!;
|
||||
|
||||
if (visited.has(currentId)) continue;
|
||||
visited.add(currentId);
|
||||
|
||||
// Find event objektet
|
||||
const currentEvent = events.find(e => e.id === currentId);
|
||||
if (currentEvent) {
|
||||
group.push(currentEvent);
|
||||
}
|
||||
|
||||
// Tilføj alle naboer til stack
|
||||
const neighbors = overlapMap.get(currentId);
|
||||
if (neighbors) {
|
||||
neighbors.forEach(neighborId => {
|
||||
if (!visited.has(neighborId)) {
|
||||
stack.push(neighborId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Sortér gruppe efter start tid
|
||||
group.sort((a, b) => a.start.getTime() - b.start.getTime());
|
||||
groups.push(group);
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
||||
private applyDragStyling(element: HTMLElement): void {
|
||||
element.classList.add('dragging');
|
||||
element.style.removeProperty("margin-left");
|
||||
|
|
@ -331,89 +208,12 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
* Handle drag end event
|
||||
*/
|
||||
public handleDragEnd(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: ColumnBounds, finalY: number): void {
|
||||
|
||||
if (!draggedClone || !originalElement) {
|
||||
console.warn('Missing draggedClone or originalElement');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check om original event var del af en stack
|
||||
const originalStackLink = originalElement.dataset.stackLink;
|
||||
|
||||
if (originalStackLink) {
|
||||
try {
|
||||
const stackData = JSON.parse(originalStackLink);
|
||||
|
||||
// Saml ALLE event IDs fra hele stack chain
|
||||
const allStackEventIds: Set<string> = new Set();
|
||||
|
||||
// Recursive funktion til at traversere stack chain
|
||||
const traverseStack = (linkData: StackLinkData, visitedIds: Set<string>) => {
|
||||
if (linkData.prev && !visitedIds.has(linkData.prev)) {
|
||||
visitedIds.add(linkData.prev);
|
||||
const prevElement = document.querySelector(`swp-time-grid [data-event-id="${linkData.prev}"]`) as HTMLElement;
|
||||
if (prevElement?.dataset.stackLink) {
|
||||
try {
|
||||
const prevLinkData = JSON.parse(prevElement.dataset.stackLink);
|
||||
traverseStack(prevLinkData, visitedIds);
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (linkData.next && !visitedIds.has(linkData.next)) {
|
||||
visitedIds.add(linkData.next);
|
||||
const nextElement = document.querySelector(`swp-time-grid [data-event-id="${linkData.next}"]`) as HTMLElement;
|
||||
if (nextElement?.dataset.stackLink) {
|
||||
try {
|
||||
const nextLinkData = JSON.parse(nextElement.dataset.stackLink);
|
||||
traverseStack(nextLinkData, visitedIds);
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start traversering fra original event's stackLink
|
||||
traverseStack(stackData, allStackEventIds);
|
||||
|
||||
// Fjern original eventId da det bliver flyttet
|
||||
allStackEventIds.delete(eventId);
|
||||
|
||||
// Find alle stack events og fjern dem
|
||||
const stackEvents: CalendarEvent[] = [];
|
||||
let container: HTMLElement | null = null;
|
||||
|
||||
allStackEventIds.forEach(id => {
|
||||
const element = document.querySelector(`swp-time-grid [data-event-id="${id}"]`) as HTMLElement;
|
||||
if (element) {
|
||||
// Gem container reference fra første element
|
||||
if (!container) {
|
||||
container = element.closest('swp-events-layer') as HTMLElement;
|
||||
}
|
||||
|
||||
const event = SwpEventElement.extractCalendarEventFromElement(element);
|
||||
if (event) {
|
||||
stackEvents.push(event);
|
||||
}
|
||||
|
||||
// Fjern elementet
|
||||
element.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Re-render stack events hvis vi fandt nogle
|
||||
if (stackEvents.length > 0 && container) {
|
||||
this.handleEventOverlaps(stackEvents, container);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse stackLink data:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove original event from any existing groups first
|
||||
this.removeEventFromExistingGroups(originalElement);
|
||||
|
||||
// Fade out original
|
||||
// TODO: this should be changed into a subscriber which only after a succesful placement is fired, not just mouseup as this can remove elements that are not placed.
|
||||
this.fadeOutAndRemove(originalElement);
|
||||
|
||||
// Remove clone prefix and normalize clone to be a regular event
|
||||
|
|
@ -424,23 +224,10 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
|
||||
// Fully normalize the clone to be a regular event
|
||||
draggedClone.classList.remove('dragging');
|
||||
// Behold z-index hvis det er et stacked event
|
||||
|
||||
// Data attributes are already updated during drag:move, so no need to update again
|
||||
// The updateCloneTimestamp method keeps them synchronized throughout the drag operation
|
||||
|
||||
// Detect overlaps with other events in the target column and reposition if needed
|
||||
this.handleDragDropOverlaps(draggedClone, finalColumn);
|
||||
|
||||
// Fjern stackLink data fra dropped element
|
||||
if (draggedClone.dataset.stackLink) {
|
||||
delete draggedClone.dataset.stackLink;
|
||||
}
|
||||
|
||||
// Clean up instance state (no longer needed since we get elements as parameters)
|
||||
// Clean up instance state
|
||||
this.draggedClone = null;
|
||||
this.originalEvent = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -450,167 +237,6 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
// Default implementation - can be overridden by subclasses
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle overlap detection and re-rendering after drag-drop
|
||||
*/
|
||||
private handleDragDropOverlaps(droppedElement: HTMLElement, targetColumn: ColumnBounds): void {
|
||||
|
||||
const eventsLayer = targetColumn.element.querySelector('swp-events-layer') as HTMLElement;
|
||||
if (!eventsLayer) return;
|
||||
|
||||
// Convert dropped element to CalendarEvent with new position
|
||||
const droppedEvent = SwpEventElement.extractCalendarEventFromElement(droppedElement);
|
||||
if (!droppedEvent) return;
|
||||
|
||||
// Get existing events in the column (excluding the dropped element)
|
||||
const existingEvents = this.getEventsInColumn(eventsLayer, droppedElement.dataset.eventId);
|
||||
|
||||
// Find overlaps with the dropped event
|
||||
const overlappingEvents = this.overlapDetector.resolveOverlap(droppedEvent, existingEvents);
|
||||
|
||||
if (overlappingEvents.length > 0) {
|
||||
// Collect ALL events in stack chains (not just direct overlaps)
|
||||
const allStackedEvents = this.collectAllStackedEvents(overlappingEvents, eventsLayer);
|
||||
|
||||
// Remove all affected events from DOM
|
||||
const affectedEventIds = [droppedEvent.id, ...allStackedEvents.map(e => e.id)];
|
||||
eventsLayer.querySelectorAll('swp-event').forEach(el => {
|
||||
const eventId = (el as HTMLElement).dataset.eventId;
|
||||
if (eventId && affectedEventIds.includes(eventId)) {
|
||||
el.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Re-render all affected events with overlap handling
|
||||
const affectedEvents = [droppedEvent, ...allStackedEvents];
|
||||
this.handleEventOverlaps(affectedEvents, eventsLayer);
|
||||
} else {
|
||||
// Reset z-index for non-overlapping events
|
||||
droppedElement.style.zIndex = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all events in stack chains for the given overlapping events
|
||||
* This ensures we re-render entire stack chains, not just direct overlaps
|
||||
*/
|
||||
private collectAllStackedEvents(overlappingEvents: CalendarEvent[], eventsLayer: HTMLElement): CalendarEvent[] {
|
||||
const allEvents = new Map<string, CalendarEvent>();
|
||||
const visitedIds = new Set<string>();
|
||||
|
||||
// Add all directly overlapping events
|
||||
overlappingEvents.forEach(event => {
|
||||
allEvents.set(event.id, event);
|
||||
visitedIds.add(event.id);
|
||||
});
|
||||
|
||||
// For each overlapping event, traverse its stack chain
|
||||
overlappingEvents.forEach(event => {
|
||||
const element = eventsLayer.querySelector(`swp-event[data-event-id="${event.id}"]`) as HTMLElement;
|
||||
if (!element?.dataset.stackLink) return;
|
||||
|
||||
try {
|
||||
const stackData = JSON.parse(element.dataset.stackLink);
|
||||
this.traverseStackChain(stackData, eventsLayer, allEvents, visitedIds);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse stackLink:', e);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(allEvents.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverse stack chain to find all connected events
|
||||
*/
|
||||
private traverseStackChain(
|
||||
stackLink: StackLinkData,
|
||||
eventsLayer: HTMLElement,
|
||||
allEvents: Map<string, CalendarEvent>,
|
||||
visitedIds: Set<string>
|
||||
): void {
|
||||
// Traverse previous events
|
||||
if (stackLink.prev && !visitedIds.has(stackLink.prev)) {
|
||||
visitedIds.add(stackLink.prev);
|
||||
const prevElement = eventsLayer.querySelector(`swp-event[data-event-id="${stackLink.prev}"]`) as HTMLElement;
|
||||
|
||||
if (prevElement) {
|
||||
const prevEvent = SwpEventElement.extractCalendarEventFromElement(prevElement);
|
||||
if (prevEvent) {
|
||||
allEvents.set(prevEvent.id, prevEvent);
|
||||
|
||||
// Continue traversing
|
||||
if (prevElement.dataset.stackLink) {
|
||||
try {
|
||||
const prevStackData = JSON.parse(prevElement.dataset.stackLink);
|
||||
this.traverseStackChain(prevStackData, eventsLayer, allEvents, visitedIds);
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse next events
|
||||
if (stackLink.next && !visitedIds.has(stackLink.next)) {
|
||||
visitedIds.add(stackLink.next);
|
||||
const nextElement = eventsLayer.querySelector(`swp-event[data-event-id="${stackLink.next}"]`) as HTMLElement;
|
||||
|
||||
if (nextElement) {
|
||||
const nextEvent = SwpEventElement.extractCalendarEventFromElement(nextElement);
|
||||
if (nextEvent) {
|
||||
allEvents.set(nextEvent.id, nextEvent);
|
||||
|
||||
// Continue traversing
|
||||
if (nextElement.dataset.stackLink) {
|
||||
try {
|
||||
const nextStackData = JSON.parse(nextElement.dataset.stackLink);
|
||||
this.traverseStackChain(nextStackData, eventsLayer, allEvents, visitedIds);
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all events in a column as CalendarEvent objects
|
||||
*/
|
||||
private getEventsInColumn(eventsLayer: HTMLElement, excludeEventId?: string): CalendarEvent[] {
|
||||
const eventElements = eventsLayer.querySelectorAll('swp-event');
|
||||
const events: CalendarEvent[] = [];
|
||||
|
||||
eventElements.forEach(el => {
|
||||
const element = el as HTMLElement;
|
||||
const eventId = element.dataset.eventId;
|
||||
|
||||
// Skip the excluded event (e.g., the dropped event)
|
||||
if (excludeEventId && eventId === excludeEventId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = SwpEventElement.extractCalendarEventFromElement(element);
|
||||
if (event) {
|
||||
events.push(event);
|
||||
}
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove event from any existing groups and cleanup empty containers
|
||||
* In the new system, this is handled automatically by re-rendering overlaps
|
||||
*/
|
||||
private removeEventFromExistingGroups(eventElement: HTMLElement): void {
|
||||
// With the new system, overlap relationships are recalculated on drop
|
||||
// No need to manually track and remove from groups
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle conversion to all-day event
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fade out and remove element
|
||||
*/
|
||||
|
|
@ -625,44 +251,29 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
|
||||
|
||||
renderEvents(events: CalendarEvent[], container: HTMLElement): void {
|
||||
|
||||
// Filter out all-day events - they should be handled by AllDayEventRenderer
|
||||
const timedEvents = events.filter(event => !event.allDay);
|
||||
|
||||
console.log('🎯 EventRenderer: Filtering events', {
|
||||
totalEvents: events.length,
|
||||
timedEvents: timedEvents.length,
|
||||
filteredOutAllDay: events.length - timedEvents.length
|
||||
});
|
||||
|
||||
// Find columns in the specific container for regular events
|
||||
const columns = this.getColumns(container);
|
||||
|
||||
columns.forEach(column => {
|
||||
const columnEvents = this.getEventsForColumn(column, timedEvents);
|
||||
|
||||
const eventsLayer = column.querySelector('swp-events-layer');
|
||||
|
||||
if (eventsLayer) {
|
||||
|
||||
this.handleEventOverlaps(columnEvents, eventsLayer as HTMLElement);
|
||||
// Simply render each event - no overlap handling
|
||||
columnEvents.forEach(event => {
|
||||
const element = this.renderEvent(event);
|
||||
eventsLayer.appendChild(element);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private renderEvent(event: CalendarEvent): HTMLElement {
|
||||
const swpEvent = SwpEventElement.fromCalendarEvent(event);
|
||||
const eventElement = swpEvent.getElement();
|
||||
|
||||
// Setup resize handles on first mouseover only
|
||||
eventElement.addEventListener('mouseover', () => { // TODO: This is not the correct way... we should not add eventlistener on every event
|
||||
if (eventElement.dataset.hasResizeHandlers !== 'true') {
|
||||
eventElement.dataset.hasResizeHandlers = 'true';
|
||||
}
|
||||
}, { once: true });
|
||||
|
||||
return eventElement;
|
||||
return swpEvent.getElement();
|
||||
}
|
||||
|
||||
protected calculateEventPosition(event: CalendarEvent): { top: number; height: number } {
|
||||
|
|
@ -671,7 +282,7 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
}
|
||||
|
||||
clearEvents(container?: HTMLElement): void {
|
||||
const selector = 'swp-event, swp-event-group';
|
||||
const selector = 'swp-event';
|
||||
const existingEvents = container
|
||||
? container.querySelectorAll(selector)
|
||||
: document.querySelectorAll(selector);
|
||||
|
|
@ -679,75 +290,6 @@ export class DateEventRenderer implements EventRendererStrategy {
|
|||
existingEvents.forEach(event => event.remove());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderer overlappende events baseret på OverlapResult
|
||||
* @param result - OverlapResult med events og stack links
|
||||
* @param container - Container at rendere i
|
||||
*/
|
||||
protected renderOverlappingEvents(result: OverlapResult, container: HTMLElement): void {
|
||||
// Iterate direkte gennem stackLinks - allerede sorteret fra decorateWithStackLinks
|
||||
for (const [eventId, stackLink] of result.stackLinks.entries()) {
|
||||
const event = result.overlappingEvents.find(e => e.id === eventId);
|
||||
if (!event) continue;
|
||||
|
||||
const element = this.renderEvent(event);
|
||||
|
||||
// Gem stack link information på DOM elementet
|
||||
element.dataset.stackLink = JSON.stringify({
|
||||
prev: stackLink.prev,
|
||||
next: stackLink.next,
|
||||
stackLevel: stackLink.stackLevel
|
||||
});
|
||||
|
||||
// Check om dette event deler kolonne med foregående (samme start tid)
|
||||
if (stackLink.prev) {
|
||||
const prevEvent = result.overlappingEvents.find(e => e.id === stackLink.prev);
|
||||
if (prevEvent && prevEvent.start.getTime() === event.start.getTime()) {
|
||||
// Samme start tid - del kolonne (side by side)
|
||||
this.new_applyColumnSharingStyling([element]);
|
||||
} else {
|
||||
// Forskellige start tider - stack vertikalt
|
||||
this.new_applyStackStyling(element, stackLink.stackLevel);
|
||||
}
|
||||
} else {
|
||||
// Første event i stack
|
||||
this.new_applyStackStyling(element, stackLink.stackLevel);
|
||||
}
|
||||
|
||||
container.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applicerer stack styling (margin-left og z-index)
|
||||
* @param element - Event element
|
||||
* @param stackLevel - Stack niveau
|
||||
*/
|
||||
protected new_applyStackStyling(element: HTMLElement, stackLevel: number): void {
|
||||
element.style.marginLeft = `${stackLevel * 15}px`;
|
||||
element.style.zIndex = `${100 + stackLevel}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applicerer column sharing styling (flexbox)
|
||||
* @param elements - Event elements der skal dele plads
|
||||
*/
|
||||
protected new_applyColumnSharingStyling(elements: HTMLElement[]): void {
|
||||
elements.forEach(element => {
|
||||
element.style.flex = '1';
|
||||
element.style.minWidth = '50px';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup drag event listeners - placeholder method
|
||||
*/
|
||||
private setupDragEventListeners(): void {
|
||||
// Drag event listeners are handled by EventRendererManager
|
||||
// This method exists for compatibility
|
||||
}
|
||||
|
||||
protected getColumns(container: HTMLElement): HTMLElement[] {
|
||||
const columns = container.querySelectorAll('swp-day-column');
|
||||
return Array.from(columns) as HTMLElement[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue