/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ (function() { 'use strict'; /* * sgCalendarBlock - Applied to an event ghost block to be displayed while dragging an event block. Each day of the * calendar's view must have a ghost block. * @memberof SOGo.SchedulerUI * @restrict attribute * * @example: / */ sgCalendarGhost.$inject = ['$rootScope', '$timeout', 'CalendarSettings', 'Calendar', 'Component']; function sgCalendarGhost($rootScope, $timeout, CalendarSettings, Calendar, Component) { return { restrict: 'A', require: ['^sgCalendarDay', '^sgCalendarScrollView'], link: link }; function link(scope, iElement, attrs, ctrls) { var domElement, calendarDayCtrl, scrollViewCtrl, calendarNumber, originalCalendarNumber; domElement = iElement[0]; calendarDayCtrl = ctrls[0]; scrollViewCtrl = ctrls[1]; calendarNumber = -1; iElement.addClass('sg-event--ghost md-whiteframe-3dp ng-hide'); // Listen on drag gestures var deregisterDragStart = $rootScope.$on('calendar:dragstart', initGhost); var deregisterDrag = $rootScope.$on('calendar:drag', updateGhost); var deregisterDragEnd = $rootScope.$on('calendar:dragend', hideGhost); // Deregister listeners on destroy scope.$on('$destroy', function() { deregisterDragStart(); deregisterDrag(); deregisterDragEnd(); }); function initGhost() { var pid, calendarData; // Expose ghost block to the scope scope.block = Component.$ghost; calendarData = calendarDayCtrl.calendarData(); if (calendarData) { // A calendar is associated to the day; this is a special multicolumn day view calendarNumber = calendarData.index; pid = calendarData.pid; originalCalendarNumber = scope.block.pointerHandler.originalCalendar.index; } if (!pid) pid = scope.block.component.pid; // Set background color iElement.addClass('bg-folder' + pid); } function hideGhost() { // Remove background color _.forEachRight(domElement.classList, function(c) { if (/^bg-folder/.test(c)) iElement.removeClass(c); }); // Hide ghost iElement.addClass('ng-hide'); } function updateGhost() { // From SOGoEventDragGhostController._updateGhosts var showGhost, isRelative, originalDay, currentDay, wasOtherBlock, start, duration, durationLeft, maxDuration, enableTransition; showGhost = false; enableTransition = function() { iElement.removeClass('sg-event--notransition'); }; if (Calendar.$view && Calendar.$view.type == scrollViewCtrl.type) { // The view of the dragging block is the scrolling view of this ghost block isRelative = scrollViewCtrl.type === 'multiday-allday'; originalDay = scope.block.pointerHandler.originalEventCoordinates.dayNumber; currentDay = scope.block.pointerHandler.currentEventCoordinates.dayNumber; start = scope.block.pointerHandler.currentEventCoordinates.start; durationLeft = scope.block.pointerHandler.currentEventCoordinates.duration; maxDuration = CalendarSettings.EventDragDayLength - start; if (angular.isUndefined(durationLeft)) return; duration = durationLeft; if (duration > maxDuration) duration = maxDuration; if (currentDay > -1 && // pointer is inside viewport ((calendarNumber < 0 && // day is not associated to a calendar currentDay == calendarDayCtrl.dayNumber) || // pointer is inside ghost's day currentDay == calendarNumber && // pointer is inside ghost's calendar (originalCalendarNumber == calendarNumber || // still inside original calendar !scope.block.component.isException) // not an exception, event can be moved to a // different calendar )) { // This ghost block (day) is the first of the dragging event showGhost = true; if (!isRelative) { // Show start hour and set the vertical position scope.block.startHour = getStartTime(start); wasOtherBlock = parseInt(iElement.css('top')) === 0; if (wasOtherBlock) iElement.addClass('sg-event--notransition'); // Set the height if (Calendar.$view.quarterHeight) { iElement.css('top', (start * Calendar.$view.quarterHeight) + 'px'); iElement.css('height', (duration * Calendar.$view.quarterHeight) + 'px'); } else iElement.css('top', Calendar.$view.topOffset + 'px'); if (wasOtherBlock) $timeout(enableTransition); } iElement.removeClass('fg-folder' + scope.block.component.pid); iElement.removeClass('sg-event--ghost--last'); iElement.addClass('sg-event--ghost--first'); } durationLeft -= duration; currentDay++; // Search a subsequent block that matches the current ghost's day while (!showGhost && durationLeft && currentDay <= calendarDayCtrl.dayNumber) { duration = durationLeft; if (duration > CalendarSettings.EventDragDayLength) duration = CalendarSettings.EventDragDayLength; if (currentDay > -1 && currentDay == calendarDayCtrl.dayNumber) { // The dragging event overlaps this current ghost's day showGhost = true; if (!isRelative) { wasOtherBlock = parseInt(iElement.css('top')) !== 0; if (wasOtherBlock) iElement.addClass('sg-event--notransition'); iElement.css('top', Calendar.$view.topOffset + 'px'); // Set the height if (Calendar.$view.quarterHeight) iElement.css('height', (duration * Calendar.$view.quarterHeight) + 'px'); if (wasOtherBlock) $timeout(enableTransition); } iElement.removeClass('sg-event--ghost--first'); iElement.removeClass('sg-event--ghost--last'); // Trick for all-day events: set the foreground color to the background color so the event's title // is not visible but the div size remains identical. iElement.addClass('fg-folder' + scope.block.component.pid); } durationLeft -= duration; currentDay++; start = 0; } if (!durationLeft) { // Reached last ghost block if (isRelative) { iElement.addClass('sg-event--ghost--last'); } else { // Set the end date scope.block.endHour = getEndTime(start, duration); } } } if (showGhost) iElement.removeClass('ng-hide'); else iElement.addClass('ng-hide'); } function quartersToHM(quarters) { var minutes, hours, mins; minutes = quarters * 15; hours = Math.floor(minutes / 60); if (hours < 10) hours = "0" + hours; mins = minutes % 60; if (mins < 10) mins = "0" + mins; return "" + hours + ":" + mins; } function getStartTime(start) { return quartersToHM(start); } function getEndTime(start, duration) { var end = (start + duration) % CalendarSettings.EventDragDayLength; return quartersToHM(end); } } } angular .module('SOGo.SchedulerUI') .directive('sgCalendarGhost', sgCalendarGhost); })();