Ext.namespace('Zarafa.calendar.ui');
/**
* @class Zarafa.calendar.ui.AbstractCalendarDaysView
* @extends Zarafa.calendar.ui.AbstractCalendarView
*
* The DaysView is used to display one or more days in columns next to eachother. This is usually limited to 7 days,
* altough more days are supported. For an overview of a large number of days, the {@link Zarafa.calendar.ui.AbstractCalendarBoxView BoxView}
* is however more recommended
*/
Zarafa.calendar.ui.AbstractCalendarDaysView = Ext.extend(Zarafa.calendar.ui.AbstractCalendarView, {
/**
* Array of configuration {@link Zarafa.calendar.data.DayLayoutPosition DayLayoutPositions} within this view.
* @property
* @type Array
*/
dayLayoutPositions : [],
/**
* The number of rows which are needed to display all all-day appointments
* for the given day.
* This property is calculated in {@link #calculateHeaderOverlaps} (called by {@link #onBeforeLayout}) and used in
* {@link getDesiredHeaderHeight} to calculate the number of rows inside the {@link #header}.
* @property
* @type Number
*/
rowCount : 1,
/**
* The format which must be passed to the {@link Date#format} function when
* the width of the dayHeader is smaller then the configured
* {@link Zarafa.calendar.ui.CalendarMultiView#minHeaderDayTextWidth minHeaderDayTextWidth}.
* If there is sufficient width, then {@link #longDayHeaderFormat} will be used.
* @property
* @type String
*/
shortDayHeaderFormat : _('jS'),
/**
* The format which must be passed to the {@link Date#format} function when
* the width of the dayHeader is greater then the configured
* {@link Zarafa.calendar.ui.CalendarMultiView#minHeaderDayTextWidth minHeaderDayTextWidth}.
* If there is not sufficient width, then {@link #shortDayHeaderFormat} will be used.
* @property
* @type String
*/
longDayHeaderFormat : _('l jS F'),
/**
* @constructor
* @param {Object} config Configuration object
*/
constructor : function(config)
{
config = config || {};
Ext.applyIf(config, {
// Add 1 pixel to the left margin, this prevents the appointment
// to overlap with the border.
appointmentBodyLeftMargin : 1
});
Zarafa.calendar.ui.AbstractCalendarDaysView.superclass.constructor.call(this, config);
},
* The {@link Zarafa.calendar.ui.CalendarMultiView CalendarMultiView} view has a header area that automatically
* resizes when its child views require more space.
* @return {Number} height in pixels the calendar view needs to properly lay out its header.
*/
getDesiredHeaderHeight : function()
{
// this.rowCount has been calculated in onBeforeLayout, so by the time this function is called it
// should be up to date
return Math.max(this.rowCount || 1, 1) * this.parentView.headerItemHeight + this.parentView.headerTextHeight;
},
* Determines the height of the calendar header in which appointments can be positioned.
* @return {Number} height in pixels of the appointment header area
*/
getAppointmentHeaderheight : function()
{
return this.header.getHeight() - this.parentView.headerTextHeight;
},
* Tests if the date range should be laid out in the header, which is when a range spans 24 hours or more.
* @return {Boolean} true if the date range represents 24 hours or more, false otherwise.
*/
isHeaderRange : function(dateRange)
{
return dateRange.getDuration(Date.DAY) >= 1;
},
* Determine the Header Text which must be displayed for the given {@link Date}. If the
* available width for the header is sufficiently large (The width is greater then
* {@link Zarafa.calendar.ui.CalendarMultiView#minHeaderDayTextWidth minHeaderDayTextWidth})
* then the {@link #longDayHeaderFormat} will be used for fomatting the date. Otherwise the
* {@link #shortDayHeaderFormat} will be used.
* @param {Date} date The date for which the header title is requested
* @param {Number} width The available width for the header
* @private
*/
getDayHeaderTitle : function(date, width)
{
var dateFormat;
if (width >= this.parentView.minHeaderDayTextWidth) {
dateFormat = this.longDayHeaderFormat;
} else {
dateFormat = this.shortDayHeaderFormat;
}
return date.format(dateFormat);
},
/**
* This calculates the positions of each day which must be rendered into this view.
* This initializes the {@link #dayLayoutPositions} array containing all the positioning information.
* @return {Array} The array of {@link Zarafa.calendar.data.DayLayoutPosition dayLayoutPositions}
* @private
*/
calculateDayLayoutPositions : function()
{
var todayTime = (new Date()).clearTime().getTime();
var firstDay = this.getDateRange().getStartDate();
var numDays = this.getDateRange().getNumDays();
var headerWidth = (this.body.getWidth()-1) / numDays;
// Because of DST switches at 00:00 in Brasil, ensure
// we are using a safe time to perform the "add" action
firstDay = firstDay.clone();
firstDay.setHours(12);
// calculate header positions (left, right)
this.dayLayoutPositions = [];
for (var i = 0; i < numDays; i++) {
var date = firstDay.add(Date.DAY, i).clearTime();
var workingDay = (this.parentView.workingDays.indexOf(date.getDay()) >= 0);
this.dayLayoutPositions.push(new Zarafa.calendar.data.DayLayoutPosition({
left : Math.round(i * headerWidth),
right : Math.round((i+1) * headerWidth) + 1,
date: date, // Make sure we select the start of the day
today : (todayTime == date.getTime()),
workingDay : workingDay
}));
}
return this.dayLayoutPositions;
},
/**
* Calculate the {@link Date date} within this view based on the
* X & Y coordinates. This uses the {@link #dayLayoutPositions} to
* determine which day & time matches the XY coordinates.
*
* @param {Number} x horizontal component of the location
* @param {Number} y vertical component of the location
* @return {Date} a Date object that corresponds to the given location
* @private
*/
locationToDate : function(x, y)
{
var numDays = this.getDateRange().getNumDays();
var stripHeight = this.parentView.numHours * this.parentView.getHourHeight();
// determine the day they mouse is over (horizontal position)
var day;
if (x < this.dayLayoutPositions[0].left) {
day = 0;
} else if (x > this.dayLayoutPositions[numDays - 1].right) {
day = numDays - 1;
} else {
for (var i = 0; i < this.dayLayoutPositions.length; i++) {
if (x >= this.dayLayoutPositions[i].left && x<=this.dayLayoutPositions[i].right) {
day = i;
break;
}
}
}
// Get the start date of the visible range
var startDate = this.getDateRange().getStartDate();
// Our first action is to move the date to the correct day,
// we do this at 12:00 so we don't need to worry about the
// DST switch at 00:00
var date = startDate.clone();
date.setHours(12);
date = date.add(Date.DAY, day).clearTime();
// determine time in milliseconds (vertical position)
var time = (y / stripHeight) * Date.dayInMillis;
// In some cases, the day might not start at 00:00, this could
// occur in Brasil for example where the DST switch occurs at
// midnight. At that moment 00:00 -> 01:00 doesn't exist. We
// must compensate for this alternative start of the day by reducing
// the time offset with the minutes which we skipped at midnight.
if (time > 0) {
time -= ((date.getHours() * 60 * 60) + (date.getMinutes() * 60)) * 1000;
}
// return a new Date object with the appropriate time
return date.add(Date.MILLI, time);
},
/**
* Converts a location in page coordinates to a corresponding date.
* @param {Number} x horizontal component of the location
* @param {Number} y vertical component of the location
* @return {Date} a Date object that corresponds to the given location
*/
screenLocationToDate : function(x, y)
{
// get height / width of header's parent as that container is scrollable and
// will give proper viewable height / width for comparison
if (Zarafa.core.Util.inside(this.header.parent().getBox(), x, y)) {
return this.locationToDate(x - this.header.getX(), 0);
} else {
return this.locationToDate(x - this.body.getX(), y - this.body.getY());
}
},
/**
* Converts a location in page coordinates to a corresponding daterange.
* @param {Number} x horizontal component of the location
* @param {Number} y vertical component of the location
* @return {Zarafa.core.DateRange} A DateRange object that corresponds to the given location
*/
screenLocationToDateRange : function(x, y)
{
// get height / width of header's parent as that container is scrollable and
// will give proper viewable height / width for comparison
var date;
if (Zarafa.core.Util.inside(this.header.parent().getBox(), x, y)) {
// Both the start and dueDate need a clearTime() call, this
// is in case of DST switches for Brasil where 00:00 doesn't exist
// and clearTime() will return 01:00.
date = this.locationToDate(x - this.header.getX(), 0).clearTime();
var dueDate = date.clone();
dueDate.setHours(12);
dueDate = dueDate.add(Date.DAY, 1).clearTime();
return new Zarafa.core.DateRange({ startDate : date, dueDate : dueDate });
} else {
date = this.locationToDate(x - this.body.getX(), y - this.body.getY());
var snapSize = this.getZoomLevel() * 60 * 1000;
var snap = date.getTime() - (date.getTime() % snapSize);
return new Zarafa.core.DateRange({ startDate : new Date(snap), dueDate : new Date(snap + snapSize) });
}
},
/**
* Convenience method that maps a Date to a number representing a day column
* on the current calendar (ranging from [0..numdays-1]).
* @param {Date} date date
* @param {Number} The day number in this view.
* @private
*/
getDayColumn : function(date)
{
var start = this.getDateRange().getStartDate();
// We use the Ext clearTime() extension of Date() to account for
// differences in DST. We pass true to get a clone of the passed
// date, so we don't overwrite the original date.
start = start.clearTime(true);
date = date.clearTime(true);
return Math.floor(Date.diff(Date.DAY, date, start));
},
/**
* Calculate the vertical position of the provided date on a given day column.
* @param {Date} date The date to calculate
* @private
*/
getDateVerticalPosition : function(date)
{
var timeZoneOffset = date.getTimezoneOffset() * 60 * 1000;
return ((date.getTime() - timeZoneOffset) % Date.dayInMillis) / Date.dayInMillis;
},
/**
* Calculate the height of a time duration on a day column
* @param {Number} time The duration
* @private
*/
getRangeVerticalHeight : function(daterange)
{
// This is DST safe, as we render 24 hours regardless of the DST which might
// occur on this particular day.
var stripHeight = this.parentView.numHours * this.parentView.getHourHeight();
var duration = daterange.getDuration();
duration += Date.getDSTDiff(daterange.getStartDate(), daterange.getDueDate());
return (duration * stripHeight) / Date.dayInMillis;
},
/**
* Converts a date range ([startDate, dueDate>) to zero or more (left, right, top, bottom) bounds objects.
* This method is used to lay out appointments (and proxies) on the calendar body.
* @param {Zarafa.core.DateRange} dateRange date range
* @param {Number} column (optional) when several appointments are overlapping a column may be assigned
* @param {Number} columnCount (optional) the number of overlapping appointments in an overlap dependency graph
* @param {Boolean} useMargin (optional) True to apply a right margin to the appointments to prevent them from
* filling up the entire width of a daybox.
* @return {Array} Array of {@link Zarafa.calendar.data.AppointmentBounds Bounds} which are used
* to position all the body elements.
*/
dateRangeToBodyBounds : function(dateRange, column, columnCount, useMargin)
{
var ret = [];
var numDays = this.dayLayoutPositions.length;
var stripHeight = this.parentView.numHours * this.parentView.getHourHeight();
var leftMargin = useMargin ? this.appointmentBodyLeftMargin : 0;
var rightMargin = useMargin ? this.appointmentBodyRightMargin : 0;
// TODO
var startDate = dateRange.getStartDate();
var dueDate = dateRange.getDueDate();
// Apply default values
column = column || 0;
columnCount = columnCount || 1;
// if dueDate>=startDate, return false. We don't swap the dates here to force a valid
// bounds array because that should be handled in the caller
if (dueDate.getTime() <= startDate.getTime()) {
return [];
}
var startDay = this.getDayColumn(startDate);
var dueDay = this.getDayColumn(dueDate);
// the date is outside the calendar range, return empty bounds array.
// IMPORTANT: This checks only if _both_ start and due date are out of bounds.
// It could still happen that the startDate is out of bounds, while the dueDate
// is positioned within the view (or vice versa). In both cases we will create
// a bound for the appointment, we will check what the exact case is later
// during the construction of the Zarafa.calendar.data.AppointmentBounds objects.
if (dueDay < 0 || startDay >= numDays) {
return [];
}
var startDatePos = Math.floor(this.getDateVerticalPosition(startDate) * stripHeight);
var dueDatePos = Math.floor(this.getDateVerticalPosition(dueDate) * stripHeight);
// move the top of each box one pixel up. This is because we want both the top line and bottom line of
// each appointment box to line up over the horizontal hour lines
startDatePos--;
if (startDay == dueDay)
{
// The startDay is the same as the dueDay, we already checked that
// both values fall within the current view boundaries, so all that
// is left to be done is creating a single Zarafa.calendar.data.AppointmentBounds
// object which is both our first, as well as the lastBox.
// Calculate the columnWidth, this is the total available space within the dayColumn
// which is usable for this appointment. The width depends on a few factors:
// 1) The width of the dayColumn itself
// 2) The margins which are applied to the dayColumn (both left, and right).
// 3) The number of appointments which overlap, each appointment will then be positioned
// into a subcolumn inside the dayColumn. The number of these columns is indicated by
// the columnCount.
var columnWidth = (this.dayLayoutPositions[startDay].right - this.dayLayoutPositions[startDay].left - 1 - rightMargin - leftMargin) / columnCount;
// Calculate the left position of the appointment, this is the position
// of the dayColumn plus the leftMargin, and the offset depending on the number
// of subcolumns.
var left = this.dayLayoutPositions[startDay].left + (columnWidth * column) + leftMargin + 1;
ret.push(new Zarafa.calendar.data.AppointmentBounds({
left : Math.round(left),
right : Math.round(left + columnWidth),
top : startDatePos,
bottom : dueDatePos,
firstBox : true,
lastBox : true
}));
}
else
{
// add a bounds object for the first day.
if (startDay >= 0)
{
var columnWidth = (this.dayLayoutPositions[startDay].right - this.dayLayoutPositions[startDay].left - 1 - rightMargin - leftMargin) / columnCount;
var left = this.dayLayoutPositions[startDay].left + (columnWidth * column) + leftMargin;
ret.push(new Zarafa.calendar.data.AppointmentBounds({
left : Math.round(left),
right : Math.round(left + columnWidth),
top : startDatePos,
bottom : stripHeight,
firstBox : true
}));
}
// for every day that is spanned completely by the appointment, return a bounds object that spans
// that day strip
for (var i = Math.max(startDay + 1, 0); i <= Math.min(dueDay - 1, numDays - 1); i++)
{
var columnWidth = (this.dayLayoutPositions[i].right - this.dayLayoutPositions[i].left - 1 - rightMargin - leftMargin) / columnCount;
var left = this.dayLayoutPositions[i].left + (columnWidth * column) + leftMargin;
ret.push(new Zarafa.calendar.data.AppointmentBounds({
left : Math.round(left),
right : Math.round(left + columnWidth),
top : -1,
bottom : stripHeight
}));
}
// add a bounds object for the last day. If the appointment starts and ends on the same day
// this will be the only item in the bounds array
// The check 'dueDatePos>0' handles a corner case where an appointment is exactly 24 hours long
// (even though this shouldn't be displayed in the body anyway).
if (dueDay < numDays && dueDatePos > 0)
{
var columnWidth = (this.dayLayoutPositions[dueDay].right - this.dayLayoutPositions[dueDay].left - 1 - rightMargin - leftMargin) / columnCount;
var left = this.dayLayoutPositions[dueDay].left + (columnWidth * column) + leftMargin;
// This is the last bound for the appointment which represents the
// due date of the appointment. Note that this is not automatically the
// case since the appointments due date might fall _after_ the last visible
// date in our view.
ret.push(new Zarafa.calendar.data.AppointmentBounds({
left : Math.round(left),
right : Math.round(left + columnWidth),
top : -1,
bottom : dueDatePos,
lastBox : true
}));
}
}
return ret;
},
* Converts a date range ([startDate, dueDate>) a (left, right, top, bottom) box.
* This method is used to lay out appointments (and proxies) on the calendar header.
* @param {Zarafa.core.DateRange} dateRange date range
* @param {Number} column (optional) when several appointments are overlapping a column may be assigned
* @param {Number} columnCount (optional) the number of overlapping appointments in an overlap dependency graph
* @param {Boolean} useMargin (optional) True to apply margins to the appointments to prevent them
* from filling up the entire width of the header (This applies {@link #appointmentHeaderLeftMargin} and
* {@link #appointmentHeaderRightMargin}).
* @return {Array} Array of {@link Zarafa.calendar.data.AppointmentBounds Bounds} which are used
* to position the header element.
*/
dateRangeToHeaderBounds : function(dateRange, row, rowCount, useMargin)
{
var numDays = this.dayLayoutPositions.length;
var leftMargin = useMargin ? this.appointmentHeaderLeftMargin :0;
var rightMargin = useMargin ? this.appointmentHeaderRightMargin :0;
var top = this.parentView.headerTextHeight;
var startDate = dateRange.getStartDate();
var dueDate = dateRange.getDueDate();
// TODO
var startDay = this.getDayColumn(startDate);
var dueDay = this.getDayColumn(dueDate);
// Apply default values
row = row || 0;
rowCount = rowCount || this.rowCount;
// Handles a corner case where the appointment ends at exactly 00:00 the next day,
// which means that the appointment is actually the end of the previous day. Note that
// we cannot use clearTime() here in case of DST switches in Brasil where 00:00 doesn't
// exist and clearTime() will return 01:00
if (dueDate.clearTime(true).getTime() === dueDate.getTime()) {
dueDay--;
}
// the date is outside the calendar range, return empty bounds array.
if (dueDay < 0 || startDay >= numDays) {
return [];
}
// We now have 4 possible cases:
// 1) The start date does not fall within the visible range,
// which means that this isn't the firstBox, and the leftMargin
// should not be applied.
// 2) The start and due date fall within the range, so the box
// is the firstBox and lastBox, and all margins must be applied.
// 3) The due date does not fall within the visible range,
// which means that this isn't the lastBox, and the right
// Margin should not be applied.
// 4) The start and due data both fall outside of the range, so the box
// is actually a middleBox, and none of the margins must be applied.
if (startDay < 0 && dueDay >= numDays) {
// case (4)
// This is a middleBox which is drawn, both the firstBox as lastBox fall outside of the range.
// Our left position is the most-left position (the first dayColumn), the right position is the
// most-right position (the last dayColumn). This will ensure that the appointment will stretch
// the entire length of all columns.
return new Zarafa.calendar.data.AppointmentBounds({
left : this.dayLayoutPositions[0].left,
right : this.dayLayoutPositions[numDays - 1].right,
top : top + row * this.parentView.headerItemHeight,
bottom : top + (row + rowCount) * this.parentView.headerItemHeight
});
} else if (startDay < 0) {
// case (1)
// This is the lastBox which is drawn, but not the firstBox (the firstBox is out of range).
// Our left position is the most-left position (the first dayColumn). This will ensure that
// the appointment will stretch from the first visible day until the due date.
return new Zarafa.calendar.data.AppointmentBounds({
left : this.dayLayoutPositions[0].left,
right : this.dayLayoutPositions[dueDay].right - rightMargin,
top : top + row * this.parentView.headerItemHeight,
bottom : top + (row + rowCount) * this.parentView.headerItemHeight,
lastBox : true
});
} else if (dueDay >= numDays) {
// case (3)
// This is the firstBox which is drawn, but not the lastBox (the lastBox is out of range).
// Our right position is the most-right position (the last dayColumn). This will ensure that
// the appointment will stretch from the start date to the last visible day.
return new Zarafa.calendar.data.AppointmentBounds({
left : this.dayLayoutPositions[startDay].left + leftMargin,
right : this.dayLayoutPositions[numDays - 1].right,
top : top + row * this.parentView.headerItemHeight,
bottom : top + (row + rowCount) * this.parentView.headerItemHeight,
firstBox : true
});
} else {
// case (2)
// This is both the firstBox as well as the lastBox (everythhing is within the range).
// The left and right position is read from the positions from the correct dayColumns
// with padding applied.
return new Zarafa.calendar.data.AppointmentBounds({
left : this.dayLayoutPositions[startDay].left + leftMargin,
right : this.dayLayoutPositions[dueDay].right - rightMargin,
top : top + row * this.parentView.headerItemHeight,
bottom : top + (row + rowCount) * this.parentView.headerItemHeight,
firstBox : true,
lastBox : true
});
}
},
/**
* Splits a set of {@link Zarafa.calendar.ui.Appointment Appointment} objects into overlapping clusters.
* @param {Zarafa.calendar.ui.Appointment|Array} appointment The appointment list
* @return {Zarafa.calendar.ui.Appointment|Array} clusters The matrix of appointments
*/
getAppointmentClusters : function(appointments)
{
// sort appointments by start date
appointments.sort(this.appointmentCompare);
// find connected graphs (clusters) of appointments and determine the maximum column number among them
// TODO clean up this code
var cluster = [], clusters = [];
var clusterStartDate = 0, clusterDueDate = 0;
for (var i=0, appointment; appointment=appointments[i]; i++) {
var startDate = appointment.getDateRange().getStartTime();
var dueDate = appointment.getAdjustedDateRange().getDueTime();
if (cluster.length === 0) {
clusterStartDate = startDate;
clusterDueDate = dueDate;
cluster.push(appointment);
} else if (startDate < clusterDueDate) {
clusterDueDate = Math.max(dueDate, clusterDueDate);
cluster.push(appointment);
} else {
clusters.push(cluster);
// start new cluster
cluster = [ appointment ];
clusterStartDate = startDate;
clusterDueDate = dueDate;
}
}
if (cluster.length > 0) {
clusters.push(cluster);
}
return clusters;
},
/**
* Appointments that span less than 24 hours are laid out in the body of the view. This method calculates
* how these appointments overlap in time and assigns slots (columns) to each appointment.
* <p>
* The appointments are first split up into clusters of overlapping appointments. Each cluster is then
* treated individually, using a simple greedy coloring algorithm. The number of required slots for each
* cluster is added to each appointment in the form of a 'slotCount' property. This property is then used
* to scale the appointments properly in the layout phase.
*
* @return {Number} the number of appointment rows needed to accommodate all appointments
* @private
*/
calculateBodyOverlaps : function()
{
// Make a list of appointments that are displayed on the calendar body
var bodyAppointments = [];
Ext.each(this.appointments, function(appointment) {
if (!this.isHeaderRange(appointment.getDateRange())) {
bodyAppointments.push(appointment);
}
}, this);
var clusters = this.getAppointmentClusters(bodyAppointments);
Ext.each(clusters, this.doGreedyColoring, this);
},
* Appointments that span over 24 hours are laid out in the header of the view. This method calculates
* how these appointments overlap in time and assigns slots (rows) to each appointment. The same greedy
* coloring algorithm is used as in calculateBodyOverlaps().
* @private
*/
calculateHeaderOverlaps : function()
{
// Make a list of appointments that are displayed in the calendar header area
var headerAppointments = [];
Ext.each(this.appointments, function(appointment) {
if (this.isHeaderRange(appointment.getDateRange())) {
headerAppointments.push(appointment);
}
}, this);
this.doGreedyColoring(headerAppointments, true);
this.rowCount = (headerAppointments.length>0) ? headerAppointments[0].slotCount : 0;
},
/**
* Called by the {@link #parentView} when the {@link Zarafa.core.data.IPMStore#load load} event
* has been fired from the appointment {@link Zarafa.calendar.ui.CalendarMultiView#store store}.
* After all appointments have been added to the calendar, the {@link #calculateBodyOverlaps body overlaps}
* and {@link #calculateHeaderOverlaps header overlaps} will be recalculated.
* @param {Zarafa.core.data.IPMStore} store store that fired the event.
* @param {Zarafa.core.data.IPMRecord[]} records loaded record set
* @param {Object} options the options (parameters) with which the load was invoked.
*/
onAppointmentsLoad : function(store, records, options)
{
Zarafa.calendar.ui.AbstractCalendarDaysView.superclass.onAppointmentsLoad.apply(this, arguments);
// Appointments have been loaded, we must recalculate the overlaps in the body and header
this.calculateBodyOverlaps();
this.calculateHeaderOverlaps();
},
/**
* Adds a new appointment to the view.
* Depending if it is an allday appointment, the {@link #calculateBodyOverlaps body overlaps}
* or {@link #calculateHeaderOverlaps header overlaps} will be recalculated.
* @param {Ext.data.Record} record a record with the appointment data
* @param {Boolean} layout (optional) if true layout() will be called after the appointment was added. Defaults to true.
* @return {Boolean} True if an appointment was added, false otherwise.
*/
addAppointment : function(record, layout)
{
var added = Zarafa.calendar.ui.AbstractCalendarDaysView.superclass.addAppointment.apply(this, arguments);
if ( !added ){
return false;
}
if (record.get('alldayevent')) {
this.calculateHeaderOverlaps();
} else {
this.calculateBodyOverlaps();
}
return true;
},
/**
* Removes an appointment from the view.
* Depending if it is an allday appointment, the {@link #calculateBodyOverlaps body overlaps}
* or {@link #calculateHeaderOverlaps header overlaps} will be recalculated.
* @param {Ext.data.Record} record appointment record
* @param {Boolean} layout (optional) if true layout() will be called after the appointment was added. Defaults to true.
* @return {Boolean} true if an appointment was removed, false otherwise (the appointment was not found in this view)
*/
removeAppointment : function(record, layout)
{
Zarafa.calendar.ui.AbstractCalendarDaysView.superclass.removeAppointment.apply(this, arguments);
if (record.get('alldayevent')) {
this.calculateHeaderOverlaps();
} else {
this.calculateBodyOverlaps();
}
},
/**
* Called before the calendar will be layed out.
* This will recalculate the {@link #calculateBodyOverlaps body} and {@link #calculateHeaderOverlaps header overlaps}.
* @protected.
*/
onBeforeLayout : function()
{
Zarafa.calendar.ui.AbstractCalendarDaysView.superclass.onBeforeLayout.apply(this, arguments);
this.calculateBodyOverlaps();
this.calculateHeaderOverlaps();
}
});