defaultRenderer({ cellElement : targetElement, record, grid, size, rowElement }) {
const
{
events,
date
} = record,
children = [];
rowElement.classList.add(grid.agendaRowCls);
targetElement.classList[record.isNonWorking ? 'add' : 'remove']('b-nonworking-day');
targetElement.classList[grid.enableSticky ? 'add' : 'remove']('b-sticky-cell');
for (let i = 0; i < events.length; i++) {
const
eventRecord = events[i],
eventEndDate = eventRecord.endDate || DH.add(eventRecord.startDate, eventRecord.duration, eventRecord.durationUnit),
isOverflow = eventRecord.startDate < date,
overflows = eventEndDate > record.tomorrow,
eventDomConfig = grid.internalEventRenderer({
date : record.date,
isAllDay : eventRecord.allDay || overflows || isOverflow,
eventRecord
});
// Arrow shows that it continues
eventDomConfig.className['b-continues-right'] = overflows;
eventDomConfig.className['b-continues-left'] = isOverflow;
children.push({
style : {
marginBottom : `${grid.eventRowSpacing}px`
},
className : {
'b-cal-agenda-event-row' : 1
},
dataset : {
rowId : eventRecord.id
},
children : [
grid.internalEventTimeRenderer(eventRecord),
eventDomConfig
],
// Match existing data-rowId elements first and ensure DOM order matches
// children order.
syncOptions : {
syncIdField : 'rowId',
releaseThreshold : 0,
strict : true
}
});
}
if (grid._cellRenderer) {
grid._cellRenderer(...arguments);
}
DomSync.sync({
domConfig : {
dataset : {
date : DH.format(date, 'YYYY-MM-DD')
},
children : [
grid.internalAgendaDateRenderer(date),
{
className : {
'b-cal-event-bar-container' : 1
},
children
}
],
// Match existing data-row-id elements first and ensure DOM order matches
// children order.
syncOptions : {
syncIdField : 'rowId',
releaseThreshold : 0,
strict : true
}
},
targetElement
});
// THIS IS THE FIX. Code to record the row's height has moved to here.
// NOTE that any images in the rendered data MUST have CSS-defined
// heights so that the scrollHeight can be measured.
size.height = grid.eventRenderer ? targetElement.scrollHeight : Math.max(record.events.length * (grid.eventHeight + grid.eventRowSpacing) - grid.eventRowSpacing + 40, 86);
}
For AgendaView :
internalEventRenderer(renderData) {
const
me = this,
{
eventRenderer,
eventHeight,
eventArrows,
intradayCls,
alldayCls,
pastEventCls,
showTime,
timeFormat
} = me,
calendar = me.up('calendar'),
{
eventRecord,
date
} = renderData,
eventEndDate = eventRecord.endDate || DH.add(eventRecord.startDate, eventRecord.duration, eventRecord.durationUnit),
resourceRecord = eventRecord.isOccurrence ? eventRecord.recurringEvent.resource : eventRecord.resource,
isRecurring = eventRecord.isRecurring || eventRecord.isOccurrence,
isAllDay = ('isAllDay' in renderData) ? renderData.isAllDay : (eventRecord.allDay || eventRecord.isInterDay),
arrowWidth = eventHeight / 3,
arrowHeight = eventHeight / 2,
startArrowStyle = {
'border-width' : `${arrowHeight}px ${arrowWidth}px ${arrowHeight}px 0`
},
eventInnerStyle = {
height : DomHelper.setLength(eventHeight)
},
endArrowStyle = {
'border-width' : `${arrowHeight}px 0 ${arrowHeight}px ${arrowWidth}px`
};
// Allow subclasses to create body content differently.
// DayView will create different content layout.
let bodyContent = me.internalBodyContentRenderer(eventRecord);
// Make DomClassList copies for renderers to mutate.
// We add our essential classes in after the renderer has run
// then use these in the DomConfig object
renderData.cls = eventRecord.cls.clone();
renderData.iconCls = new DomClassList(eventRecord.iconCls); // Not a DomClassList, so not cloneable
renderData.style = Object.assign(DomHelper.parseStyle(resourceRecord?.eventStyle), DomHelper.parseStyle(eventRecord.style));
renderData.eventColor = eventRecord.color || eventRecord.eventColor || resourceRecord?.eventColor || emptyString;
renderData.eventHeight = eventHeight;
if (resourceRecord?.cls) {
renderData.cls.add(resourceRecord.cls);
}
if (eventRenderer) {
// Renderer may set renderedEvent style and cls
const rendererValue = me.callback(eventRenderer, me, [{
eventRecord,
resourceRecord,
renderData
}]);
// Allow renderer to change the event height <===== THIS BLOCK IS THE FIX ========<<<<<<
if (renderData.eventHeight !== eventHeight) {
eventInnerStyle.height = DomHelper.setLength(renderData.eventHeight);
}
if (rendererValue != null) {
bodyContent = rendererValue;
}
// If the renderer has replaced the DomClassList with a string, promote back to a DomClassList
if (typeof renderData.cls === 'string') {
renderData.cls = new DomClassList(renderData.cls);
}
// Same goes for iconCls
if (typeof renderData.iconCls === 'string') {
renderData.iconCls = new DomClassList(renderData.iconCls);
}
// If the renderer set it to be a string, reinstate it as an object so we can add our essential styles
if (typeof renderData.style === 'string') {
renderData.style = DomHelper.parseStyle(renderData.style);
}
}
bodyContent = [{
className : 'b-cal-event-desc',
html : bodyContent
}];
// Some views mix intra and multi day events, but want the icons
// to line up. AgendaView defaults this to true.
if (me.alignIconOfStartsBeforeEvents && date && eventRecord.startDate < date) {
renderData.style.marginLeft = `-${arrowWidth}px`;
}
// Set this after renderer has seen the data
renderData.style.marginBottom = `${me.eventSpacing}px`;
// Add essential classes for eventWrap *after* the renderer has run
Object.assign(renderData.cls, {
'b-cal-event-wrap' : 1,
[alldayCls] : alldayCls && isAllDay,
[intradayCls] : intradayCls && !isAllDay,
[pastEventCls] : eventEndDate < new Date(),
'b-selected' : calendar?.isEventSelected(eventRecord)
});
const color = renderData.eventColor;
if (color) {
if (color.startsWith('#')) {
// Always set the color styles in case a previously set colour has been unset. In this case, we
// set the value to an empty String object in order to avoid any falsy traps in called code.
// The style value will always be set to ''
if (isAllDay) {
// The border color is inherited by the start and end arrows which signify
// pointers to previous and next week. The bar element does not have a border.
renderData.style['border-color'] = eventInnerStyle['background-color'] = color;
}
else {
eventInnerStyle[me.eventColourStyleProperty] = color;
}
}
// None-hex colors are take to be one of the predefined colors
else if (color !== emptyString) {
renderData.cls[`b-cal-color-${color}`] = 1;
}
}
if (showTime && !isAllDay) {
bodyContent.unshift({
className : 'b-event-header',
children : [
{
className : 'b-event-time',
html : DH.format(eventRecord.startDate, timeFormat)
}
]
});
}
const
hasIcon = Boolean(renderData.iconCls.length), // Pull iconCls out of the renderData
iconStyle = me.iconTarget === 'header' ? { color } : emptyObject,
useIconAsRecurrIcon = !hasIcon && isRecurring,
showCircle = me.showCircle && !hasIcon && !isRecurring,
iconElement = {
tag : 'i',
className : Object.assign({
'b-cal-event-icon' : !useIconAsRecurrIcon,
'b-cal-recurrence-icon' : useIconAsRecurrIcon,
'b-icon' : 1,
'b-fw-icon' : 1,
'b-icon-circle' : showCircle,
'b-icon-recurring' : useIconAsRecurrIcon
}, renderData.iconCls),
style : iconStyle
},
eventInnerContent = [{
className : 'b-cal-event-body',
children : bodyContent
}],
iconParent = me.iconTarget === 'header' ? (bodyContent[0].children.length > 0 ? bodyContent[0].children : bodyContent) : eventInnerContent;
if (me.iconTarget === 'header') {
iconParent.push(iconElement);
}
else {
iconParent.unshift(iconElement);
}
// If the event had its own icon and is recurring, the recurrence icon is extra
if (hasIcon && isRecurring) {
iconParent.push({
tag : 'i',
className : {
'b-cal-recurrence-icon' : 1,
'b-icon' : 1,
'b-fw-icon' : 1,
'b-icon-recurring' : 1
},
style : iconStyle
});
}
return {
// Events are tabbable
tabIndex : 0,
dataset : {
eventId : eventRecord.id
},
className : renderData.cls,
style : renderData.style,
children : [eventArrows ? {
className : 'b-start-arrow',
style : startArrowStyle
} : null, {
className : 'b-cal-event',
style : eventInnerStyle,
children : eventInnerContent
}, eventArrows ? {
className : 'b-end-arrow',
style : endArrowStyle
} : null]
};
}
And in your app's SCSS file:
.b-cal-agenda-event-row {
// Images must have defined height so that the rendered cell can be measured
// By AgendaColumn's defaultRenderer
.b-event-image {
height : 100px;
}
}
And in your custom eventRenderer:
eventRenderer : ({ eventRecord, renderData }) => {
...
// Informs AgendaColumn's rendering that it must *measure* the content height
// instead of multiplying its configured eventHeight by the number of events in that day.
renderData.eventHeight = 'auto';
return `<div class="agenda-event-container">
<img class="b-event-image" src="${img}"/>
<h6>${discipline}</h6>
<p>${description}</p>
</div>`;
}