@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
1,388 lines (1,198 loc) • 185 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
//Provides control sap.m.PlanningCalendar.
sap.ui.define([
"sap/base/i18n/Formatting",
"sap/base/i18n/Localization",
'sap/m/delegate/DateNavigation',
'sap/ui/core/Control',
'sap/ui/base/ManagedObjectObserver',
"sap/ui/core/Lib",
'sap/ui/unified/library',
'sap/ui/unified/calendar/CalendarUtils',
'sap/ui/unified/calendar/CalendarDate',
'sap/ui/unified/calendar/DatesRow',
'sap/ui/unified/calendar/OneMonthDatesRow',
'sap/ui/unified/calendar/MonthsRow',
'sap/ui/unified/calendar/TimesRow',
'sap/ui/unified/calendar/WeeksRow',
'sap/ui/unified/DateRange',
'sap/ui/unified/DateTypeRange',
'sap/ui/unified/CalendarAppointment',
'sap/ui/unified/CalendarRow',
'sap/ui/unified/CalendarRowRenderer',
'sap/ui/Device',
'sap/ui/core/Element',
'sap/ui/core/Renderer',
'sap/ui/core/ResizeHandler',
'sap/ui/core/InvisibleText',
'sap/ui/core/dnd/DragInfo',
'sap/ui/core/dnd/DropInfo',
'sap/ui/core/dnd/DragDropInfo',
'sap/ui/core/format/DateFormat',
'sap/base/i18n/date/CalendarType',
'sap/base/i18n/date/CalendarWeekNumbering',
'sap/ui/core/date/CalendarUtils',
'sap/ui/core/Locale',
"sap/ui/core/date/UI5Date",
"sap/ui/events/KeyCodes",
'sap/m/Avatar',
'sap/m/Toolbar',
'sap/m/Table',
'sap/m/Column',
'sap/m/ColumnListItem',
'sap/m/ColumnListItemRenderer',
'sap/m/SegmentedButtonItem',
'sap/m/StandardListItem',
'sap/m/PlanningCalendarHeader',
'sap/m/PlanningCalendarRenderer',
'sap/m/PlanningCalendarView',
'sap/m/CheckBox',
'sap/m/library',
"sap/base/util/deepEqual",
"sap/base/Log",
"sap/m/List",
"sap/ui/thirdparty/jquery",
// jQuery Plugin "control"
"sap/ui/dom/jquery/control"
], function(
Formatting,
Localization,
DateNavigation,
Control,
ManagedObjectObserver,
Library,
unifiedLibrary,
CalendarUtils,
CalendarDate,
DatesRow,
OneMonthDatesRow,
MonthsRow,
TimesRow,
WeeksRow,
DateRange,
DateTypeRange,
CalendarAppointment,
CalendarRow,
CalendarRowRenderer,
Device,
Element,
Renderer,
ResizeHandler,
InvisibleText,
DragInfo,
DropInfo,
DragDropInfo,
DateFormat,
_CalendarType, // indirectly used for properties `primaryCalendarType` and `secondaryCalendarType`
_CalendarWeekNumbering, // indirectly required for property `calendarWeekNumbering`
CalendarDateUtils,
Locale,
UI5Date,
KeyCodes,
Avatar,
Toolbar,
Table,
Column,
ColumnListItem,
ColumnListItemRenderer,
SegmentedButtonItem,
StandardListItem,
PlanningCalendarHeader,
PlanningCalendarRenderer,
PlanningCalendarView,
CheckBox,
library,
deepEqual,
Log,
List,
jQuery
) {
"use strict";
// shortcut for sap.m.Sticky
var Sticky = library.Sticky;
// shortcut for sap.ui.unified.CalendarDayType
var CalendarDayType = unifiedLibrary.CalendarDayType;
// shortcut for sap.m.ListMode
var ListMode = library.ListMode;
// shortcut for sap.m.ToolbarDesign
var ToolbarDesign = library.ToolbarDesign;
// shortcut for sap.m.PlanningCalendarBuiltInView
var PlanningCalendarBuiltInView = library.PlanningCalendarBuiltInView;
// shortcut for sap.m.ScreenSize
var ScreenSize = library.ScreenSize;
// shortcut for sap.ui.unified.CalendarAppointmentVisualization
var CalendarAppointmentVisualization = unifiedLibrary.CalendarAppointmentVisualization;
// shortcut for sap.ui.unified.GroupAppointmentsMode
var GroupAppointmentsMode = unifiedLibrary.GroupAppointmentsMode;
// shortcut for sap.ui.unified.CalendarIntervalType
var CalendarIntervalType = unifiedLibrary.CalendarIntervalType;
// shortcut for sap.ui.unified.CalendarAppointmentHeight
var CalendarAppointmentHeight = unifiedLibrary.CalendarAppointmentHeight;
// shortcut for sap.ui.unified.CalendarAppointmentRoundWidth
var CalendarAppointmentRoundWidth = unifiedLibrary.CalendarAppointmentRoundWidth;
var AvatarShape = library.AvatarShape;
var DRAG_DROP_CONFIG_NAME = "DragDropConfig";
var RESIZE_CONFIG_NAME = "ResizeConfig";
var CREATE_CONFIG_NAME = "CreateConfig";
var LISTITEM_SUFFIX = "-CLI";
/**
* Constructor for a new <code>PlanningCalendar</code>.
*
* @param {string} [sID] ID for the new control, generated automatically if no ID is given
* @param {object} [mSettings] Initial settings for the new control
*
* @class
* Displays rows with appointments for different entities (such as persons or teams) for the selected time interval.
*
* <h3>Overview</h3>
*
* You can use the <code>PlanningCalendar</code> to represent a calendar containing multiple rows with
* appointments, where each row represents a different person.
*
* You can configure different time-interval views that the user can switch between, such as hours or days, and even
* a whole week/month. The available navigation allows the user to select a specific interval using a picker, or
* move to the previous/next interval using arrows.
*
* <b>Note:</b> The application developer should add dependency to <code>sap.ui.unified</code> library
* on application level to ensure that the library is loaded before the module dependencies will be required.
* The <code>PlanningCalendar</code> uses parts of the <code>sap.ui.unified</code> library.
* This library will be loaded after the <code>PlanningCalendar</code>, if it wasn't loaded first.
* This could lead to CSP compliance issues and adds an additional waiting time when a <code>PlanningCalendar</code> is used for the first time.
* To prevent this, apps that use the <code>PlanningCalendar</code> should also load the
* <code>sap.ui.unified</code> library in advance.
*
* <h3>Usage</h3>
*
* The <code>PlanningCalendar</code> has the following structure from top to bottom:
*
* <ul>
* <li>A toolbar where you can add your own buttons or other controls using the <code>toolbarContent</code> aggregation.</li>
* <li>A header containing a drop-down menu for selecting the {@link sap.m.PlanningCalendarView PlanningCalendarViews},
* and navigation for moving through the intervals using arrows or selecting a specific interval with a picker.
* Custom views can be configured using the <code>views</code> aggregation. If not configured, the following set of default
* built-in views is available - Hours, Days, 1 Week, 1 Month, and Months. Setting a custom view(s) replaces the built-in ones.</li>
* <li>The rows of the <code>PlanningCalendar</code> that contain the assigned appointments.
* They can be configured with the <code>rows</code> aggregation, which is of type
* {@link sap.m.PlanningCalendarRow PlanningCalendarRow}.</li>
* </ul>
*
* Since 1.48 the empty space in the cell that is below an appointment can be removed by adding
* the <code>sapUiCalendarAppFitVertically</code> CSS class to the <code>PlanningCalendar</code>.
* Please note that it should be used only for a <code>PlanningCalendar</code> with one appointment per day
* for a row that doesn't have interval headers set.
*
* Since 1.44 alternating row colors can be suppressed by adding the <code>sapMPlanCalSuppressAlternatingRowColors</code>
* CSS class to the <code>PlanningCalendar</code>.
*
* <h3>Responsive behavior</h3>
*
* You can define the number of displayed intervals based on the size of the <code>PlanningCalendar</code> using the
* {@link sap.m.PlanningCalendarView PlanningCalendarView}'s properties.
*
* @extends sap.ui.core.Control
* @version 1.146.0
*
* @constructor
* @public
* @since 1.34
* @alias sap.m.PlanningCalendar
* @see {@link fiori:https://experience.sap.com/fiori-design-web/planning-calendar/ Planning Calendar}
*/
var PlanningCalendar = Control.extend("sap.m.PlanningCalendar", /** @lends sap.m.PlanningCalendar.prototype */ {
metadata : {
library : "sap.m",
properties : {
/**
* Determines the start date of the row, as a UI5Date or JavaScript Date object. The current date is used as default.
*/
startDate : {type : "object", group : "Data"},
/**
* Defines the key of the <code>PlanningCalendarView</code> used for the output.
*
* <b>Note:</b> The default value is set <code>Hour</code>. If you are using your own views, the keys of these
* views should be used instead.
*/
viewKey : {type : "string", group : "Appearance", defaultValue : CalendarIntervalType.Hour},
/**
* Determines whether only a single row can be selected.
*/
singleSelection : {type : "boolean", group : "Misc", defaultValue : true},
/**
* Specifies the width of the <code>PlanningCalendar</code>.
*/
width : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},
/**
* Specifies the height of the <code>PlanningCalendar</code>.
* <b>Note:</b> If the set height is less than the displayed content, it will not be applied
*/
height : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},
/**
* Determines whether the assigned interval headers are displayed. You can assign them using the
* <code>intervalHeaders</code> aggregation of the {@link sap.m.PlanningCalendarRow PlanningCalendarRow}.
*
* <b>Note:</b> If you set both <code>showIntervalHeaders</code> and <code>showEmptyIntervalHeaders</code>
* properties to <code>true</code>, the space (at the top of the intervals) where the assigned interval
* headers appear, will remain visible even if no interval headers are assigned.
*/
showIntervalHeaders : {type : "boolean", group : "Appearance", defaultValue : true},
/**
* Determines whether the space (at the top of the intervals), where the assigned interval headers appear, should remain
* visible even when no interval headers are present in the visible time frame. If set to <code>false</code>, this
* space would collapse/disappear when no interval headers are assigned.
*
* <b>Note:</b> This property takes effect, only if <code>showIntervalHeaders</code> is also set to <code>true</code>.
* @since 1.38.0
*/
showEmptyIntervalHeaders : {type : "boolean", group : "Appearance", defaultValue : true},
/**
* Determines whether the column containing the headers of the {@link sap.m.PlanningCalendarRow PlanningCalendarRows}
* is displayed.
*/
showRowHeaders : {type : "boolean", group : "Appearance", defaultValue : true},
/**
* Defines the text that is displayed when no {@link sap.m.PlanningCalendarRow PlanningCalendarRows} are assigned.
* <b>Note:</b> If both <code>noDataText</code> property and <code>noData</code> aggregation are provided, the <code>noData</code> aggregation takes priority.
* If the <code>noData</code> aggregation is undefined or set to null, the <code>noDataText</code> property is used instead.
*/
noDataText : {type : "string", group : "Misc", defaultValue : null},
/**
* Defines the mode in which the overlapping appointments are displayed.
*
* <b>Note:</b> This property takes effect, only if the <code>intervalType</code> of the current calendar view
* is set to <code>sap.ui.unified.CalendarIntervalType.Month</code>. On phone devices this property is ignored,
* and the default value is applied.
* @since 1.48.0
*/
groupAppointmentsMode : {type : "sap.ui.unified.GroupAppointmentsMode", group : "Appearance", defaultValue : GroupAppointmentsMode.Collapsed},
/**
* Determines whether the appointments that have only title without text are rendered with smaller height.
*
* <b>Note:</b> On phone devices this property is ignored, appointments are always rendered in full height
* to facilitate touching.
* @deprecated Since version 1.119. Please use the <code>appointmentHeight</code> with value "Automatic" property instead.
* @since 1.38.0
*/
appointmentsReducedHeight : {type : "boolean", group : "Appearance", defaultValue : false, deprecated: true},
/**
* Determines the different possible sizes for appointments.
* @since 1.81.0
*/
appointmentHeight: { type: "sap.ui.unified.CalendarAppointmentHeight", group: "Appearance", defaultValue: CalendarAppointmentHeight.Regular },
/**
* Defines rounding of the width <code>CalendarAppoinment</code>
* <b>Note:</b> This property is applied, when the calendar interval type is Day and the view shows more than 20 days
* @since 1.81.0
*/
appointmentRoundWidth: { type: "sap.ui.unified.CalendarAppointmentRoundWidth", group: "Appearance", defaultValue: CalendarAppointmentRoundWidth.None},
/**
* Determines how the appointments are visualized depending on the used theme.
* @since 1.40.0
*/
appointmentsVisualization : {type : "sap.ui.unified.CalendarAppointmentVisualization", group : "Appearance", defaultValue : CalendarAppointmentVisualization.Standard},
/**
* Defines the minimum date that can be displayed and selected in the <code>PlanningCalendar</code>.
* This must be a UI5Date or JavaScript Date object.
*
* <b>Note:</b> If the <code>minDate</code> is set to be after the current <code>maxDate</code>,
* the <code>maxDate</code> is set to the last date of the month in which the <code>minDate</code> belongs.
* @since 1.38.0
*/
minDate : {type : "object", group : "Misc", defaultValue : null},
/**
* Defines the maximum date that can be displayed and selected in the <code>PlanningCalendar</code>.
* This must be a UI5Date or JavaScript Date object.
*
* <b>Note:</b> If the <code>maxDate</code> is set to be before the current <code>minDate</code>,
* the <code>minDate</code> is set to the first date of the month in which the <code>maxDate</code> belongs.
* @since 1.38.0
*/
maxDate : {type : "object", group : "Misc", defaultValue : null},
/**
* Determines whether the day names are displayed in a separate line or inside the single days.
* @since 1.50
*/
showDayNamesLine : {type : "boolean", group : "Appearance", defaultValue : false},
/**
* Determines if the week numbers are displayed.
* @since 1.52
*/
showWeekNumbers : {type : "boolean", group : "Appearance", defaultValue : false},
/**
* Defines the list of predefined views as an array.
* The views should be specified by their keys.
*
* The default predefined views and their keys are available at
* {@link sap.m.PlanningCalendarBuiltInView}.
*
* <b>Note:</b> If set, all specified views will be displayed along
* with any custom views (if available). If not set and no custom
* views are available, all default views will be displayed.
* If not set and there are any custom views available, only the
* custom views will be displayed.
* @since 1.50
*/
builtInViews : {type : "string[]", group : "Appearance", defaultValue : []},
/**
* Determines whether the header area will remain visible (fixed on top) when the rest of the content is scrolled out of view.
*
* The sticky header behavior is automatically disabled on phones in landscape mode for better visibility of the content.
*
* <b>Note:</b> There is limited browser support, hence the API is in experimental state.
* Browsers that currently support this feature are Chrome (desktop and mobile), Safari (desktop and mobile) and Edge.
*
* There are also some known issues with respect to the scrolling behavior and focus handling. A few are given below:
*
* When the PlanningCalendar is placed in certain layout containers, for example the <code>GridLayout</code> control,
* the column headers do not fix at the top of the viewport. Similar behavior is also observed with the <code>ObjectPage</code> control.
*
* This API should not be used in production environment.
*
*<b>Note:</b> The <code>stickyHeader</code> of the <code>PlanningCalendar</code> uses the <code>sticky</code> property of <code>sap.m.Table</code>.
* Therefore, all features and restrictions of the property in <code>sap.m.Table</code> apply to the <code>PlanningCalendar</code> as well.
* @since 1.54
*/
stickyHeader : {type : "boolean", group : "Appearance", defaultValue : false},
/**
* If set, the first day of the displayed week is this day. Valid values are 0 to 6 starting on Sunday.
* If there is no valid value set, the default of the used locale is used.
*
* Note: this property will only have effect in the weekly – based views of the PlanningCalendar – Week view,
* and OneMonth view (on small devices).
*
* @since 1.94
*/
firstDayOfWeek : {type : "int", group : "Appearance", defaultValue : -1},
/**
* If set, the calendar week numbering is used for display.
* If not set, the calendar week numbering of the global configuration is used.
* @since 1.110.0
*/
calendarWeekNumbering : { type : "sap.base.i18n.date.CalendarWeekNumbering", group : "Appearance", defaultValue: null},
/**
* If set, the calendar type is used for display.
* If not set, the calendar type of the global configuration is used.
* @since 1.108.0
*/
primaryCalendarType : {type : "sap.base.i18n.date.CalendarType", group : "Appearance"},
/**
* If set, the days are also represented in this calendar type.
* If not set, the dates are only represented in the primary calendar type.
* Note: The second calendar type won't be represented in the DOM when this property is not set explicitly.
* @since 1.109.0
*/
secondaryCalendarType : {type : "sap.base.i18n.date.CalendarType", group : "Appearance"},
/**
* Determines whether the selection of multiple appointments is enabled.
*
* Note: selection of multiple appointments is possible using CTRL key regardless of the value of this property.
*
* @since 1.97
*/
multipleAppointmentsSelection : {type : "boolean", group : "Data", defaultValue : false},
/**
* Defines the shape of the <code>Avatar</code>.
*/
iconShape: {type: "sap.m.AvatarShape", group: "Appearance", defaultValue: AvatarShape.Circle}
},
aggregations : {
/**
* Rows of the <code>PlanningCalendar</code>.
*/
rows : {type : "sap.m.PlanningCalendarRow", multiple : true, singularName : "row"},
/**
* Views of the <code>PlanningCalendar</code>.
*
* <b>Note:</b> If not set, all the default views are available. Their keys are defined in
* {@link sap.ui.unified.CalendarIntervalType}.
*/
views : {type : "sap.m.PlanningCalendarView", multiple : true, singularName : "view"},
/**
* Special days in the header calendar visualized as date range with a type.
*
* <b>Note:</b> In case there are multiple <code>sap.ui.unified.DateTypeRange</code> instances given for a single date,
* only the first <code>sap.ui.unified.DateTypeRange</code> instance will be used.
* For example, using the following sample, the 1st of November will be displayed as a working day of type "Type10":
*
*
* <pre>
* new DateTypeRange({
* startDate: UI5Date.getInstance(2023, 10, 1),
* type: CalendarDayType.Type10,
* }),
* new DateTypeRange({
* startDate: UI5Date.getInstance(2023, 10, 1),
* type: CalendarDayType.NonWorking
* })
* </pre>
*
* If you want the first of November to be displayed as a non-working day and also as "Type10," the following should be done:
* <pre>
* new DateTypeRange({
* startDate: UI5Date.getInstance(2023, 10, 1),
* type: CalendarDayType.Type10,
* secondaryType: CalendarDayType.NonWorking
* })
* </pre>
*
* You can use only one of the following types for a given date: <code>sap.ui.unified.CalendarDayType.NonWorking</code>,
* <code>sap.ui.unified.CalendarDayType.Working</code> or <code>sap.ui.unified.CalendarDayType.None</code>.
* Assigning more than one of these values in combination for the same date will lead to unpredictable results.
*
*/
specialDates : {type : "sap.ui.unified.DateTypeRange", multiple : true, singularName : "specialDate"},
/**
* The content of the toolbar.
*/
toolbarContent : {
type : "sap.ui.core.Control",
multiple : true,
singularName : "toolbarContent",
forwarding : {
getter : "_getHeader",
aggregation : "actions"
}
},
/**
* Hidden, for internal use only.
*/
table : {type : "sap.m.Table", multiple : false, visibility : "hidden"},
/**
* Hidden, for internal use only.
*/
header : {type : "sap.ui.core.Control", multiple : false, visibility : "hidden"},
/**
* Defines the custom visualization if there is no data available.
* <b>Note:</b> If both <code>noDataText</code> property and <code>noData</code> aggregation are provided, the <code>noData</code> aggregation takes priority.
* If the <code>noData</code> aggregation is undefined or set to null, the <code>noDataText</code> property is used instead.
* @since 1.125.0
*/
noData : {type: "sap.ui.core.Control", multiple: false, altTypes: ["string"], forwarding: {
idSuffix: "-Table",
aggregation: "noData"
}}
},
associations: {
/**
* Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledby).
* @since 1.40.0
*/
ariaLabelledBy: { type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy" },
/**
* Association to the <code>CalendarLegend</code> explaining the colors of the <code>Appointments</code>.
*
* <b>Note:</b> The legend does not have to be rendered but must exist, and all required types must be assigned.
* @since 1.40.0
*/
legend: { type: "sap.ui.unified.CalendarLegend", multiple: false}
},
events : {
/**
* Fired if an appointment is selected.
*/
appointmentSelect : {
parameters : {
/**
* The selected appointment.
*/
appointment : {type : "sap.ui.unified.CalendarAppointment"},
/**
* The selected appointments in case a group appointment is selected.
*/
appointments : {type : "sap.ui.unified.CalendarAppointment[]"},
/**
* If set, the appointment was selected using multiple selection (e.g. Shift + single mouse click),
* meaning more than the current appointment could be selected.
*/
multiSelect : {type : "boolean"},
/**
* Gives the ID of the DOM element of the clicked appointment
* @since 1.50.0
*/
domRefId: {type: "string"}
}
},
/**
* Fired if an interval was selected in the calendar header or in the row.
*/
intervalSelect : {
parameters : {
/**
* Start date of the selected interval, as a UI5Date or JavaScript Date object.
*/
startDate : {type : "object"},
/**
* Interval end date as a UI5Date or JavaScript Date object.
* @since 1.38.0
*/
endDate : {type : "object"},
/**
* If set, the selected interval is a subinterval.
* @since 1.38.0
*/
subInterval : {type : "boolean"},
/**
* Row of the selected interval.
* @since 1.38.0
*/
row : {type : "sap.m.PlanningCalendarRow"}
}
},
/**
* Fires when row selection is changed.
*/
rowSelectionChange : {
parameters : {
/**
* Array of rows whose selection has changed.
*/
rows : {type : "sap.m.PlanningCalendarRow[]"}
}
},
/**
* Fired when the <code>startDate</code> property was changed while navigating in the <code>PlanningCalendar</code>.
* The new value can be obtained using the <code>sap.m.PlanningCalendar#getStartDate()</code> method.
* <b>Note:</b> This event is fired in case when the <code>viewKey</code> property is changed, and as a result of
* which the view requires a change in the <code>startDate</code> property.
*/
startDateChange : {},
/**
* Fired when the <code>viewKey</code> property was changed by user interaction.
*/
viewChange : {},
/**
* Fires when a row header is clicked.
* @since 1.46.0
* @deprecated Since version 1.119, replaced by <code>rowHeaderPress</code> event
*/
rowHeaderClick: {
parameters : {
/**
* The ID of the <code>PlanningCalendarRowHeader</code> of the selected appointment.
*
* <b>Note:</b> Intended to be used as an easy way to get an ID of a <code>PlanningCalendarRowHeader</code>. Do NOT use for modification.
*
* @since 1.73
*/
headerId : {type : "string"},
/**
* The row user clicked on.
*/
row : {type : "sap.m.PlanningCalendarRow"}
}
},
/**
* Fires when a row header press is triggered with mouse click, SPACE or ENTER press.
* @since 1.119.0
*/
rowHeaderPress: {
parameters : {
/**
* The ID of the <code>PlanningCalendarRowHeader</code> of the selected appointment.
*
* <b>Note:</b> Intended to be used as an easy way to get an ID of a <code>PlanningCalendarRowHeader</code>. Do NOT use for modification.
*
*/
headerId : {type : "string"},
/**
* The row user pressed.
*/
row : {type : "sap.m.PlanningCalendarRow"}
}
}
},
designtime: "sap/m/designtime/PlanningCalendar.designtime"
},
constructor: function(vId, mSettings) {
Control.prototype.constructor.apply(this, arguments);
if (typeof vId !== "string"){
mSettings = vId;
}
if (mSettings && typeof mSettings.customAppointmentsSorterCallback === "function") {
this._fnCustomSortedAppointments = mSettings.customAppointmentsSorterCallback;
}
},
renderer: PlanningCalendarRenderer
});
//List of private properties controlling different intervals
var INTERVAL_CTR_REFERENCES = ["_oTimesRow", "_oDatesRow", "_oMonthsRow", "_oWeeksRow", "_oOneMonthsRow"],
//Holds metadata of the different interval instances that should be created.
INTERVAL_METADATA = {};
INTERVAL_METADATA[CalendarIntervalType.Day] = {
sInstanceName: "_oDatesRow",
sIdSuffix: "-DatesRow",
oClass: DatesRow
};
INTERVAL_METADATA[CalendarIntervalType.Week] = {
sInstanceName: "_oWeeksRow",
sIdSuffix: "-WeeksRow",
oClass: DatesRow
};
INTERVAL_METADATA[CalendarIntervalType.OneMonth] = {
sInstanceName: "_oOneMonthsRow",
sIdSuffix: "-OneMonthsRow",
oClass: OneMonthDatesRow
};
//Defines the minimum screen width for the appointments column (it is a popin column)
var APP_COLUMN_MIN_SCREEN_WIDTH = ScreenSize.Desktop;
//All supported built-in views
var KEYS_FOR_ALL_BUILTIN_VIEWS = [
PlanningCalendarBuiltInView.Hour,
PlanningCalendarBuiltInView.Day,
PlanningCalendarBuiltInView.Month,
PlanningCalendarBuiltInView.Week,
PlanningCalendarBuiltInView.OneMonth];
var SCREEEN_BREAKPOINTS = {
PHONE: "600",
TABLET: "1024"
};
// Holds the possible values for the "_currentPicker" property in the currentPicker association of the header
var CURRENT_PICKERS = {
MONTH: "month", // represents the "month" aggregation
MONTH_PICKER: "monthPicker", // represents the "monthPicker" aggregation
YEAR_PICKER: "yearPicker", // represents the "yearPicker" aggregation
YEAR_RANGE_PICKER: "yearRangePicker" // represents the "yearRangePicker" aggregation
};
var MONTH_DELEGATE = {
onAfterRendering: function () {
this.setProperty("_currentPicker", CURRENT_PICKERS.MONTH);
this.removeDelegate(MONTH_DELEGATE);
}
};
var MONTH_PICKER_DELEGATE = {
onAfterRendering: function () {
this.setProperty("_currentPicker", CURRENT_PICKERS.MONTH_PICKER);
this.removeDelegate(MONTH_PICKER_DELEGATE);
}
};
var YEAR_PICKER_DELEGATE = {
onAfterRendering: function () {
this.setProperty("_currentPicker", CURRENT_PICKERS.YEAR_PICKER);
this.removeDelegate(YEAR_PICKER_DELEGATE);
}
};
var aIntervalRepresentatives = [
"sap.ui.unified.calendar.TimesRow",
"sap.ui.unified.calendar.DatesRow",
"sap.ui.unified.calendar.MonthsRow",
"sap.ui.unified.calendar.OneMonthDatesRow",
"sap.ui.unified.calendar.WeeksRow"
];
var CalendarHeader = Control.extend("sap.m._PlanningCalendarInternalHeader", {
metadata : {
properties : {
showWeekNumbers : {type : "boolean", group : "Appearance", defaultValue : false}
},
aggregations: {
"toolbar" : {type: "sap.m.Toolbar", multiple: false},
"allCheckBox" : {type: "sap.m.CheckBox", multiple: false}
}
},
renderer : {
apiVersion: 2,
render: function(oRm, oHeader) {
oRm.openStart("div", oHeader);
oRm.class("sapMPlanCalHead");
oRm.openEnd();
var oToolbar = oHeader.getToolbar();
if (oToolbar) {
oRm.renderControl(oToolbar);
}
var oAllCB = oHeader.getAllCheckBox();
if (oAllCB) {
oRm.renderControl(oAllCB);
}
oRm.close("div");
}
}
});
PlanningCalendar.prototype.init = function(){
this._dateNav = new DateNavigation();
this._iBreakPointTablet = Device.media._predefinedRangeSets[Device.media.RANGESETS.SAP_STANDARD_EXTENDED].points[0];
this._iBreakPointDesktop = Device.media._predefinedRangeSets[Device.media.RANGESETS.SAP_STANDARD_EXTENDED].points[1];
this._iBreakPointLargeDesktop = Device.media._predefinedRangeSets[Device.media.RANGESETS.SAP_STANDARD_EXTENDED].points[2];
if (Device.system.phone || jQuery('html').hasClass("sapUiMedia-Std-Phone")) {
this._iSize = 0;
this._iSizeScreen = 0;
} else if ((Device.system.tablet || jQuery('html').hasClass("sapUiMedia-Std-Tablet")) && !(Device.system.desktop || jQuery('html').hasClass("sapUiMedia-Std-Desktop"))){
this._iSize = 1;
this._iSizeScreen = 1;
} else {
this._iSize = 2;
this._iSizeScreen = 2;
}
this.addStyleClass("sapMSize" + this._iSize);
this.setAggregation("header", this._createHeader());
this._attachHeaderEvents();
this._oRB = Library.getResourceBundleFor("sap.m");
var sId = this.getId();
this._oIntervalTypeSelect = this._getHeader()._getOrCreateViewSwitch();
this._oIntervalTypeSelect.attachEvent("selectionChange", changeIntervalType, this);
this._oTodayButton = this._getHeader()._getTodayButton();
this._oCalendarHeader = new CalendarHeader(sId + "-CalHead", {});
this._oCalendarHeader.isRelative = this.isRelative.bind(this);
this._oCalendarHeader._getRelativeInfo = this._getRelativeInfo.bind(this);
this._oInfoToolbar = new Toolbar(sId + "-InfoToolbar", {
height: "auto",
design: ToolbarDesign.Transparent,
content: [this._oCalendarHeader, this._oTimesRow],
ariaLabelledBy: InvisibleText.getStaticId("sap.m", "PC_INTERVAL_TOOLBAR")
});
this._oInfoToolbar.addStyleClass("sapMPlanCalInfoToolbar");
var oTable = new Table(sId + "-Table", {
sticky: [], // set sticky property to an empty array this correspondents to PlanningCalendar stickyHeader = false
infoToolbar: this._oInfoToolbar,
mode: ListMode.SingleSelectMaster,
columns: [
new Column({
styleClass: "sapMPlanCalRowHead"
}),
new Column({
width: "80%",
styleClass: "sapMPlanCalAppRow",
minScreenWidth: APP_COLUMN_MIN_SCREEN_WIDTH,
demandPopin: true
})
],
ariaLabelledBy: `${this.getId()}-Descr`
});
oTable.attachEvent("selectionChange", handleTableSelectionChange, this);
oTable.addDelegate({
onBeforeRendering: function () {
if (this._rowHeaderPressEventMouse) {
this._rowHeaderPressEventMouse.off();
}
if (this._rowHeaderPressEventKeyboard) {
this._rowHeaderPressEventKeyboard.off();
}
},
onAfterRendering: function () {
if (this.hasListeners("rowHeaderPress")) {
this._addRowHeaderDescription();
}
const oRowHeader = oTable.$().find(".sapMPlanCalRowHead");
this._rowHeaderPressEventMouse = oRowHeader.on("click", function (oEvent) {
const oRowListItem = Element.closestTo(oEvent.currentTarget),
oRow = getRow(oRowListItem),
sRowHeaderId = oRowListItem.getAggregation("cells")[0].getId();
/**
* @deprecated As of version 1.119
*/
this.fireRowHeaderClick({headerId: sRowHeaderId, row: oRow});
this.fireRowHeaderPress({headerId: sRowHeaderId, row: oRow});
}.bind(this));
this._rowHeaderPressEventKeyboard = oRowHeader.on("keydown", function (oEvent) {
if (oEvent.which === KeyCodes.SPACE || oEvent.which === KeyCodes.ENTER) {
oEvent.preventDefault();
var oRowListItem = Element.closestTo(oEvent.currentTarget),
oRow = getRow(oRowListItem),
sRowHeaderId = oRowListItem.getAggregation("cells")[0].getId();
this.fireRowHeaderPress({headerId: sRowHeaderId, row: oRow});
}
}.bind(this));
this._adjustColumnHeadersTopOffset();
}
}, false, this);
oTable.getStickyFocusOffset = getStickyFocusOffset.bind(this);
// Override setNavigationItems to exclude the popin column header (.sapMTblItemNav) from keyboard navigation
// In PlanningCalendar context, this element serves no interactive purpose and creates a confusing "ghost" tab stop
var fnOriginalSetNavigationItems = oTable.setNavigationItems.bind(oTable);
oTable.setNavigationItems = function(oItemNavigation) {
fnOriginalSetNavigationItems(oItemNavigation);
// Remove .sapMTblItemNav elements from item navigation as they are not meaningful in PlanningCalendar
var aItemDomRefs = oItemNavigation.getItemDomRefs().filter(function(oDomRef) {
return !oDomRef.classList.contains("sapMTblItemNav");
});
oItemNavigation.setItemDomRefs(aItemDomRefs);
};
this.setAggregation("table", oTable, true);
this.setStartDate(UI5Date.getInstance());
this._resizeProxy = handleResize.bind(this);
this._fnCustomSortedAppointments = undefined; //transfers a custom appointments sorter function to the CalendarRow
this.iWidth = 0;
};
PlanningCalendar.prototype.exit = function(){
if (this._sResizeListener) {
ResizeHandler.deregister(this._sResizeListener);
this._sResizeListener = undefined;
}
Device.orientation.detachHandler(this._updateStickyHeader, this);
if (this._sUpdateCurrentTime) {
clearTimeout(this._sUpdateCurrentTime);
this._sUpdateCurrentTime = undefined;
}
// remove ColumnListItems from table to not destroy them with table but from parent PlanningCalendarRow
var oTable = this.getAggregation("table");
oTable.removeAllItems();
// destroy also currently not used controls
INTERVAL_CTR_REFERENCES.forEach(function (sControlRef) {
if (this[sControlRef]) {
this[sControlRef]._oPlanningCalendar = undefined;
this[sControlRef].destroy();
this[sControlRef] = undefined;
}
}, this);
if (this._oViews) {
for (var sKey in this._oViews) {
this._oViews[sKey].destroy();
}
}
if (this._oSelectAllCheckBox) {
this._oSelectAllCheckBox.destroy();
}
// Remove event listener for rowHeaderPress event
if (this._rowHeaderPressEventMouse) {
this._rowHeaderPressEventMouse.off();
this._rowHeaderPressEventMouse = null;
}
// Remove event listener for rowHeaderPress event
if (this._rowHeaderPressEventKeyboard) {
this._rowHeaderPressEventKeyboard.off();
this._rowHeaderPressEventKeyboard = null;
}
if (this._oCalendarWeeks) {
this._oCalendarWeeks.destroy();
this._oCalendarWeeks = null;
}
};
PlanningCalendar.prototype.onBeforeRendering = function(){
this._bBeforeRendering = true;
this._updateHeader();
// init interval if default one is used
this._adjustViewKey();
updateSelectItems.call(this);
if (this._sUpdateCurrentTime) {
clearTimeout(this._sUpdateCurrentTime);
this._sUpdateCurrentTime = undefined;
}
this._updatePickerSelection();
this._updateHeaderButtons();
Device.orientation.detachHandler(this._updateStickyHeader, this);
this._bBeforeRendering = undefined;
this._toggleStickyClasses();
updateSelectedRows.call(this);
this._setProperties();
};
PlanningCalendar.prototype._setProperties = function() {
const bMultiSelect = this.getMultipleAppointmentsSelection(),
sIconShape = this.getIconShape(),
oStartDate = this.getStartDate(),
sAppointmentHeight = this.getAppointmentHeight(),
sAppointmentRoundWidth = this.getAppointmentRoundWidth(),
bShowIntervalHeaders = this.getShowIntervalHeaders(),
bShowEmptyIntervalHeaders = this.getShowEmptyIntervalHeaders(),
sAppointmentsVisualization = this.getAppointmentsVisualization(),
oGroupAppointmentsMode = this.getGroupAppointmentsMode(),
/**
* @deprecated Since version 1.119.
*/
bAppointmentsReducedHeight = this.getAppointmentsReducedHeight(),
vLegend = this.getLegend();
this.getRows().forEach(function (oRow) {
const oCurrentRowHeader = getRowHeader(oRow),
oRowTimeline = getRowTimeline(oRow);
if (oCurrentRowHeader.getAvatar) {
oCurrentRowHeader.getAvatar().setDisplayShape(sIconShape);
}
oRowTimeline.setMultipleAppointmentsSelection(bMultiSelect);
oRowTimeline.setStartDate(oStartDate);
oRowTimeline.setAppointmentHeight(sAppointmentHeight);
oRowTimeline.setAppointmentRoundWidth(sAppointmentRoundWidth);
oRowTimeline.setShowIntervalHeaders(bShowIntervalHeaders);
oRowTimeline.setShowEmptyIntervalHeaders(bShowEmptyIntervalHeaders);
oRowTimeline.setAppointmentsVisualization(sAppointmentsVisualization);
oRowTimeline.setGroupAppointmentsMode(oGroupAppointmentsMode);
/**
* @deprecated Since version 1.119.
*/
oRowTimeline.setAppointmentsReducedHeight(bAppointmentsReducedHeight);
oRowTimeline.setLegend(vLegend);
});
this._setPrimaryCalendarType();
this._setSecondaryCalendarType();
this._setFirstDayOfWeek();
this._setCalendarWeekNumbering();
this._setShowWeekNumbers();
this._setShowRowHeaders();
this._setShowDayNamesLine();
this._setStickyHeader();
this._setNoDataText();
this._setLegend(vLegend);
};
PlanningCalendar.prototype._bindAggregation = function(sName, oBindingInfo) {
if (sName === "rows") {
addBindingListener(oBindingInfo, "dataRequested", this._onBindingDataRequestedListener.bind(this));
addBindingListener(oBindingInfo, "dataReceived", this._onBindingDataReceivedListener.bind(this));
}
Control.prototype._bindAggregation.call(this, sName, oBindingInfo);
};
PlanningCalendar.prototype._onBindingDataRequestedListener = function(oEvent) {
this.getAggregation("table").setBusy(true, "listUl");
};
PlanningCalendar.prototype._onBindingDataReceivedListener = function(oEvent) {
this.getAggregation("table").setBusy(false, "listUl");
};
PlanningCalendar.prototype._updateHeader = function () {
this._getHeader().setProperty("_primaryCalendarType", this._getPrimaryCalendarType());
if (this._getSecondaryCalendarType()) {
this.setShowDayNamesLine(true);
this._getHeader().setProperty("_secondaryCalendarType", this.getSecondaryCalendarType());
}
return this;
};
PlanningCalendar.prototype.attachEvent = function (eventId, data, functionToCall, listener) {
Control.prototype.attachEvent.call(this, eventId, data, functionToCall, listener);
if (this.hasListeners("intervalSelect")) {
INTERVAL_CTR_REFERENCES.forEach(function (sControlRef) {
if (this[sControlRef]) {
this[sControlRef]._setAriaRole("columnheader"); // set new aria role
}
}, this);
} else if (this.hasListeners("rowHeaderPress") && this.getDomRef()) {
this._addRowHeaderDescription();
}
return this;
};
PlanningCalendar.prototype.detachEvent = function (eventId, functionToCall, listener) {
Control.prototype.detachEvent.call(this, eventId, functionToCall, listener);
if (!this.hasListeners("intervalSelect")) {
INTERVAL_CTR_REFERENCES.forEach(function (sControlRef) {
if (this[sControlRef]) {
this[sControlRef]._setAriaRole("gridcell"); // set new aria role
}
}, this);
}
return this;
};
/**
* Creates the header and adds proper <code>ariaLabelledBy</code> references on its toolbars.
*
* @returns {sap.m.PlanningCalendarHeader} The created header
* @private
*/
PlanningCalendar.prototype._createHeader = function () {
var oHeader = new PlanningCalendarHeader(this.getId() + "-Header", {
calendarWeekNumbering: this.getCalendarWeekNumbering()
});
oHeader._getRelativeInfo = this._getRelativeInfo.bind(this);
oHeader.getAggregation("_actionsToolbar")
.addAriaLabelledBy(InvisibleText.getStaticId("sap.m", "PC_FUNCTIONS_TOOLBAR"));
oHeader.getAggregation("_navigationToolbar")
.addAriaLabelledBy(InvisibleText.getStaticId("sap.m", "PC_INTERVAL_SELECTION_TOOLBAR"));
return oHeader;
};
/**
* Attaches handlers to the events in the _header aggregation.
*
* @returns {this} this for method chaining
* @private
*/
PlanningCalendar.prototype._attachHeaderEvents = function () {
var oHeader = this._getHeader();
oHeader.attachEvent("pressPrevious", this._handlePressArrow, this);
oHeader.attachEvent("pressToday", this._handleTodayPress, this);
oHeader.attachEvent("pressNext", this._handlePressArrow, this);
oHeader.attachEvent("dateSelect", this._handleDateSelect, this);
oHeader.attachEvent("_titleChange", this._handleTitleChange, this);
return this;
};
PlanningCalendar.prototype._handleTitleChange = function (oEvent) {
const oTitle = oEvent.getParameter("title");
const sTitleId = oTitle?.getId() || "";
this.getDomRef()?.setAttribute("aria-labelledby", sTitleId);
this._resetTableLabelledBy(oTitle);
};
/**
* Handler for the pressPrevious and pressNext events in the _header aggregation.
* @param {object} oEvent The triggered event
* @private
*/
PlanningCalendar.prototype._handlePressArrow = function (oEvent) {
this._applyArrowsLogic(oEvent.getId() === "pressPrevious");
};
/**
* Logic for moving the selected time range in the control via the navigation arrows.
* @param {boolean} bBackwards Whether the left arrow is pressed
* @private
*/
PlanningCalendar.prototype._applyArrowsLogic = function(bBackwards) {
if (bBackwards) {
this._dateNav.previous(this._getPrimaryCalendarType());
} else {
this._dateNav.next(this._getPrimaryCalendarType());
}
var oRow = this._getRowInstanceByViewKey(this.getViewKey());
this.setStartDate(this._dateNav.getStart());
oRow.displayDate(this._dateNav.getCurrent());
this._updatePickerSelection();
this.fireStartDateChange();
};
PlanningCalendar.prototype._addRowHeaderDescription = function() {
const aPlanningCalendarRowListItems = this.getAggregation("table").getItems();
aPlanningCalendarRowListItems.forEach(function(oRowListItem) {
const oRowId = oRowListItem.getTimeline().getAssociation("row"),
oRow = Element.getElementById(oRowId),
sRowDesctiption = oRow.getRowHeaderDescription() || this._oRB.getText("PLANNING_CALENDAR_ROW_HEADER_DESCRIPTION");
oRowListItem.getDomRef().querySelector(".sapMPlanCalRowHead").setAttribute("aria-description", sRowDesctiption);
}, this);
};
/**
* Creates and formats the strings to be displayed in the picker button from the _header aggregation.
* If the date part of the start and end range of the showed view are different, the string contains
* info about the current date. Otherwise, the result string shows info about a date range.
* @returns {Object} The concatenated strings to be displayed
* @private
*/
PlanningCalendar.prototype._formatPickerText = function () {
var oRangeDates = this._getFirstAndLastRangeDate(),
oStartDate = CalendarUtils._createLocalDate(oRangeDates.oStartDate, true),
oEndDate = CalendarUtils._createLocalDate(oRangeDates.oEndDate, true),
sViewKey = this.getViewKey(),
sViewType = CalendarIntervalType[sViewKey] ? CalendarIntervalType[sViewKey] : this._getView(sViewKey).getIntervalType(),
bRTL = Localization.getRTL(),
oDateFormat,
sResult,
sBeginningResult,
sEndResult,
oDateFormatInSecType,
sBeginnigDateResultInSecType,
sEndResultInSecType,
sResultInSecType;
if (this._getSecondaryCalendarType()) {
oDateFormatInSecType = DateFormat.getDateInstance({ format: "yMMMMd", calendarType: this.getSecondaryCalendarType() });
}
switch (sViewType) {
case CalendarIntervalType.Hour:
oDateFormat = DateFormat.getDateInstance({format: "yMMMMd", calendarType: this._getPrimaryCalendarType()});
sBeginningResult = oDateFormat.format(oStartDate);
if (oStartDate.getDate() !== oEndDate.getDate()) {
sEndResult = oDateFormat.format(oEndDate);
}
if (this._getSecondaryCalendarType()){
sBeginnigDateResultInSecType = oDateFormatInSecType.format(oStartDate);
if (oStartDate.getDate() !== oEndDate.getDate()) {
sEndResultInSecType = oDateFormatInSecType.format(oEndDate);
}
}
break;
case CalendarIntervalType.Day:
case CalendarIntervalType.Week:
var fnIntervalLabelFormatter = this._getRelativeInfo().intervalLabelFormatter;
if (this.isRelative()) {
var iBeginning = this.calcIntervalOffset(this.getStartDate());
var iEnding = this.calcIntervalOffset(this.getEndDate()) - this.calcIntervalOffset(this.getStartDate());
sBeginningResult = fnIntervalLabelFormatter ? fnIntervalLabelFormatter(iBeginning) : iBeginning;
var iEndingParameter = this._getRelativeInfo().iIntervalSize === 1 ? iBeginning + iEnding : iBeginning + iEnding - 1;
sEndResult = fnIntervalLabelFormatter ? fnIntervalLabelFormatter(iEndingParameter) : iBeginning + iEnding;
} else {
oDateFormat = DateFormat.getDateInstance({ format: "yMMMMd", calendarType: this._getPrimaryCalendarType() });
sBeginningResult = oDateFormat.format(oStartDate);
sEndResult = oDateFormat.format(oEndDate);
if (this._getSecondaryCalendarType()) {
sBeginnigDateResultInSecType = oDateFormatInSecType.format(oStartDate);
sEndResultInSecType = oDateFormatInSecType.format(oEndDate);
}
}
break;
case CalendarIntervalType.OneMonth:
case "OneMonth":
oDateFormat = DateFormat.getDateInstance({format: "yMMMM", calendarType: this._getPrimaryCalendarType()});
sBeginningResult = oDateFormat.format(oStartDate);
if (this._getSecondaryCalendarType()) {
oDateFormatInSecType = DateFormat.getDateInstance({format: "yMMMM", calendarType: this.getSecondaryCalendarType()});
sBeginnigDateResultInSecType = oDateFormatInSecType.format(oStartDate);
}
break;
case CalendarIntervalType.Month:
oDateFormat = DateFormat.getDateInstance({format: "y", calendarType: this._getPrimaryCalendarType()});
sBeginningResult = oDateFormat.format(oStartDate);
if (this._getSecondaryCalendarType()) {
oDateFormatInSecType = DateFormat.getDateInstance({format: "y", calendarType: this.getSecondaryCalendarType()});
sBeginnigDateResultInSecType = oDateFormatInSecType.format(oStartDate);
}
if (oStartDate.getFullYear() !== oEndDate.getFullYear()) {
sEndResult = oDateFormat.format(oEndDate);
if (this._getSecondaryCalendarType()) {
sEndResultInSecType = oDateFormatInSecType.format(oEndDate);
}
}
if (sBeginningResult === sEndResult) {
sEndResult = undefined;
}
break;
default:
throw new Error("Unknown IntervalType: " + sViewKey + "; " + this);
}
if (!bRTL) {
sResult = sBeginningResult;
sResultInSecType = sBeginnigDateResultInSecType;
if (sEndResult) {
sResult += " - " + sEndResult;
}
if (this._getSecondaryCalendarType() && sEndResultInSecType) {
sResultInSecType += " - " + sEndResultInSecType;
}
} else {
if (sEndResult) {
sResult = sEndResult + " - " + sBeginningResult;
} else {
sResult = sBeginningResult;
}
if (this._getSecondaryCalendarType() && sEndResultInSecType) {
sResultInSecType = sBeginnigDateResultInSecType + " - " + sEndResultInSecType;
} else if (this._getSecondaryCalendarType()) {
sResultInSecType = sBeginnigDateResultInSecType;
}
}
return { primaryType: sResult, secondaryType: sResultInSecType };
};
PlanningCalendar.prototype._getPrimaryCalendarType = function() {
return this.getProperty("primaryCalendarType") || Formatting.getCalendarType();
};
/**
* Calculates the first and the last date of the range to be displayed. The size of the range depends on the
* currently selected view.
* @returns {object} Two properties containing the first and the last date from the range
* @private
*/
PlanningCalendar.prototype._getFirstAndLastRangeDate = function () {
var oStartDate = this.getStartDate(),
oMinDate = this.getMinDate(),
oStartRange = oStartDate,
oUniStartDate,
oUniEndDate;
if (oMinDate && oMinDate.getTime() > oStartDate.getTime() && this._isWeekOrOneMonthView(this.getViewKey())) {
oStartRange = oMinDate;
}
oUniStartDate = CalendarUtils._createUniversalUTCDate(oStartRange, this._getPrimaryCalendarType(), true);
oUniEndDate = CalendarUtils._createUniversalUTCDate(this._dateNav.getEnd(), this._getPrimaryCalendarType(), true);
return {
oStartDate: oUniStartDate,
oEndDate: oUniEndDate
};
};
/**
* Getter for header aggregation.
*
* @returns {sap.m.PlanningCalendarHeader} The header object
* @private
*/
PlanningCalendar.prototype._getHeader = function () {
return this.getAggregation("header");
};
/**
* Applies or removes sticky class based on <code>stickyHeader</code>'s value.
*
* @returns {this} <code>this</code> for chaining
* @private
*/
PlanningCalendar.prototype._toggleStickyClasses = function () {
this.toggleStyleClass("sapMPCSticky", this.getStickyHeader());
return this;
};
/**
* Makes sure that the column headers are offset in such a way, that they are positioned right
* after the navigation