/*!
* UI development toolkit for HTML5 (OpenUI5)
* (c) Copyright 2009-2018 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.m.OnePersonGrid.
sap.ui.define([
'sap/ui/core/Control',
'sap/ui/core/LocaleData',
'sap/ui/core/Locale',
'sap/ui/core/format/DateFormat',
'sap/ui/core/date/UniversalDate',
'sap/ui/unified/library',
'sap/ui/unified/calendar/DatesRow',
'./OnePersonGridRenderer'
],
function (Control, LocaleData, Locale, DateFormat, UniversalDate, unifiedLibrary, DatesRow, OnePersonGridRenderer) {
"use strict";
// shortcut for sap.ui.unified.CalendarAppointmentVisualization
var CalendarAppointmentVisualization = unifiedLibrary.CalendarAppointmentVisualization;
var ROW_HEIGHT = 48,
BLOCKER_ROW_HEIGHT = 28,
HALF_HOUR = 3600000 / 2,
ONE_DAY = 86400000;
/**
* Constructor for a new OnePersonGrid.
*
* @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
* A Grid control for rendering OnePersonCalendar Appointments
* Disclaimer: this control is in beta state - incompatible API changes may be done before its official public release. Use at your own discretion.
*
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.60.23
*
* @constructor
* @private
* @alias sap.m.OnePersonGrid
* @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
*/
var OnePersonGrid = Control.extend("sap.m.OnePersonGrid", /** @lends sap.m.OnePersonGrid.prototype */ {
metadata: {
library: "sap.m",
properties: {
startDate: {type: "object", group: "Data"},
startHour: {type: "int", group: "Appearance", defaultValue: 8},
endHour: {type: "int", group: "Appearance", defaultValue: 17},
showFullDay: {type: "boolean", group: "Appearance", defaultValue: true},
appointmentsVisualization : {type : "sap.ui.unified.CalendarAppointmentVisualization", group : "Appearance", defaultValue : CalendarAppointmentVisualization.Standard}
},
aggregations: {
appointments: {type: "sap.ui.unified.CalendarAppointment", multiple: true, singularName: "appointment"},
_columnHeaders: {type: "sap.ui.unified.calendar.DatesRow", multiple: false, visibility: "hidden"}
},
associations: {
/**
* Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledby).
*
* Note These labels are also assigned to the appointments.
*/
ariaLabelledBy: {type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy"}
}
}
});
OnePersonGrid.prototype.init = function () {
var oStartDate = this._getUniversalCurrentDate().getJSDate(),
oDatesRow = new DatesRow(this.getId() + "-columnHeaders", {
showDayNamesLine: false,
showWeekNumbers: false,
startDate: oStartDate
}).addStyleClass("sapMOnePersonColumnHeader"),
iDelay = (60 - oStartDate.getSeconds()) * 1000;
this.setAggregation("_columnHeaders", oDatesRow);
this.setStartDate(oStartDate);
this._setColumns(7);
setTimeout(this._updateRowHeaderAndNowMarker.bind(this), iDelay);
};
OnePersonGrid.prototype.onBeforeRendering = function () {
var oAppointmentsMap = this._createAppointmentsMap(this.getAppointments()),
oStartDate = this._getUniversalStartDate(),
iColumns = this._getColumns();
this._oVisibleAppointments = this._calculateVisibleAppointments(oAppointmentsMap.appointments, oStartDate, iColumns);
this._oAppointmentsToRender = this._calculateAppointmentsLevelsAndWidth(this._oVisibleAppointments);
this._aVisibleBlockers = this._calculateVisibleBlockers(oAppointmentsMap.blockers, oStartDate, iColumns);
this._oBlockersToRender = this._calculateBlockersLevelsAndWidth(this._aVisibleBlockers);
};
OnePersonGrid.prototype.setStartDate = function (oStartDate) {
this._oUniversalStartDate = UniversalDate.getInstance(oStartDate);
this.getAggregation("_columnHeaders").setStartDate(oStartDate);
return this.setProperty("startDate", oStartDate);
};
/*
* PRIVATE API
*/
OnePersonGrid.prototype._getUniversalStartDate = function () {
return this._oUniversalStartDate;
};
OnePersonGrid.prototype._getUniversalCurrentDate = function () {
return UniversalDate.getInstance(new Date());
};
OnePersonGrid.prototype._areDatesInSameDay = function (oDate1, oDate2) {
var bYearEqual = oDate1.getFullYear() === oDate2.getFullYear(),
bMonthEqual = oDate1.getMonth() === oDate2.getMonth(),
bDateEqual = oDate1.getDate() === oDate2.getDate();
return bYearEqual && bMonthEqual && bDateEqual;
};
OnePersonGrid.prototype._getStartHour = function () {
var iMinHour = Math.min(this.getStartHour(), this.getEndHour());
return iMinHour < 0 ? 0 : iMinHour;
};
OnePersonGrid.prototype._getEndHour = function () {
var iMaxHour = Math.max(this.getStartHour(), this.getEndHour());
return iMaxHour > 24 ? 24 : iMaxHour;
};
OnePersonGrid.prototype._getVisibleStartHour = function () {
return this.getShowFullDay() ? 0 : this._getStartHour();
};
OnePersonGrid.prototype._getVisibleEndHour = function () {
return (this.getShowFullDay() ? 24 : this._getEndHour()) - 1;
};
OnePersonGrid.prototype._isWorkingHour = function (iHour) {
return this._getStartHour() <= iHour && iHour <= this._getEndHour();
};
OnePersonGrid.prototype._isOutsideVisibleHours = function (iHour) {
var iHour,
iVisibleStartHour = this._getVisibleStartHour(),
iVisibleEndHour = this._getVisibleEndHour();
return iHour < iVisibleStartHour || iHour > iVisibleEndHour;
};
OnePersonGrid.prototype._isCurrentMinutesLessThan = function (iMaxMinutes) {
var iCurrentMinutes = this._getUniversalCurrentDate().getMinutes();
return iMaxMinutes >= iCurrentMinutes;
};
OnePersonGrid.prototype._isCurrentMinutesMoreThan = function (iMinMinutes) {
var iCurrentMinutes = this._getUniversalCurrentDate().getMinutes();
return iMinMinutes <= iCurrentMinutes;
};
OnePersonGrid.prototype._isWeekend = function (oDate) {
var iDay = oDate.getDay();
return iDay % 6 === 0;
};
OnePersonGrid.prototype._shouldHideRowHeader = function (iRow) {
var iCurrentHour = this._getUniversalCurrentDate().getHours(),
bIsNearAfterCurrentHour = this._isCurrentMinutesLessThan(15) && iCurrentHour === iRow,
bIsNearBeforeCurrentHour = this._isCurrentMinutesMoreThan(45) && iCurrentHour === iRow - 1;
return bIsNearAfterCurrentHour || bIsNearBeforeCurrentHour;
};
OnePersonGrid.prototype._formatDayAsString = function (oDate) {
return oDate.getFullYear() + "-" + oDate.getMonth() + "-" + oDate.getDate();
};
OnePersonGrid.prototype._formatTimeAsString = function (oDate) {
var iCurrentMinutes = oDate.getMinutes(),
oHoursFormat = this._getHoursFormat(),
oAMPMFormat = this._getAMPMFormat(),
sAMPM = "";
if (iCurrentMinutes < 10) {
iCurrentMinutes = "0" + iCurrentMinutes;
}
if (this._hasAMPM()) {
sAMPM += " " + oAMPMFormat.format(oDate); // TODO: use second param true when convert all dates to UTC
}
return oHoursFormat.format(oDate) + ":" + iCurrentMinutes + sAMPM; // TODO: use second param true when convert all dates to UTC
};
OnePersonGrid.prototype._calculateTopPosition = function (oDate) {
var iHour = oDate.getHours() - this._getVisibleStartHour(),
iMinutes = oDate.getMinutes(),
iRowHeight = this._getRowHeight();
return (iRowHeight * iHour) + (iRowHeight / 60) * iMinutes;
};
OnePersonGrid.prototype._calculateBottomPosition = function (oDate) {
var iHour = this._getVisibleEndHour() + 1 - oDate.getHours(),
iMinutes = oDate.getMinutes(),
iRowHeight = this._getRowHeight();
return (iRowHeight * iHour) - (iRowHeight / 60) * iMinutes;
};
OnePersonGrid.prototype._updateRowHeaderAndNowMarker = function () {
var oCurrentDate = this._getUniversalCurrentDate();
this._updateNowMarker(oCurrentDate);
this._updateRowHeaders(oCurrentDate);
setTimeout(this._updateRowHeaderAndNowMarker.bind(this), 60 * 1000);
};
OnePersonGrid.prototype._updateNowMarker = function (oDate) {
var $nowMarker = this.$("nowMarker"),
$nowMarkerText = this.$("nowMarkerText"),
bCurrentHourNotVisible = this._isOutsideVisibleHours(oDate.getHours());
$nowMarker.toggleClass("sapMOnePersonNowMarkerHidden", bCurrentHourNotVisible);
$nowMarker.css("top", this._calculateTopPosition(oDate) + "px");
$nowMarkerText.text(this._formatTimeAsString(oDate));
};
OnePersonGrid.prototype._updateRowHeaders = function (oDate) {
var $domRef = this.$(),
iCurrentHour = oDate.getHours(),
iNextHour = iCurrentHour + 1;
$domRef.find(".sapMOnePersonRowHeader").removeClass("sapMOnePersonRowHeaderHidden");
if (this._shouldHideRowHeader(iCurrentHour)) {
$domRef.find(".sapMOnePersonRowHeader" + iCurrentHour).addClass("sapMOnePersonRowHeaderHidden");
} else if (this._shouldHideRowHeader(iNextHour)) {
$domRef.find(".sapMOnePersonRowHeader" + iNextHour).addClass("sapMOnePersonRowHeaderHidden");
}
};
OnePersonGrid.prototype._createAppointmentsMap = function (aAppointments) {
var that = this;
return aAppointments.reduce(function (oMap, oAppointment) {
var oAppStartDate = oAppointment.getStartDate(),
oAppEndDate = oAppointment.getEndDate(),
bIsFullDay = oAppointment.getFullDay && oAppointment.getFullDay();
if (!oAppStartDate || !oAppEndDate) {
return oMap;
}
if (!bIsFullDay) {
var oCurrentAppStartDate = new UniversalDate(oAppStartDate.getFullYear(), oAppStartDate.getMonth(), oAppStartDate.getDate()),
oCurrentAppEndDate = new UniversalDate(oAppEndDate.getFullYear(), oAppEndDate.getMonth(), oAppEndDate.getDate());
while (oCurrentAppStartDate.getTime() <= oCurrentAppEndDate.getTime()) {
var sDay = that._formatDayAsString(oCurrentAppStartDate);
if (!oMap.appointments[sDay]) {
oMap.appointments[sDay] = [];
}
oMap.appointments[sDay].push(oAppointment);
oCurrentAppStartDate.setDate(oCurrentAppStartDate.getDate() + 1);
}
} else {
oMap.blockers.push(oAppointment);
}
return oMap;
}, { appointments: {}, blockers: []});
};
OnePersonGrid.prototype._calculateVisibleAppointments = function (oAppointments, oStartDate, iColumns) {
var oVisibleAppointments = {};
for (var i = 0; i < iColumns; i++) {
var oDate = new UniversalDate(oStartDate.getFullYear(), oStartDate.getMonth(), oStartDate.getDate() + i),
sDate = this._formatDayAsString(oDate),
fnIsVisiblePredicate = this._isAppointmentFitInVisibleHours(oDate);
if (oAppointments[sDate]) {
oVisibleAppointments[sDate] = oAppointments[sDate]
.filter(fnIsVisiblePredicate, this)
.sort(this._sortAppointmentsByStartHour);
}
}
return oVisibleAppointments;
};
OnePersonGrid.prototype._isAppointmentFitInVisibleHours = function (oColumnDate) {
return function (oAppointment) {
var iAppStartTime = oAppointment.getStartDate().getTime(),
iAppEndTime = oAppointment.getEndDate().getTime(),
iColumnStartTime = (new UniversalDate(oColumnDate.getFullYear(), oColumnDate.getMonth(), oColumnDate.getDate(), this._getVisibleStartHour())).getTime(),
iColumnEndTime = (new UniversalDate(oColumnDate.getFullYear(), oColumnDate.getMonth(), oColumnDate.getDate(), this._getVisibleEndHour(), 59, 59)).getTime();
var bBiggerThanVisibleHours = iAppStartTime < iColumnStartTime && iAppEndTime > iColumnEndTime,
bStartHourBetweenColumnStartAndEnd = iAppStartTime >= iColumnStartTime && iAppStartTime < iColumnEndTime,
bEndHourBetweenColumnStartAndEnd = iAppEndTime > iColumnStartTime && iAppEndTime <= iColumnEndTime;
return bBiggerThanVisibleHours || bStartHourBetweenColumnStartAndEnd || bEndHourBetweenColumnStartAndEnd;
};
};
OnePersonGrid.prototype._calculateAppointmentsLevelsAndWidth = function (oVisibleAppointments) {
var that = this;
return Object.keys(oVisibleAppointments).reduce(function (oAcc, sDate) {
var iMaxLevel = 0,
oAppointmentsList = new AppointmentsList(),
aAppointments = oVisibleAppointments[sDate];
aAppointments.forEach(function (oCurrentAppointment) {
var oCurrentAppointmentNode = new AppointmentNode(oCurrentAppointment),
iCurrentAppointmentStart = oCurrentAppointment.getStartDate().getTime();
if (oAppointmentsList.getSize() === 0) {
oAppointmentsList.add(oCurrentAppointmentNode);
return;
}
oAppointmentsList.getIterator().forEach(function (oAppointmentNode) {
var bShouldBreak = true,
oAppointment = oAppointmentNode.getData(),
iAppointmentStart = oAppointment.getStartDate().getTime(),
iAppointmentEnd = oAppointment.getEndDate().getTime(),
iAppointmentDuration = iAppointmentEnd - iAppointmentStart;
if (iAppointmentDuration < HALF_HOUR) {
// Take into account that appointments smaller than one hour will be rendered as one hour
// in height. That's why the calculation for levels should consider this too.
iAppointmentEnd = iAppointmentEnd + (HALF_HOUR - iAppointmentDuration);
}
if (iCurrentAppointmentStart >= iAppointmentStart && iCurrentAppointmentStart < iAppointmentEnd) {
oCurrentAppointmentNode.level++;
iMaxLevel = Math.max(iMaxLevel, oCurrentAppointmentNode.level);
}
if (oAppointmentNode.next && oAppointmentNode.next.level === oCurrentAppointmentNode.level) {
bShouldBreak = false;
}
if (iCurrentAppointmentStart >= iAppointmentEnd && bShouldBreak) {
this.interrupt();
}
});
oAppointmentsList.insertAfterLevel(oCurrentAppointmentNode.level, oCurrentAppointmentNode);
});
oAcc[sDate] = { oAppointmentsList: that._calculateAppointmentsWidth(oAppointmentsList), iMaxLevel: iMaxLevel };
return oAcc;
}, {});
};
OnePersonGrid.prototype._calculateAppointmentsWidth = function (oAppointmentsList) {
oAppointmentsList.getIterator().forEach(function (oCurrentAppointmentNode) {
var oCurrentAppointment = oCurrentAppointmentNode.getData(),
iLevelFoundSpace = oCurrentAppointmentNode.level,
iCurrentAppointmentLevel = oCurrentAppointmentNode.level,
iCurrentAppointmentStart = oCurrentAppointment.getStartDate().getTime(),
iCurrentAppointmentEnd = oCurrentAppointment.getEndDate().getTime(),
iCurrentAppointmentDuration = iCurrentAppointmentEnd - iCurrentAppointmentStart;
if (iCurrentAppointmentDuration < HALF_HOUR) {
// Take into account that appointments smaller than one hour will be rendered as one hour
// in height. That's why the calculation for levels should consider this too.
iCurrentAppointmentEnd = iCurrentAppointmentEnd + (HALF_HOUR - iCurrentAppointmentDuration);
}
new AppointmentsIterator(oAppointmentsList).forEach(function (oAppointmentNode) {
var oAppointment = oAppointmentNode.getData(),
iAppointmentLevel = oAppointmentNode.level,
iAppointmentStart = oAppointment.getStartDate().getTime(),
iAppointmentEnd = oAppointment.getEndDate().getTime(),
iAppointmentDuration = iAppointmentEnd - iAppointmentStart;
if (iAppointmentDuration < HALF_HOUR) {
// Take into account that appointments smaller than one hour will be rendered as one hour
// in height. That's why the calculation for levels should consider this too.
iAppointmentEnd = iAppointmentEnd + (HALF_HOUR - iAppointmentDuration);
}
if (iCurrentAppointmentLevel >= iAppointmentLevel) {
return;
}
if (
iCurrentAppointmentStart >= iAppointmentStart && iCurrentAppointmentStart < iAppointmentEnd ||
iCurrentAppointmentEnd > iAppointmentStart && iCurrentAppointmentEnd < iAppointmentEnd ||
iCurrentAppointmentStart <= iAppointmentStart && iCurrentAppointmentEnd >= iAppointmentEnd
) {
oCurrentAppointmentNode.width = iAppointmentLevel - iCurrentAppointmentLevel;
this.interrupt();
return;
}
if (iLevelFoundSpace < iAppointmentLevel) {
iLevelFoundSpace = iAppointmentLevel;
oCurrentAppointmentNode.width++;
}
});
});
return oAppointmentsList;
};
OnePersonGrid.prototype._calculateVisibleBlockers = function (aBlockers, oStartDate, iColumns) {
oStartDate = this._getDayPart(oStartDate);
var oEndDate = new UniversalDate(oStartDate.getFullYear(), oStartDate.getMonth(), oStartDate.getDate() + iColumns),
fnIsVisiblePredicate = this._isBlockerVisible(oStartDate, oEndDate);
return aBlockers.filter(fnIsVisiblePredicate)
.sort(this._sortAppointmentsByStartHour);
};
OnePersonGrid.prototype._isBlockerVisible = function (oStartDate, oEndDate) {
var that = this;
return function (oAppointment) {
var oAppStartDate = oAppointment.getStartDate(),
oAppEndDate = oAppointment.getEndDate(),
iAppStartTime = that._getDayPart(oAppStartDate).getTime(),
iAppEndTime = that._getDayPart(oAppEndDate).getTime(),
iViewStartTime = oStartDate.getTime(),
iViewEndTime = oEndDate.getTime();
var bIsBiggerThanView = iAppStartTime < iViewStartTime && iAppEndTime > iViewEndTime,
bStartDateBetweenViewStartAndEnd = iAppStartTime >= iViewStartTime && iAppStartTime < iViewEndTime,
bEndDateBetweenViewStartAndEnd = iAppEndTime >= iViewStartTime && iAppEndTime <= iViewEndTime;
return bIsBiggerThanView || bStartDateBetweenViewStartAndEnd || bEndDateBetweenViewStartAndEnd;
};
};
OnePersonGrid.prototype._calculateBlockersLevelsAndWidth = function (aVisibleBlockers) {
var iMaxLevel = 0,
oBlockersList = new AppointmentsList(),
that = this;
aVisibleBlockers.forEach(function (oCurrentBlocker) {
var oCurrentBlockerNode = new AppointmentNode(oCurrentBlocker),
oCurrentBlockerStartDate = oCurrentBlocker.getStartDate(),
oCurrentBlockerEndDate = oCurrentBlocker.getEndDate(),
iCurrentBlockerStartTime = that._getDayPart(oCurrentBlockerStartDate).getTime(),
iCurrentBlockerEndTime = that._getDayPart(oCurrentBlockerEndDate).getTime();
oCurrentBlockerNode.width = that._calculateDaysDifference(iCurrentBlockerStartTime, iCurrentBlockerEndTime);
if (oBlockersList.getSize() === 0) {
oBlockersList.add(oCurrentBlockerNode);
return;
}
oBlockersList.getIterator().forEach(function (oBlockerNode) {
var bShouldBreak = true,
oBlocker = oBlockerNode.getData(),
oBlockerStartDate = oBlocker.getStartDate(),
oBlockerEndDate = oBlocker.getEndDate(),
iBlockerStartTime = that._getDayPart(oBlockerStartDate).getTime(),
iBlockerEndTime = that._getDayPart(oBlockerEndDate).getTime();
if (iCurrentBlockerStartTime >= iBlockerStartTime && iCurrentBlockerStartTime < iBlockerEndTime) {
oCurrentBlockerNode.level++;
iMaxLevel = Math.max(iMaxLevel, oCurrentBlockerNode.level);
}
if (oBlockerNode.next && oBlockerNode.next.level === oCurrentBlockerNode.level) {
bShouldBreak = false;
}
if (iCurrentBlockerStartTime >= iBlockerEndTime && bShouldBreak) {
this.interrupt();
}
});
oBlockersList.insertAfterLevel(oCurrentBlockerNode.level, oCurrentBlockerNode);
}, this);
return { oBlockersList: oBlockersList, iMaxlevel: iMaxLevel };
};
OnePersonGrid.prototype._calculateDaysDifference = function (iStartTime, iEndTime) {
var iTimeDifference = iEndTime - iStartTime;
return Math.round(iTimeDifference / ONE_DAY);
};
OnePersonGrid.prototype._sortAppointmentsByStartHour = function (oApp1, oApp2) {
return oApp1.getStartDate().getTime() - oApp2.getStartDate().getTime() || oApp2.getEndDate().getTime() - oApp1.getEndDate().getTime();
};
OnePersonGrid.prototype._getVisibleAppointments = function () {
return this._oVisibleAppointments;
};
OnePersonGrid.prototype._getAppointmentsToRender = function () {
return this._oAppointmentsToRender;
};
OnePersonGrid.prototype._getVisibleBlockers = function () {
return this._aVisibleBlockers;
};
OnePersonGrid.prototype._getBlockersToRender = function () {
return this._oBlockersToRender;
};
OnePersonGrid.prototype._setColumns = function (iColumns) {
this._iColumns = iColumns;
this.getAggregation("_columnHeaders").setDays(iColumns);
this.invalidate();
};
OnePersonGrid.prototype._getColumns = function () {
return this._iColumns; // TODO: should get it from the view
};
OnePersonGrid.prototype._getRowHeight = function () {
return ROW_HEIGHT;
};
OnePersonGrid.prototype._getBlockerRowHeight = function () {
return BLOCKER_ROW_HEIGHT;
};
OnePersonGrid.prototype._getDayPart = function (oDate) {
return new UniversalDate(oDate.getFullYear(), oDate.getMonth(), oDate.getDate());
};
OnePersonGrid.prototype._getCoreLocale = function () {
if (!this._sLocale) {
this._sLocale = sap.ui.getCore().getConfiguration().getFormatSettings().getFormatLocale().toString();
}
return this._sLocale;
};
OnePersonGrid.prototype._getCoreLocaleData = function() {
if (!this._oLocaleData) {
var sLocale = this._getCoreLocale(),
oLocale = new Locale(sLocale);
this._oLocaleData = LocaleData.getInstance(oLocale);
}
return this._oLocaleData;
};
OnePersonGrid.prototype._hasAMPM = function () {
var oLocaleData = this._getCoreLocaleData();
return oLocaleData.getTimePattern("short").search("a") >= 0;
};
OnePersonGrid.prototype._getHoursFormat = function () {
var sLocale = this._getCoreLocale();
if (!this._oHoursFormat || this._oHoursFormat.oLocale.toString() !== sLocale) {
var oLocale = new Locale(sLocale),
bHasAMPM = this._hasAMPM(),
sPattern = bHasAMPM ? "h" : "H";
this._oHoursFormat = DateFormat.getTimeInstance({pattern: sPattern}, oLocale);
}
return this._oHoursFormat;
};
OnePersonGrid.prototype._getAMPMFormat = function () {
var sLocale = this._getCoreLocale(),
oLocale = new Locale(sLocale);
if (!this._oAMPMFormat || this._oAMPMFormat.oLocale.toString() !== sLocale) {
this._oAMPMFormat = DateFormat.getTimeInstance({pattern: "a"}, oLocale);
}
return this._oAMPMFormat;
};
// Appointments Node
function AppointmentNode(oData) {
this.data = oData;
this.level = 0;
this.width = 1;
this.prev = null;
this.next = null;
}
AppointmentNode.prototype.hasNext = function () {
return this.next !== null;
};
AppointmentNode.prototype.hasPrev = function () {
return this.prev !== null;
};
AppointmentNode.prototype.getData = function () {
return this.data;
};
// Appointments List
function AppointmentsList() {
this.head = null;
this.tail = null;
this.size = 0;
this.iterator = new AppointmentsIterator(this);
}
AppointmentsList.prototype.getHeadNode = function () {
return this.head;
};
AppointmentsList.prototype.getTailNode = function () {
return this.tail;
};
AppointmentsList.prototype.getSize = function () {
return this.size;
};
AppointmentsList.prototype.isEmpty = function () {
return this.getSize() === 0;
};
AppointmentsList.prototype.createNewNode = function (oData) {
return new AppointmentNode(oData);
};
AppointmentsList.prototype.getIterator = function () {
return this.iterator;
};
AppointmentsList.prototype.indexOf = function (oNode, fnComparator) {
this.iterator.reset();
var oCurrentNode,
iIndex = 0;
while (this.iterator.hasNext()) {
oCurrentNode = this.iterator.next();
if (fnComparator(oCurrentNode)) {
return iIndex;
}
iIndex++;
}
return -1;
};
AppointmentsList.prototype.add = function (oData) {
var oNewNode = oData;
if (!(oData instanceof AppointmentNode)) {
oNewNode = this.createNewNode(oData);
}
if (this.isEmpty()) {
this.head = this.tail = oNewNode;
} else {
this.tail.next = oNewNode;
oNewNode.prev = this.tail;
this.tail = oNewNode;
}
this.size++;
return true;
};
AppointmentsList.prototype.insertFirst = function (oData) {
if (this.isEmpty()) {
this.add(oData);
} else {
var oNewNode = oData;
if (!(oData instanceof AppointmentNode)) {
oNewNode = this.createNewNode(oData);
}
oNewNode.next = this.head;
this.head.prev = oNewNode;
this.head = oNewNode;
this.size++;
return true;
}
};
AppointmentsList.prototype.insertAt = function (iIndex, oData) {
var oCurrentNode = this.getHeadNode(),
position = 0,
oNewNode = oData;
if (!(oData instanceof AppointmentNode)) {
oNewNode = this.createNewNode(oData);
}
if (iIndex < 0) {
return false;
}
if (iIndex === 0) {
return this.insertFirst(oData);
}
if (iIndex > this.getSize() - 1) {
return this.add(oData);
}
while (position < iIndex) {
oCurrentNode = oCurrentNode.next;
position++;
}
oCurrentNode.prev.next = oNewNode;
oNewNode.prev = oCurrentNode.prev;
oCurrentNode.prev = oNewNode;
oNewNode.next = oCurrentNode;
this.size++;
return true;
};
AppointmentsList.prototype.insertAfterLevel = function (iLevel, oNode) {
var iIndex = this.indexOf(oNode, function (oCurrentNode) {
var bLastInLevel = oCurrentNode.level === iLevel;
if (oCurrentNode.next && oCurrentNode.next.level === iLevel) {
bLastInLevel = false;
}
return bLastInLevel;
}),
iSize = this.getSize();
if (iIndex + 1 === iSize || iIndex === -1) {
return this.add(oNode);
} else {
return this.insertAt(iIndex + 1, oNode);
}
};
// AppointmentsList Iterator
function AppointmentsIterator (oList) {
this.list = oList;
this.stopIterationFlag = false;
this.currentNode = null;
}
AppointmentsIterator.prototype.next = function () {
var oCurrentNode = this.currentNode;
if (this.currentNode !== null) {
this.currentNode = this.currentNode.next;
}
return oCurrentNode;
};
AppointmentsIterator.prototype.hasNext = function () {
return this.currentNode !== null;
};
AppointmentsIterator.prototype.reset = function () {
this.currentNode = this.list.getHeadNode();
return this;
};
AppointmentsIterator.prototype.forEach = function (fnCallback, oThis) {
var oCurrentNode;
oThis = oThis || this;
this.reset();
while (this.hasNext() && !this.stopIterationFlag) {
oCurrentNode = this.next();
fnCallback.call(oThis, oCurrentNode);
}
this.stopIterationFlag = false;
};
AppointmentsIterator.prototype.interrupt = function () {
this.stopIterationFlag = true;
return this;
};
return OnePersonGrid;
});