Closed ExtAnimal closed 1 month ago
It should always show the generated, empty cell for the current date
:
Code :
onMonthChange() {
super.onMonthChange(...arguments);
// No cells, and there's a date change with showAtLeastOneCell set
// We must ensure that the store is repopulated with the generated
// cell for the new date.
// If the date change is to a date range with data, populateStore will
// be called immediately which cancels the populateStoreSoon queue.
if (!this._cellMap?.size && this.showAtLeastOneCell) {
this.populateStoreSoon();
}
}
populateStore() {
this._cellMap?.clear();
const
me = this,
{
store,
eventStore,
rowManager
} = me,
{ rowHeight } = rowManager,
rowCount = rowManager.rows?.length,
eventHeight = isNaN(me.eventHeight) ? 25 : me.eventHeight;
me._eventCount = 0;
me.populateStoreSoon.cancel();
if (!me.date) {
// Avoid recursion into populateStore
me.isConfiguring = true;
me.date = eventStore.map(r => r.startDate).sort((lhs, rhs) => lhs.valueOf() - rhs.valueOf())[0];
me.isConfiguring = false;
}
const
{
cellMap,
firstVisibleDate
} = me,
endDate = DH.add(me.endDate, me.range ? 0 : 1, 'd'),
cellMapEntries = [...cellMap.values()],
sortedEntries = [];
me.dateIndex = {};
// If configured to do so, ensure there is always a cell for the start date if the range turns out to be empty,
// so that user has something to interact with
if (me.showAtLeastOneCell && !cellMapEntries.length) {
cellMapEntries.push(me.createCellData(me.date));
}
for (let i = 0, { length } = cellMapEntries; i < length; i++) {
const
cellData = cellMapEntries[i],
{ events, date } = cellData;
// Recurring event continuation blocks which are past a midnight boundary are inserted into
// the cellMap even if they are beyond the end date. Eliminate these from the view.
if (date >= firstVisibleDate && date < endDate) {
// Count unique events
for (let j = 0, { length } = events; j < length; j++) {
const event = events[j];
if (!me.isAllDayEvent(event) || !i || DH.clearTime(event.startDate).valueOf() === date.valueOf()) {
me._eventCount++;
}
}
// Build Store data array in ascending YYYY-MM-DD order.
// The ordered insertion is needed because generated occurrences are
// added to the Map in a second pass, and it will not be in order.
// Other views iterate their date range and pull cell info using the key.
// This view is a grid which renders rows in the store's order.
const
cellInfo = store.createRecord(cellData),
idx = ArrayHelper.findInsertionIndex(cellInfo, sortedEntries, compareDate);
sortedEntries.splice(idx, 0, cellInfo);
me.dateIndex[cellData.id] = cellInfo;
}
}
const avgEventsPerCell = me._eventCount ? sortedEntries.map(e => e.events.length).reduce((a, b) => a + b, 0) / cellMapEntries.length : 0;
store.suspendEvents();
store.loadData(sortedEntries);
store.resumeEvents();
// Give RowManager a clue so that it can calculate an appropriate rowCount.
// If the rows are tall, we do not need many to cover the viewport.
rowManager._rowHeight = 20;
// RowManager#set rowHeight does not tolerate no rows.
if (store.count) {
rowManager.rowHeight = Math.max(avgEventsPerCell * (eventHeight + me.eventSpacing), 70);
}
// Setting the rowHeight does a refresh if there are existing rows and the height actually changed.
// Otherwise, we explicitly refresh now.
if (!rowCount || !store.count || rowManager.rowHeight === rowHeight) {
rowManager.calculateRowCount();
rowManager.estimateTotalHeight(true);
}
me.refreshCount = (me.refreshCount || 0) + 1;
/**
* Fires when this AgendaView refreshes.
* @param {Calendar.widget.AgendaView} source The triggering instance.
* @event refresh
*/
me.trigger('refresh');
// The owning Calendar's UI may need to sync with the new state
me.calendar?.syncUIWithActiveView(me);
me.columns.forEach(c => c.constructor.exposeProperties?.());
// Evaluate this late so that it doesn't change the order of date config evaluation
// Ensure that the menu stays aligned if scrollbar causes button movement.
me.settings?._menu?.realign();
}
Forum post
To allow user interaction to create events.
Suggested code in thread