334 lines
18 KiB
JavaScript
334 lines
18 KiB
JavaScript
"use strict";
|
|
(function () {
|
|
'use strict';
|
|
angular.module('changeModule')
|
|
.directive('calendarBookView', ['$timeout', '$log', 'events', '$rootScope', 'dateFilter', '$locale', '$state',
|
|
function ($timeout, $log, events, $rootScope, dateFilter, $locale, $state) {
|
|
return {
|
|
restrict: 'E',
|
|
templateUrl: 'views/change/calendar-book-view.html',
|
|
require: '^calendar',
|
|
scope: {},
|
|
link: function (scope, element, attrs, calendarCtrl) {
|
|
scope.model = calendarCtrl.model;
|
|
var timelineDays = 5, zoomLevel = 3, maxTimelineDays = 20, halfTimelineDays = Math.floor(timelineDays / 2), timelineStart = scope.model.context.scheduledStartDate
|
|
? new DayPilot.Date(scope.model.context.scheduledStartDate, true).addDays(-halfTimelineDays)
|
|
: new DayPilot.Date();
|
|
var zoomLevels = [
|
|
{
|
|
cellDuration: 15,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Hour" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 5,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 30,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Hour" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 5,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 60,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 5,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 120,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 5,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 240,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 10,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 360,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 14,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
},
|
|
{
|
|
cellDuration: 480,
|
|
timeHeaders: [
|
|
{ groupBy: "Day" },
|
|
{ groupBy: "Cell" }
|
|
],
|
|
minTimelineDays: 18,
|
|
formats: ['dayAndDate', 'shortestTime']
|
|
}
|
|
];
|
|
scope.isChangeCalendar = ($state.current.name && $state.current.name.indexOf('changeCalendar') !== -1);
|
|
scope.config = {
|
|
heightSpec: "Parent100Pct",
|
|
days: timelineDays,
|
|
startDate: timelineStart,
|
|
scale: "CellDuration",
|
|
cellDuration: zoomLevels[zoomLevel].cellDuration,
|
|
timeHeaders: zoomLevels[zoomLevel].timeHeaders,
|
|
theme: 'bookview',
|
|
cssClassPrefix: 'bookview',
|
|
resources: generateResourceArray(25),
|
|
onIncludeTimeCell: function (args) {
|
|
var Sunday = 0;
|
|
var Saturday = 6;
|
|
if (!scope.model.showWeekends && (args.cell.start.getDayOfWeek() === Sunday ||
|
|
args.cell.start.getDayOfWeek() === Saturday)) {
|
|
args.cell.visible = false;
|
|
}
|
|
},
|
|
onBeforeTimeHeaderRender: function (args) {
|
|
var format = zoomLevels[zoomLevel].formats[args.header.level];
|
|
if (args.header.level === 0 && window.myitsmLocale === 'en' && $locale.id.toLowerCase() !== 'en-us') {
|
|
format = 'shortDate';
|
|
}
|
|
if (format) {
|
|
var htmlText = dateFilter(args.header.start.toDateLocal(), format);
|
|
if (args.header.level === 0 && window.myitsmLocale === 'en' && $locale.id.toLowerCase() !== 'en-us') {
|
|
if ($locale.id.toLowerCase() === 'en-ca') {
|
|
//remove yy- at the beginning
|
|
htmlText = htmlText.substring(htmlText.indexOf('-') + 1);
|
|
}
|
|
else if ($locale.id.toLowerCase() === 'en-za') {
|
|
//remove yy/ at the beginning
|
|
htmlText = htmlText.substring(htmlText.indexOf('/') + 1);
|
|
}
|
|
else {
|
|
//remove /yy at the end
|
|
htmlText = htmlText.substring(0, htmlText.lastIndexOf('/'));
|
|
}
|
|
}
|
|
args.header.html = htmlText;
|
|
args.header.toolTip = htmlText;
|
|
}
|
|
},
|
|
onTimeRangeSelected: function (args) {
|
|
if (scope.isChangeCalendar) {
|
|
args.preventDefault();
|
|
}
|
|
else {
|
|
scope.changeBookView.clearSelection();
|
|
if (args.resource === scope.model.currentRequestResourceId) {
|
|
scope.model.context.scheduledStartDate = args.start.toDateLocal();
|
|
scope.model.context.scheduledEndDate = args.end.toDateLocal();
|
|
scope.$apply();
|
|
}
|
|
}
|
|
},
|
|
onEventMove: function (args) {
|
|
if (scope.isChangeCalendar || (args.newResource !== scope.model.currentRequestResourceId)) {
|
|
args.preventDefault();
|
|
}
|
|
},
|
|
onEventMoved: function (args) {
|
|
if (args.newResource === scope.model.currentRequestResourceId) {
|
|
scope.model.context.scheduledStartDate = args.newStart.toDateLocal();
|
|
scope.model.context.scheduledEndDate = args.newEnd.toDateLocal();
|
|
scope.$apply();
|
|
}
|
|
},
|
|
onEventResize: function (args) {
|
|
if (scope.isChangeCalendar || (args.e.resource() !== scope.model.currentRequestResourceId)) {
|
|
args.preventDefault();
|
|
}
|
|
},
|
|
onEventResized: function (args) {
|
|
if (args.e.resource() === scope.model.currentRequestResourceId) {
|
|
scope.model.context.scheduledStartDate = args.newStart.toDateLocal();
|
|
scope.model.context.scheduledEndDate = args.newEnd.toDateLocal();
|
|
scope.$apply();
|
|
}
|
|
},
|
|
onEventClicked: calendarCtrl.onEventClicked
|
|
};
|
|
scope.$watch('model.showWeekends', function () {
|
|
updateBookView();
|
|
});
|
|
scope.$watch('model.expanded', function () {
|
|
if (scope.model.expanded) {
|
|
$timeout(function () {
|
|
updateBookView();
|
|
}, 500);
|
|
}
|
|
});
|
|
scope.$watch('model.context.scheduledStartDate', function () {
|
|
enqueueRescheduleChangeRequest();
|
|
});
|
|
scope.$watch('model.context.scheduledEndDate', function () {
|
|
enqueueRescheduleChangeRequest();
|
|
});
|
|
scope.$watch('model.selectedCalendarView', function () {
|
|
if (scope.model.selectedCalendarView === scope.model.calendarViews[0]) {
|
|
$timeout(function () {
|
|
updateBookView();
|
|
positionTimeline();
|
|
});
|
|
}
|
|
});
|
|
var off = $rootScope.$on(events.CHANGE_COLLISION_STATUS_CHANGED, function (event, addressedCollisions) {
|
|
calendarCtrl.applyAddressedCollisions(addressedCollisions);
|
|
displayCollisions();
|
|
});
|
|
scope.$on('$destroy', function () {
|
|
off();
|
|
});
|
|
scope.$watch('model.context', function () {
|
|
calendarCtrl.updateCalendarHandling(scope.changeBookView);
|
|
}, true);
|
|
scope.$watch('model.collisions', function () {
|
|
displayCollisions();
|
|
}, true);
|
|
scope.$watch('model.calendarTypes', function () {
|
|
displayCollisions();
|
|
}, true);
|
|
scope.$on(events.ZOOM_LEVEL_CHANGED, function (event, increment) {
|
|
applyZoomLevel(increment);
|
|
});
|
|
function displayCollisions() {
|
|
calendarCtrl.displayCollisions({
|
|
calendar: scope.changeBookView,
|
|
resources: scope.config.resources,
|
|
outagesIndex: computeOutagesIndex(),
|
|
businessEventsIndex: computeBusinessEventsIndex(),
|
|
changeCollisionCss: 'bookview_event_collision',
|
|
changeNonCollisionCss: 'bookview_event_secondary',
|
|
outageCollisionCss: 'bookview_event_outage_collision',
|
|
outageNonCollisionCss: 'bookview_event_outage_secondary',
|
|
businessEventCollisionCss: 'bookview_event_business_event_collision',
|
|
businessEventNonCollisionCss: 'bookview_event_business_event_secondary',
|
|
updateCalendar: function () {
|
|
updateBookView(true);
|
|
}
|
|
});
|
|
}
|
|
function computeOutagesIndex() {
|
|
return (calendarCtrl.changeRequestFilterSelected() ? calendarCtrl.visibleChangeRequests(scope.changeBookView).length : 0) + 1;
|
|
}
|
|
function computeBusinessEventsIndex() {
|
|
var outageIndex = computeOutagesIndex();
|
|
return calendarCtrl.outageFilterSelected() ? outageIndex + 1 : outageIndex;
|
|
}
|
|
function updateBookView(forceUpdate) {
|
|
var start = scope.model.context.scheduledStartDate, end = scope.model.context.scheduledEndDate, update = !!(start && end);
|
|
if (update) {
|
|
$log.log("update book view: start=" + start + "(" + start.getTime() + "), end=" + end + "(" + end.getTime() + ")");
|
|
scope.changeBookView.collisionStart = new DayPilot.Date(start, true);
|
|
scope.changeBookView.collisionEnd = new DayPilot.Date(end, true);
|
|
}
|
|
else {
|
|
scope.changeBookView.collisionStart = null;
|
|
scope.changeBookView.collisionEnd = null;
|
|
}
|
|
if (update || forceUpdate) {
|
|
scope.changeBookView.update();
|
|
}
|
|
}
|
|
function positionTimeline() {
|
|
var start = scope.model.context.scheduledStartDate
|
|
? scope.model.context.scheduledStartDate
|
|
: new Date();
|
|
startTimelineOn(start);
|
|
}
|
|
function startTimelineOn(date) {
|
|
if (date instanceof Date) {
|
|
date = new DayPilot.Date(date, true);
|
|
}
|
|
date = date.addHours(-date.getHours()).addMinutes(-date.getMinutes());
|
|
scope.changeBookView.scrollTo(date);
|
|
}
|
|
function enqueueRescheduleChangeRequest() {
|
|
$timeout(function () {
|
|
rescheduleChangeRequest(scope.model.context.scheduledStartDate, scope.model.context.scheduledEndDate);
|
|
});
|
|
}
|
|
function rescheduleChangeRequest(start, end) {
|
|
if (calendarCtrl.rescheduleChangeRequest(scope.changeBookView, start, end)
|
|
&& !extendTimeline(start, end)) {
|
|
updateBookView();
|
|
}
|
|
}
|
|
function extendTimeline(start, end) {
|
|
if (!start || !end) {
|
|
return false;
|
|
}
|
|
if (start instanceof Date) {
|
|
start = new DayPilot.Date(start, true);
|
|
}
|
|
if (end instanceof Date) {
|
|
end = new DayPilot.Date(end, true);
|
|
}
|
|
var edgeDays = 1, bufferDays = 2, timelineStartMoment = moment(timelineStart.toDateLocal()).startOf("day"), timelineEnd = timelineStart.addDays(timelineDays), timelineEndMoment = moment(timelineEnd.toDateLocal()).startOf("day"), startMoment = moment(start.toDateLocal()).startOf("day"), endMoment = moment(end.toDateLocal()).startOf("day"), timelineModified = false;
|
|
var startDiff = startMoment.diff(timelineStartMoment, "days");
|
|
var endDiff = timelineEndMoment.diff(endMoment, "days");
|
|
if (startDiff < edgeDays || endDiff <= edgeDays) {
|
|
timelineStartMoment = startMoment.subtract(bufferDays, "days");
|
|
timelineEndMoment = endMoment.add(bufferDays + 1, "days"); // +1 is required to have full bufferDays number after end date, otherwise the actual number would be 1 day less
|
|
timelineDays = timelineEndMoment.diff(timelineStartMoment, "days");
|
|
timelineDays = Math.min(timelineDays, maxTimelineDays);
|
|
timelineDays = Math.max(timelineDays, zoomLevels[zoomLevel].minTimelineDays);
|
|
timelineStart = new DayPilot.Date(timelineStartMoment.toDate());
|
|
timelineModified = true;
|
|
}
|
|
if (timelineModified) {
|
|
$log.log("book view timeline extended: start=" + timelineStart + " days=" + timelineDays);
|
|
scope.changeBookView.days = scope.config.days = timelineDays;
|
|
scope.changeBookView.startDate = scope.config.startDate = timelineStart;
|
|
updateBookView();
|
|
positionTimeline();
|
|
}
|
|
return timelineModified;
|
|
}
|
|
function generateResourceArray(count) {
|
|
count = count || 10;
|
|
var resources = [
|
|
{ name: "", id: scope.model.currentRequestResourceId }
|
|
];
|
|
for (var i = 1; i < count; i++) {
|
|
resources.push({ name: "", id: i.toString() });
|
|
}
|
|
return resources;
|
|
}
|
|
function applyZoomLevel(increment) {
|
|
zoomLevel += increment;
|
|
if (zoomLevel < 0 || zoomLevel >= zoomLevels.length) {
|
|
zoomLevel -= increment;
|
|
return;
|
|
}
|
|
scope.model.zoomInDisabled = zoomLevel === 0;
|
|
scope.model.zoomOutDisabled = zoomLevel === zoomLevels.length - 1;
|
|
$log.log("book view timeline zoomed to " + zoomLevel + " level.");
|
|
scope.changeBookView.cellDuration = scope.config.cellDuration = zoomLevels[zoomLevel].cellDuration;
|
|
scope.changeBookView.timeHeaders = scope.config.timeHeaders = zoomLevels[zoomLevel].timeHeaders;
|
|
scope.changeBookView.days = scope.config.days = Math.max(timelineDays, zoomLevels[zoomLevel].minTimelineDays);
|
|
updateBookView();
|
|
}
|
|
positionTimeline();
|
|
}
|
|
};
|
|
}
|
|
]);
|
|
})();
|