diff --git a/NEWS b/NEWS index 31dff2ac9..1386162b2 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Enhancements - [web] disable JavaScript theme generation when SOGoUIxDebugEnabled is set to NO - [web] added Serbian (sr) translation - thanks to Bogdanović Bojan - [web] added sort by arrival date in Mail module (#708) + - [web] restored "now" line in Calendar module - [web] updated CKEditor to version 4.5.11 - [eas] propagate message submission errors to EAS clients (#3774) diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index ee7a02d03..ba5fdbc5c 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -98,7 +98,7 @@
-
+
= i; j--) + vm.views.splice(j, 1); }); } diff --git a/UI/WebServerResources/js/Scheduler/sgCalendarScrollView.directive.js b/UI/WebServerResources/js/Scheduler/sgCalendarScrollView.directive.js index 77f08ea0e..710086c00 100644 --- a/UI/WebServerResources/js/Scheduler/sgCalendarScrollView.directive.js +++ b/UI/WebServerResources/js/Scheduler/sgCalendarScrollView.directive.js @@ -25,10 +25,15 @@ }, controller: sgCalendarScrollViewController, link: function(scope, element, attrs, controller) { - var view, type; + var view, type, isMultiColumn = false; view = null; type = scope.type; // multiday, multiday-allday, monthly, unknown? + isMultiColumn = (element.attr('sg-view') == 'multicolumndayview'); + + // Expose isMultiColumn in the controller + // See sgNowLine directive + controller.isMultiColumn = isMultiColumn; // Update the "view" object literal once the Angular template has been transformed $timeout(initView); @@ -54,6 +59,10 @@ view.element.scrollTop = hourCell.offsetTop + quartersOffset; } }); + + // Expose quarter height to the controller + // See sgNowLine directive + controller.quarterHeight = view.quarterHeight; } /** @@ -133,11 +142,8 @@ getDayNumbers: function() { - var viewType = null, isMultiColumn, days, total, sum; + var viewType = null, days, total, sum; - if (this.element.attributes['sg-view']) - viewType = this.element.attributes['sg-view'].value; - isMultiColumn = (viewType == 'multicolumndayview'); days = this.element.getElementsByTagName('sg-calendar-day'); return _.map(days, function(el, index) { diff --git a/UI/WebServerResources/js/Scheduler/sgNowLine.directive.js b/UI/WebServerResources/js/Scheduler/sgNowLine.directive.js new file mode 100644 index 000000000..037208623 --- /dev/null +++ b/UI/WebServerResources/js/Scheduler/sgNowLine.directive.js @@ -0,0 +1,112 @@ +/* -*- Mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */ + +(function() { + /* jshint validthis: true */ + 'use strict'; + + /* + * sgNowLine - Now line to be displayed on top of current day + * @restrict class + */ + function sgNowLine() { + return { + restrict: 'C', + require: '^^sgCalendarScrollView', + link: link, + controller: sgNowLineController + }; + + function link(scope, iElement, iAttr, sgCalendarScrollViewCtrl) { + function _getDays() { + return iElement.find('sg-calendar-day'); + } + function _getView() { + return sgCalendarScrollViewCtrl.quarterHeight; + } + + // We need to wait for the view to be compiled + var _unwatchView = scope.$watch(_getView, function(quarterHeight) { + if (quarterHeight) { + _unwatchView(); // self release + scope.quarterHeight = quarterHeight; + // We need to wait for the days to be compiled + var _unwatchDays = scope.$watch(_getDays, function(days) { + if (days.length) { + _unwatchDays(); // self release + scope.days = days; + // Draw the line + scope.updateLine(); + } + }); + } + }); + } + } + + /** + * @ngInject + */ + sgNowLineController.$inject = ['$scope', '$element', '$timeout']; + function sgNowLineController($scope, $element, $timeout) { + var _this = this, updater, + scrollViewCtrl = $element.controller('sgCalendarScrollView'); + + $scope.nowDay = null; + $scope.lineElement = null; + $scope.updateLine = _updateLine; + + $scope.$on('$destroy', function() { + if (updater) + $timeout.cancel(updater); + }); + + + function _updateLine(force) { + var now = new Date(), // TODO: adjust to user's timezone + nowDay = now.getDayString(), + hours = now.getHours(), + hourHeight = $scope.quarterHeight * 4, + minutes = now.getMinutes(), + minuteHeight = $scope.quarterHeight/15, + position = parseInt(hours * hourHeight + + minutes * minuteHeight - + 1); + + if (force || nowDay != $scope.nowDay) { + if ($scope.lineElement) + $scope.lineElement.remove(); + $scope.lineElement = _addLine(nowDay, $scope.days); + $scope.nowDay = nowDay; + } + + if ($scope.lineElement) { + // Current day is displayed + $scope.lineElement.css('top', position + "px"); + // Update line every minute + updater = $timeout(angular.bind(_this, $scope.updateLine), 60000); + } + } + + function _addLine(nowDay, days) { + var $lineElement = angular.element(''); + + if (scrollViewCtrl.isMultiColumn) { + // In multicolumn day view, the line must go over all columns + if (days && days[0].attributes['sg-day'].value == nowDay) + $element.append($lineElement); + } + else + _.forEach(days, function(dayElement) { + if (dayElement.attributes['sg-day'].value == nowDay) { + angular.element(dayElement).find('div').eq(0).append($lineElement); + } + }); + + return $lineElement; + } + } + + angular + .module('SOGo.SchedulerUI') + .directive('sgNowLine', sgNowLine); +})(); diff --git a/UI/WebServerResources/scss/views/SchedulerUI.scss b/UI/WebServerResources/scss/views/SchedulerUI.scss index 7762fab0e..da484f965 100644 --- a/UI/WebServerResources/scss/views/SchedulerUI.scss +++ b/UI/WebServerResources/scss/views/SchedulerUI.scss @@ -240,6 +240,16 @@ $quarter_height: 10px; position: relative; } + // The "now" line that overlaps the current day in day/week/multicolumn views + sg-now-line { + display: block; + position: absolute; + width: 100%; + height: 2px; + background: red; + z-index: $z-index-view + 1; + } + // Events from editable calendars are draggable .sg-draggable-calendar-block, .sg-event--ghost { @@ -697,4 +707,4 @@ $quarter_height: 10px; background-color: sg-color($sogoBlue, 300); } } -} \ No newline at end of file +}