sogo/UI/WebServerResources/js/Scheduler.js.map
2015-12-11 15:44:55 -05:00

1 line
124 KiB
Plaintext

{"version":3,"sources":["Scheduler/Scheduler.app.js","Scheduler/CalendarController.js","Scheduler/CalendarListController.js","Scheduler/CalendarsController.js","Scheduler/ComponentController.js","Scheduler/sgCalendarDay.directive.js","Scheduler/sgCalendarDayBlock.directive.js","Scheduler/sgCalendarDayTable.directive.js","Scheduler/sgCalendarGhost.directive.js","Scheduler/sgCalendarMonthDay.directive.js","Scheduler/sgCalendarMonthEvent.directive.js","Scheduler/sgCalendarScrollView.directive.js","Scheduler/sgCalendarTable.directive.js","Scheduler/sgCategoryStylesheet.directive.js","Scheduler/sgDraggableCalendarBlock.directive.js","Scheduler/sgDroppableBlock.directive.js"],"names":["configure","$stateProvider","$urlRouterProvider","state","url","views","calendars","templateUrl","controller","controllerAs","resolve","stateCalendars","calendarView","$stateParams","view","day","stateEventsBlocks","when","now","Date","getDayString","otherwise","Calendar","$calendars","$findAll","window","calendarsData","Component","$eventsBlocksForView","asDate","then","_","forEach","id","calendar","name","calendarName","runBlock","$rootScope","$log","$location","$state","Preferences","$on","event","toState","toParams","fromState","fromParams","error","go","current","previous","rejection","length","ready","exec","settings","View","replace","angular","module","config","run","$inject","CalendarController","$scope","updateView","data","vm","changeView","$event","date","element","currentTarget","attr","deregisterCalendarsList","this","CalendarListController","$timeout","$mdDialog","Dialog","selectComponentType","type","options","reload","componentType","isUndefined","$filter","unselectComponents","saveSelectedList","each","component","selected","selectAll","toggleComponentSelection","preventDefault","stopPropagation","confirmDeleteSelectedComponents","confirm","l","components","filter","$deleteComponents","status","openEvent","openComponent","openTask","task","viewable","capitalize","show","parent","document","body","targetEvent","clickOutsideToClose","escapeToClose","locals","stateComponent","newComponent","baseComponent","pid","updateComponentFromGhost","RecurrentComponentDialogController","params","updateThisOccurrence","$adjust","hide","cancel","updateAllOccurrences","occurrenceId","pointerHandler","coordinates","delta","$ghost","isNew","currentEventCoordinates","isAllDay","duration","setDelta","getDelta","originalEventCoordinates","days","dayNumber","start","isException","$emit","template","join","filterpopup","filteredBy","sort","field","sortedBy","cancelSearch","mode","search","value","selectedList","SelectedList","CalendarsController","$window","$mdToast","FileUploader","focus","Settings","User","newCalendar","ev","prompt","isEditable","isRemote","owner","UserLogin","$id","$add","addWebCalendar","inputType","$addWebCalendar","confirmDelete","folder","isSubscription","$delete","alert","importCalendar","CalendarImportDialogController","scope","filterByExtension","item","isTextFile","indexOf","test","position","hideDelay","uploader","ApplicationBaseURL","autoUpload","queueLimit","filters","fn","onSuccessItem","response","headers","msg","imported","simple","content","onErrorItem","close","exportCalendar","location","href","showLinks","LinksDialogController","showProperties","PropertiesDialogController","srcCalendar","saveProperties","$save","init","$omit","$watch","color","editFolder","editMode","revertEditing","$reset","renameFolder","$rename","share","$acl","$users","usersWithACL","users","subscribeToFolder","calendarData","debug","$subscribe","today","fragments","hash","split","path","activeUser","service","categories","map","defaults","SOGoCalendarCategories","asCSSIdentifier","SOGoCalendarCategoriesColors","union","o","pick","$subscriptions","$webcalendars","newList","oldList","ids","pluck","i","isEqual","$get","$setActivation","ComponentController","AddressBook","Alarm","cardFilter","$query","$filterAll","$cards","edit","editAllOccurrences","$getComponent","$futureComponentData","reply","c","$reply","getAlarms","replyAllOccurrences","delegatedTo","$hasAlarm","alarm","deleteOccurrence","remove","deleteAllOccurrences","toggleRawSource","$$resource","post","ComponentRawSourceDialogController","organizer","ComponentEditorController","Card","addAttachUrl","toggleRecurrenceEditor","showRecurrenceEditor","$hasCustomRepeat","toggleAttendeesEditor","showAttendeesEditor","addAttendee","card","isString","isValidEmail","emails","searchText","save","form","$valid","getDays","end","daysUpTo","stringWithSeparator","getHours","hours","push","toString","addStartDate","$addStartDate","oldStartDate","getTime","addDueDate","$addDueDate","oldDueDate","due","updateStartTime","addMinutes","getMinutes","adjustStartTime","valueOf","oldEndDate","updateFreeBusy","updateEndTime","adjustEndTime","minutesTo","updateDueTime","adjustDueTime","attendeesEditor","isDefined","attendees","sgCalendarDay","restrict","dayString","sgCalendarDayController","directive","sgCalendarDayBlock","CalendarSettings","link","iElement","attrs","pc","left","right","block","siblings","css","addClass","clickBlock","sgCalendarDayTable","blocks","sgCalendarGhost","ctrls","initGhost","hideGhost","forEachRight","domElement","classList","removeClass","updateGhost","showGhost","isRelative","originalDay","currentDay","wasOtherBlock","durationLeft","maxDuration","enableTransition","$view","scrollViewCtrl","EventDragDayLength","startHour","endHour","calendarDayCtrl","getStartTime","parseInt","quarterHeight","topOffset","getEndTime","quartersToHM","quarters","minutes","mins","Math","floor","deregisterDragStart","deregisterDrag","deregisterDragEnd","require","sgCalendarMonthDay","sgCalendarMonthEvent","sgCalendarScrollView","$document","$q","$mdGesture","sgCalendarScrollViewController","initView","getQuarterHeight","scrollStep","maxX","getMaxColumns","scrollView","on","updateCoordinates","time","hourCell","quartersOffset","SOGoDayStartTime","getElementById","scrollTop","offsetTop","hour0","hour23","height","getDayDimensions","viewLeft","width","leftOffset","nodes","domRect","tileHeader","getElementsByClassName","getBoundingClientRect","clientHeight","offset","top","max","dayDimensions","extend","x","y","dayHeight","dayWidth","daysOffset","onDragStart","updateFromPointerHandler","onDragEnd","off","pointerCoordinates","scrollY","minY","getContainerBasedCoordinates","lastScroll","deregisterDragStop","sgCalendarTable","blocksType","sgCategoryStylesheet","ngModel","sgDraggableCalendarBlock","initGrips","blockIndex","isFirstBlock","isLastBlock","dragGrip","leftGrip","rightGrip","topGrip","bottomGrip","findIndex","matchesProperty","c_isallday","parentNode","tagName","append","clone","onDragDetect","dragMode","target","className","SOGoEventDragPointerHandler","initFromEvent","one","onDrag","dragStart","eventType","isHourCell","isMonthly","startDate","newData","hasClass","substring","summary","b","dragging","prepareWithEventType","initFromBlock","starthour","updateFromEvent","pointer","dragHasStarted","SOGoCoordinates","SOGoEventDragEventCoordinates","setEventType","editable","prototype","otherCoordinates","getDistance","sqrt","sum","_quartersToHM","originalCoordinates","currentCoordinates","originalViewCoordinates","currentViewCoordinates","getEventViewCoordinates","pageX","pageY","newEventCoordinates","setTimeFromQuarters","updateEventCoordinates","distance","newDuration","deltaQuarters","deltaDays","ceil","JSON","stringify","container","clientWidth","methods","multiday","getEventMultiDayViewCoordinates","multiday-allday","getEventMultiDayAllDayViewCoordinates","monthly","getEventMonthlyViewCoordinates","unknown","method","pxCoordinates","EventDragHorizontalOffset","maxY","daysTopOffset","daysY","setHours","sgDroppableBlock","onDrop","deregister"],"mappings":"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","file":"Scheduler.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n/* JavaScript for SOGo.SchedulerUI module */\n\n(function() {\n 'use strict';\n\n angular.module('SOGo.SchedulerUI', ['ngSanitize', 'ui.router', 'angularFileUpload', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.ContactsUI', 'SOGo.MailerUI'])\n .config(configure)\n .run(runBlock);\n\n /**\n * @ngInject\n */\n configure.$inject = ['$stateProvider', '$urlRouterProvider'];\n function configure($stateProvider, $urlRouterProvider) {\n $stateProvider\n .state('calendars', {\n url: '/calendar',\n views: {\n calendars: {\n templateUrl: 'UIxCalMainView', // UI/Templates/SchedulerUI/UIxCalMainView.wox\n controller: 'CalendarsController',\n controllerAs: 'app'\n }\n },\n resolve: {\n stateCalendars: stateCalendars\n }\n })\n .state('calendars.view', {\n url: '/{view:(?:day|week|month|multicolumnday)}/:day',\n //sticky: true,\n //deepStateRedirect: true,\n views: {\n calendarView: {\n templateUrl: function($stateParams) {\n // UI/Templates/SchedulerUI/UIxCalDayView.wox or\n // UI/Templates/SchedulerUI/UIxCalWeekView.wox or\n // UI/Templates/SchedulerUI/UIxCalMonthView.wox or\n // UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox\n return $stateParams.view + 'view?day=' + $stateParams.day;\n },\n controller: 'CalendarController',\n controllerAs: 'calendar'\n }\n },\n resolve: {\n stateEventsBlocks: stateEventsBlocks\n }\n });\n\n $urlRouterProvider.when('/calendar/day', function() {\n // If no date is specified, show today\n var now = new Date();\n return '/calendar/day/' + now.getDayString();\n });\n $urlRouterProvider.when('/calendar/multicolumnday', function() {\n // If no date is specified, show today\n var now = new Date();\n return '/calendar/multicolumnday/' + now.getDayString();\n });\n $urlRouterProvider.when('/calendar/week', function() {\n // If no date is specified, show today's week\n var now = new Date();\n return '/calendar/week/' + now.getDayString();\n });\n $urlRouterProvider.when('/calendar/month', function() {\n // If no date is specified, show today's month\n var now = new Date();\n return '/calendar/month/' + now.getDayString();\n });\n\n // If none of the above states are matched, use this as the fallback.\n // runBlock will also act as a fallback by looking at user's settings\n $urlRouterProvider.otherwise('/calendar');\n }\n\n /**\n * @ngInject\n */\n stateCalendars.$inject = ['Calendar'];\n function stateCalendars(Calendar) {\n return Calendar.$calendars || Calendar.$findAll(window.calendarsData);\n }\n\n /**\n * @ngInject\n */\n stateEventsBlocks.$inject = ['$stateParams', 'Component', 'Calendar', ];\n function stateEventsBlocks($stateParams, Component, Calendar) {\n // See CalendarController.js\n return Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate())\n .then(function(views) {\n _.forEach(views, function(view) {\n if (view.id) {\n // Note: this can't be done in Component service since it would make Component dependent on\n // the Calendar service and create a circular dependency\n view.calendar = new Calendar({ id: view.id, name: view.calendarName });\n }\n });\n return views;\n });\n }\n\n /**\n * @ngInject\n */\n runBlock.$inject = ['$rootScope', '$log', '$location', '$state', 'Preferences'];\n function runBlock($rootScope, $log, $location, $state, Preferences) {\n $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {\n $log.error(error);\n $state.go('calendar');\n });\n $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {\n $log.error(event, current, previous, rejection);\n });\n if ($location.url().length === 0) {\n // Restore user's last view\n Preferences.ready().then(function() {\n var url = '/calendar/',\n view = /(.+)view/.exec(Preferences.settings.Calendar.View);\n if (view)\n url += view[1];\n else\n url += 'week';\n $location.replace().url(url);\n });\n }\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n CalendarController.$inject = ['$scope', '$rootScope', '$state', '$stateParams', 'Calendar', 'Component', 'stateEventsBlocks'];\n function CalendarController($scope, $rootScope, $state, $stateParams, Calendar, Component, stateEventsBlocks) {\n var vm = this, deregisterCalendarsList;\n\n vm.views = stateEventsBlocks;\n vm.changeView = changeView;\n\n // Refresh current view when the list of calendars is modified\n deregisterCalendarsList = $rootScope.$on('calendars:list', updateView);\n\n $scope.$on('$destroy', deregisterCalendarsList);\n\n function updateView() {\n // See stateEventsBlocks in Scheduler.app.js\n Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function(data) {\n vm.views = data;\n _.forEach(vm.views, function(view) {\n if (view.id) {\n // Note: this can't be done in Component service since it would make Component dependent on\n // the Calendar service and create a circular dependency\n view.calendar = new Calendar({ id: view.id, name: view.calendarName });\n }\n });\n });\n }\n\n // Change calendar's view\n function changeView($event) {\n var date = angular.element($event.currentTarget).attr('date');\n $state.go('calendars.view', { view: $stateParams.view, day: date });\n }\n }\n\n angular\n .module('SOGo.SchedulerUI') \n .controller('CalendarController', CalendarController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n CalendarListController.$inject = ['$rootScope', '$timeout', '$state', '$mdDialog', 'Dialog', 'Preferences', 'Calendar', 'Component'];\n function CalendarListController($rootScope, $timeout, $state, $mdDialog, Dialog, Preferences, Calendar, Component) {\n var vm = this;\n\n vm.component = Component;\n vm.componentType = 'events';\n vm.selectedList = 0;\n vm.selectComponentType = selectComponentType;\n vm.unselectComponents = unselectComponents;\n vm.selectAll = selectAll;\n vm.toggleComponentSelection = toggleComponentSelection;\n vm.confirmDeleteSelectedComponents = confirmDeleteSelectedComponents;\n vm.openEvent = openEvent;\n vm.openTask = openTask;\n vm.newComponent = newComponent;\n vm.filter = filter;\n vm.filteredBy = filteredBy;\n vm.sort = sort;\n vm.sortedBy = sortedBy;\n vm.reload = reload;\n vm.cancelSearch = cancelSearch;\n vm.mode = { search: false };\n\n // Select list based on user's settings\n Preferences.ready().then(function() {\n var type = 'events';\n if (Preferences.settings.Calendar.SelectedList == 'tasksListView') {\n vm.selectedList = 1;\n type = 'tasks';\n }\n selectComponentType(type, { reload: true });\n });\n\n // Refresh current list when the list of calendars is modified\n $rootScope.$on('calendars:list', function() {\n Component.$filter(vm.componentType, { reload: true });\n });\n\n // Update the component being dragged\n $rootScope.$on('calendar:dragend', updateComponentFromGhost);\n\n // Switch between components tabs\n function selectComponentType(type, options) {\n if (options && options.reload || vm.componentType != type) {\n if (angular.isUndefined(Component['$' + type]))\n Component.$filter(type);\n vm.unselectComponents();\n vm.componentType = type;\n Component.saveSelectedList(type);\n }\n }\n\n function unselectComponents() {\n _.each(Component['$' + vm.componentType], function(component) { component.selected = false; });\n }\n\n function selectAll() {\n _.each(Component['$' + vm.componentType], function(component) {\n component.selected = true;\n });\n }\n\n function toggleComponentSelection($event, component) {\n component.selected = !component.selected;\n $event.preventDefault();\n $event.stopPropagation();\n }\n\n function confirmDeleteSelectedComponents() {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the selected components?'))\n .then(function() {\n // User confirmed the deletion\n var components = _.filter(Component['$' + vm.componentType], function(component) { return component.selected; });\n Calendar.$deleteComponents(components);\n }, function(data, status) {\n // Delete failed\n });\n }\n\n function openEvent($event, event) {\n openComponent($event, event, 'appointment');\n }\n\n function openTask($event, task) {\n openComponent($event, task, 'task');\n }\n\n function openComponent($event, component, type) {\n if (component.viewable) {\n // UI/Templates/SchedulerUI/UIxAppointmentViewTemplate.wox or\n // UI/Templates/SchedulerUI/UIxTaskViewTemplate.wox\n var templateUrl = 'UIx' + type.capitalize() + 'ViewTemplate';\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: templateUrl,\n controller: 'ComponentController',\n controllerAs: 'editor',\n locals: {\n stateComponent: component\n }\n });\n }\n }\n\n function newComponent($event, baseComponent) {\n var type = 'appointment', component;\n\n if (baseComponent) {\n component = baseComponent;\n type = baseComponent.type;\n }\n else {\n // TODO respect SOGoDefaultCalendar\n if (vm.componentType == 'tasks')\n type = 'task';\n component = new Component({ pid: 'personal', type: type });\n }\n\n // UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox or\n // UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox\n var templateUrl = 'UIx' + type.capitalize() + 'EditorTemplate';\n return $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: templateUrl,\n controller: 'ComponentEditorController',\n controllerAs: 'editor',\n locals: {\n stateComponent: component\n }\n });\n }\n\n // Adjust component or create new component through drag'n'drop\n function updateComponentFromGhost($event) {\n var component, pointerHandler, coordinates, delta, params;\n\n component = Component.$ghost.component;\n pointerHandler = Component.$ghost.pointerHandler;\n\n if (component.isNew) {\n coordinates = pointerHandler.currentEventCoordinates;\n if (component.isAllDay)\n coordinates.duration -= 96;\n component.setDelta(coordinates.duration * 15);\n newComponent(null, component).finally(function() {\n $timeout(function() {\n Component.$ghost.pointerHandler = null;\n Component.$ghost.component = null;\n });\n });\n }\n else {\n delta = pointerHandler.currentEventCoordinates.getDelta(pointerHandler.originalEventCoordinates);\n params = {\n days: delta.dayNumber,\n start: delta.start * 15,\n duration: delta.duration * 15\n };\n if (component.isException || !component.occurrenceId)\n // Component is an exception to a recurrence or is not recurrent;\n // Immediately perform the adjustments\n component.$adjust(params).then(function() {\n $rootScope.$emit('calendars:list');\n $timeout(function() {\n Component.$ghost = {};\n });\n });\n else if (component.occurrenceId) {\n $mdDialog.show({\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n component: component,\n params: params\n },\n template: [\n '<md-dialog flex=\"50\" md-flex=\"80\" sm-flex=\"90\">',\n ' <md-dialog-content class=\"md-dialog-content\">',\n ' <p>' + l('editRepeatingItem') + '</p>',\n ' </md-dialog-content>',\n ' <md-dialog-actions>',\n ' <md-button ng-click=\"updateThisOccurrence()\">' + l('button_thisOccurrenceOnly') + '</md-button>',\n ' <md-button ng-click=\"updateAllOccurrences()\">' + l('button_allOccurrences') + '</md-button>',\n ' </md-dialog-actions>',\n '</md-dialog>'\n ].join(''),\n controller: RecurrentComponentDialogController\n }).then(function() {\n $rootScope.$emit('calendars:list');\n }).finally(function() {\n $timeout(function() {\n Component.$ghost = {};\n });\n });\n }\n }\n\n /**\n * @ngInject\n */\n RecurrentComponentDialogController.$inject = ['$scope', '$mdDialog', 'component', 'params'];\n function RecurrentComponentDialogController($scope, $mdDialog, component, params) {\n $scope.updateThisOccurrence = function() {\n component.$adjust(params).then($mdDialog.hide, $mdDialog.cancel);\n };\n $scope.updateAllOccurrences = function() {\n delete component.occurrenceId;\n component.$adjust(params).then($mdDialog.hide, $mdDialog.cancel);\n };\n }\n }\n\n function filter(filterpopup) {\n Component.$filter(vm.componentType, { filterpopup: filterpopup });\n }\n\n function filteredBy(filterpopup) {\n return Component['$query' + vm.componentType.capitalize()].filterpopup == filterpopup;\n }\n\n function sort(field) {\n Component.$filter(vm.componentType, { sort: field });\n }\n\n function sortedBy(field) {\n return Component['$query' + vm.componentType.capitalize()].sort == field;\n }\n\n function reload() {\n $rootScope.$emit('calendars:list');\n }\n\n function cancelSearch() {\n vm.mode.search = false;\n Component.$filter(vm.componentType, { value: '' });\n }\n }\n \n angular\n .module('SOGo.SchedulerUI')\n .controller('CalendarListController', CalendarListController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n CalendarsController.$inject = ['$rootScope', '$scope', '$window', '$mdDialog', '$log', '$mdToast', 'FileUploader', 'sgFocus', 'Dialog', 'sgSettings', 'Preferences', 'Calendar', 'User', 'stateCalendars'];\n function CalendarsController($rootScope, $scope, $window, $mdDialog, $log, $mdToast, FileUploader, focus, Dialog, Settings, Preferences, Calendar, User, stateCalendars) {\n var vm = this;\n\n vm.activeUser = Settings.activeUser;\n vm.service = Calendar;\n vm.newCalendar = newCalendar;\n vm.addWebCalendar = addWebCalendar;\n vm.confirmDelete = confirmDelete;\n vm.editFolder = editFolder;\n vm.revertEditing = revertEditing;\n vm.renameFolder = renameFolder;\n vm.share = share;\n vm.importCalendar = importCalendar;\n vm.exportCalendar = exportCalendar;\n vm.showLinks = showLinks;\n vm.showProperties = showProperties;\n vm.subscribeToFolder = subscribeToFolder;\n vm.today = today;\n\n Preferences.ready().then(function() {\n vm.categories = _.map(Preferences.defaults.SOGoCalendarCategories, function(name) {\n return { id: name.asCSSIdentifier(),\n name: name,\n color: Preferences.defaults.SOGoCalendarCategoriesColors[name]\n };\n });\n });\n\n // Dispatch the event named 'calendars:list' when a calendar is activated or deactivated or\n // when the color of a calendar is changed\n $scope.$watch(\n function() {\n return _.union(\n _.map(Calendar.$calendars, function(o) { return _.pick(o, ['id', 'active', 'color']); }),\n _.map(Calendar.$subscriptions, function(o) { return _.pick(o, ['id', 'active', 'color']); }),\n _.map(Calendar.$webcalendars, function(o) { return _.pick(o, ['id', 'active', 'color']); })\n );\n },\n function(newList, oldList) {\n // Identify which calendar has changed\n var ids = _.pluck(_.filter(newList, function(o, i) { return !_.isEqual(o, oldList[i]); }), 'id');\n if (ids.length > 0) {\n $log.debug(ids.join(', ') + ' changed');\n _.each(ids, function(id) {\n var calendar = Calendar.$get(id);\n calendar.$setActivation().then(function() {\n $rootScope.$emit('calendars:list');\n });\n });\n }\n },\n true // compare for object equality\n );\n\n function newCalendar(ev) {\n Dialog.prompt(l('New calendar'), l('Name of the Calendar'))\n .then(function(name) {\n var calendar = new Calendar(\n {\n name: name,\n isEditable: true,\n isRemote: false,\n owner: UserLogin\n }\n );\n calendar.$id().then(function() {\n Calendar.$add(calendar);\n });\n });\n }\n\n function addWebCalendar() {\n Dialog.prompt(l('Subscribe to a web calendar...'), l('URL of the Calendar'), {inputType: 'url'})\n .then(function(url) {\n Calendar.$addWebCalendar(url);\n });\n }\n\n function confirmDelete(folder) {\n if (folder.isSubscription) {\n // Unsubscribe without confirmation\n folder.$delete()\n .then(function() {\n $rootScope.$emit('calendars:list');\n }, function(data, status) {\n Dialog.alert(l('An error occured while deleting the calendar \"%{0}\".', folder.name),\n l(data.error));\n });\n }\n else {\n Dialog.confirm(l('Warning'), l('Are you sure you want to delete the calendar <em>%{0}</em>?', folder.name))\n .then(function() {\n folder.$delete()\n .then(function() {\n $rootScope.$emit('calendars:list');\n }, function(data, status) {\n Dialog.alert(l('An error occured while deleting the calendar \"%{0}\".', folder.name),\n l(data.error));\n });\n });\n }\n }\n\n function importCalendar($event, folder) {\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: 'UIxCalendarImportDialog',\n controller: CalendarImportDialogController,\n controllerAs: '$CalendarImportDialogController',\n locals: {\n folder: folder\n }\n });\n\n /**\n * @ngInject\n */\n CalendarImportDialogController.$inject = ['scope', '$mdDialog', 'folder'];\n function CalendarImportDialogController(scope, $mdDialog, folder) {\n var vm = this;\n\n vm.uploader = new FileUploader({\n url: ApplicationBaseURL + [folder.id, 'import'].join('/'),\n autoUpload: true,\n queueLimit: 1,\n filters: [{ name: filterByExtension, fn: filterByExtension }],\n onSuccessItem: function(item, response, status, headers) {\n var msg;\n\n $mdDialog.hide();\n\n if (response.imported === 0)\n msg = l('No event was imported.');\n else {\n msg = l('A total of %{0} events were imported in the calendar.', response.imported);\n $rootScope.$emit('calendars:list');\n }\n\n $mdToast.show(\n $mdToast.simple()\n .content(msg)\n .position('top right')\n .hideDelay(3000));\n },\n onErrorItem: function(item, response, status, headers) {\n $mdToast.show({\n template: [\n '<md-toast>',\n ' <div class=\"md-toast-content\">',\n ' <md-icon class=\"md-warn md-hue-1\">error_outline</md-icon>',\n ' <span>' + l('An error occurred while importing calendar.') + '</span>',\n ' </div>',\n '</md-toast>'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n }\n });\n\n vm.close = function() {\n $mdDialog.hide();\n };\n\n function filterByExtension(item) {\n var isTextFile = item.type.indexOf('text') === 0 ||\n /\\.(ics)$/.test(item.name);\n\n if (!isTextFile)\n $mdToast.show({\n template: [\n '<md-toast>',\n ' <div class=\"md-toast-content\">',\n ' <md-icon class=\"md-warn md-hue-1\">error_outline</md-icon>',\n ' <span>' + l('Select an iCalendar file (.ics).') + '</span>',\n ' </div>',\n '</md-toast>'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n\n return isTextFile;\n }\n }\n }\n\n function exportCalendar(calendar) {\n window.location.href = ApplicationBaseURL + '/' + calendar.id + '.ics' + '/export';\n }\n\n function showLinks(calendar) {\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: calendar.id + '/links',\n controller: LinksDialogController,\n controllerAs: 'links',\n locals: {\n calendar: calendar\n }\n });\n \n /**\n * @ngInject\n */\n LinksDialogController.$inject = ['$mdDialog', 'calendar'];\n function LinksDialogController($mdDialog, calendar) {\n var vm = this;\n vm.calendar = calendar;\n vm.close = close;\n\n function close() {\n $mdDialog.hide();\n }\n }\n }\n\n function showProperties(calendar) {\n var color = calendar.color;\n $mdDialog.show({\n templateUrl: calendar.id + '/properties',\n controller: PropertiesDialogController,\n controllerAs: 'properties',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n srcCalendar: calendar\n }\n }).catch(function() {\n // Restore original color when cancelling or closing the dialog\n calendar.color = color;\n });\n \n /**\n * @ngInject\n */\n PropertiesDialogController.$inject = ['$scope', '$mdDialog', 'srcCalendar'];\n function PropertiesDialogController($scope, $mdDialog, srcCalendar) {\n var vm = this;\n\n vm.calendar = new Calendar(srcCalendar.$omit());\n vm.saveProperties = saveProperties;\n vm.close = close;\n\n $scope.$watch('properties.calendar.color', function() {\n srcCalendar.color = vm.calendar.color;\n });\n\n function saveProperties() {\n vm.calendar.$save();\n // Refresh list instance\n srcCalendar.init(vm.calendar.$omit());\n $mdDialog.hide();\n }\n\n function close() {\n $mdDialog.cancel();\n }\n }\n }\n\n function editFolder(folder) {\n vm.calendarName = folder.name;\n vm.editMode = folder.id;\n focus('calendarName_' + folder.id);\n }\n\n function revertEditing(folder) {\n folder.$reset();\n vm.editMode = false;\n }\n\n function renameFolder(folder) {\n folder.$rename()\n .then(function(data) {\n vm.editMode = false;\n }, function(data, status) {\n Dialog.alert(l('Warning'), data);\n });\n }\n\n function share(calendar) {\n calendar.$acl.$users().then(function() {\n $mdDialog.show({\n templateUrl: calendar.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox\n controller: 'AclController', // from the ng module SOGo.Common\n controllerAs: 'acl',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n usersWithACL: calendar.$acl.users,\n User: User,\n folder: calendar\n }\n });\n });\n }\n\n // Callback of sgSubscribe directive\n function subscribeToFolder(calendarData) {\n $log.debug('subscribeToFolder ' + calendarData.owner + calendarData.name);\n Calendar.$subscribe(calendarData.owner, calendarData.name).then(function(data) {\n $mdToast.show(\n $mdToast.simple()\n .content(l('Sucessfully subscribed to calendar'))\n .position('top right')\n .hideDelay(3000));\n });\n }\n\n function today() {\n var fragments = $window.location.hash.split('/'),\n state = fragments[1],\n view = fragments[2],\n now = new Date(),\n path = ['#', state, view, now.getDayString()];\n $window.location = path.join('/');\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .controller('CalendarsController', CalendarsController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n ComponentController.$inject = ['$rootScope', '$mdDialog', 'Calendar', 'AddressBook', 'Alarm', 'stateComponent'];\n function ComponentController($rootScope, $mdDialog, Calendar, AddressBook, Alarm, stateComponent) {\n var vm = this, component;\n\n vm.component = stateComponent;\n vm.close = close;\n vm.cardFilter = cardFilter;\n vm.edit = edit;\n vm.editAllOccurrences = editAllOccurrences;\n vm.reply = reply;\n vm.replyAllOccurrences = replyAllOccurrences;\n vm.deleteOccurrence = deleteOccurrence;\n vm.deleteAllOccurrences = deleteAllOccurrences;\n vm.toggleRawSource = toggleRawSource;\n\n // Load all attributes of component\n if (angular.isUndefined(vm.component.$futureComponentData)) {\n component = Calendar.$get(vm.component.pid).$getComponent(vm.component.id, vm.component.occurrenceId);\n component.$futureComponentData.then(function() {\n vm.component = component;\n vm.organizer = [vm.component.organizer];\n });\n }\n\n function close() {\n $mdDialog.hide();\n }\n\n // Autocomplete cards for attendees\n function cardFilter($query) {\n AddressBook.$filterAll($query);\n return AddressBook.$cards;\n }\n\n function edit() {\n var type = (vm.component.component == 'vevent')? 'Appointment':'Task';\n $mdDialog.hide().then(function() {\n // UI/Templates/SchedulerUI/UIxAppointmentEditorTemplate.wox or\n // UI/Templates/SchedulerUI/UIxTaskEditorTemplate.wox\n var templateUrl = 'UIx' + type + 'EditorTemplate';\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: templateUrl,\n controller: 'ComponentEditorController',\n controllerAs: 'editor',\n locals: {\n stateComponent: vm.component\n }\n });\n });\n }\n\n function editAllOccurrences() {\n component = Calendar.$get(vm.component.pid).$getComponent(vm.component.id);\n component.$futureComponentData.then(function() {\n vm.component = component;\n edit();\n });\n }\n\n function reply(component) {\n var c = component || vm.component;\n\n c.$reply().then(function() {\n $rootScope.$emit('calendars:list');\n $mdDialog.hide();\n Alarm.getAlarms();\n });\n }\n\n function replyAllOccurrences() {\n // Retrieve master event\n component = Calendar.$get(vm.component.pid).$getComponent(vm.component.id);\n component.$futureComponentData.then(function() {\n // Propagate the participant status and alarm to the master event\n component.reply = vm.component.reply;\n component.delegatedTo = vm.component.delegatedTo;\n component.$hasAlarm = vm.component.$hasAlarm;\n component.alarm = vm.component.alarm;\n // Send reply to the server\n reply(component);\n });\n }\n\n function deleteOccurrence() {\n vm.component.remove(true).then(function() {\n $rootScope.$emit('calendars:list');\n $mdDialog.hide();\n });\n }\n\n function deleteAllOccurrences() {\n vm.component.remove().then(function() {\n $rootScope.$emit('calendars:list');\n $mdDialog.hide();\n });\n }\n\n function toggleRawSource($event) {\n Calendar.$$resource.post(vm.component.pid + '/' + vm.component.id, \"raw\").then(function(data) {\n $mdDialog.hide();\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n template: [\n '<md-dialog flex=\"80\" flex-xs=\"100\" aria-label=\"' + l('View Raw Source') + '\">',\n ' <md-dialog-content class=\"md-dialog-content\">',\n ' <pre>',\n data,\n ' </pre>',\n ' </md-dialog-content>',\n ' <md-dialog-actions>',\n ' <md-button ng-click=\"close()\">' + l('Close') + '</md-button>',\n ' </md-dialog-actions>',\n '</md-dialog>'\n ].join(''),\n controller: ComponentRawSourceDialogController\n });\n\n /**\n * @ngInject\n */\n ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog'];\n function ComponentRawSourceDialogController(scope, $mdDialog) {\n scope.close = function() {\n $mdDialog.hide();\n };\n }\n });\n }\n }\n\n /**\n * @ngInject\n */\n ComponentEditorController.$inject = ['$rootScope', '$scope', '$log', '$timeout', '$mdDialog', 'User', 'Calendar', 'Component', 'AddressBook', 'Card', 'Alarm', 'stateComponent'];\n function ComponentEditorController($rootScope, $scope, $log, $timeout, $mdDialog, User, Calendar, Component, AddressBook, Card, Alarm, stateComponent) {\n var vm = this, component, oldStartDate, oldEndDate, oldDueDate;\n\n vm.service = Calendar;\n vm.component = stateComponent;\n vm.categories = {};\n vm.showRecurrenceEditor = vm.component.$hasCustomRepeat;\n vm.toggleRecurrenceEditor = toggleRecurrenceEditor;\n vm.showAttendeesEditor = angular.isDefined(vm.component.attendees);\n vm.toggleAttendeesEditor = toggleAttendeesEditor;\n //vm.searchText = null;\n vm.cardFilter = cardFilter;\n vm.addAttendee = addAttendee;\n vm.addAttachUrl = addAttachUrl;\n vm.cancel = cancel;\n vm.save = save;\n vm.attendeesEditor = {\n days: getDays(),\n hours: getHours()\n };\n vm.addStartDate = addStartDate;\n vm.addDueDate = addDueDate;\n\n // Synchronize start and end dates\n vm.updateStartTime = updateStartTime;\n vm.adjustStartTime = adjustStartTime;\n vm.updateEndTime = updateEndTime;\n vm.adjustEndTime = adjustEndTime;\n vm.updateDueTime = updateDueTime;\n vm.adjustDueTime = adjustDueTime;\n\n if (vm.component.start)\n oldStartDate = new Date(vm.component.start.getTime());\n if (vm.component.end)\n oldEndDate = new Date(vm.component.end.getTime());\n if (vm.component.due)\n oldDueDate = new Date(vm.component.due.getTime());\n\n function addAttachUrl() {\n var i = vm.component.addAttachUrl('');\n focus('attachUrl_' + i);\n }\n\n function toggleRecurrenceEditor() {\n vm.showRecurrenceEditor = !vm.showRecurrenceEditor;\n vm.component.$hasCustomRepeat = vm.showRecurrenceEditor;\n }\n\n function toggleAttendeesEditor() {\n vm.showAttendeesEditor = !vm.showAttendeesEditor;\n }\n\n // Autocomplete cards for attendees\n function cardFilter($query) {\n AddressBook.$filterAll($query);\n return AddressBook.$cards;\n }\n\n function addAttendee(card) {\n if (angular.isString(card)) {\n // User pressed \"Enter\" in search field, adding a non-matching card\n if (card.isValidEmail()) {\n vm.component.addAttendee(new Card({ emails: [{ value: card }] }));\n vm.searchText = '';\n }\n }\n else {\n vm.component.addAttendee(card);\n }\n }\n\n function save(form) {\n if (form.$valid) {\n vm.component.$save()\n .then(function(data) {\n $rootScope.$emit('calendars:list');\n $mdDialog.hide();\n Alarm.getAlarms();\n }, function(data, status) {\n $log.debug('failed');\n });\n }\n }\n\n function cancel() {\n vm.component.$reset();\n if (vm.component.isNew) {\n // Cancelling the creation of a component\n vm.component = null;\n }\n $mdDialog.cancel();\n }\n\n function getDays() {\n var days = [];\n\n if (vm.component.start && vm.component.end)\n days = vm.component.start.daysUpTo(vm.component.end);\n\n return _.map(days, function(date) {\n return { stringWithSeparator: date.stringWithSeparator(),\n getDayString: date.getDayString() };\n });\n }\n\n function getHours() {\n var hours = [];\n for (var i = 0; i <= 23; i++) {\n //hours.push(Component.timeFormat.formatTime(i, 0));\n hours.push(i.toString());\n }\n return hours;\n }\n\n function addStartDate() {\n vm.component.$addStartDate();\n oldStartDate = new Date(vm.component.start.getTime());\n }\n\n function addDueDate() {\n vm.component.$addDueDate();\n oldDueDate = new Date(vm.component.due.getTime());\n }\n\n function updateStartTime() {\n // When using the datepicker, the time is reset to 00:00; restore it\n vm.component.start.addMinutes(oldStartDate.getHours() * 60 + oldStartDate.getMinutes());\n adjustStartTime();\n }\n\n function adjustStartTime() {\n // Preserve the delta between the start and end dates\n var delta;\n delta = oldStartDate.valueOf() - vm.component.start.valueOf();\n if (delta !== 0) {\n oldStartDate = new Date(vm.component.start.getTime());\n if (vm.component.type === 'appointment') {\n vm.component.end = new Date(vm.component.start.getTime());\n vm.component.end.addMinutes(vm.component.delta);\n oldEndDate = new Date(vm.component.end.getTime());\n }\n }\n updateFreeBusy();\n }\n\n function updateEndTime() {\n // When using the datepicker, the time is reset to 00:00; restore it\n vm.component.end.addMinutes(oldEndDate.getHours() * 60 + oldEndDate.getMinutes());\n adjustEndTime();\n }\n\n function adjustEndTime() {\n // The end date must be after the start date\n var delta = vm.component.start.minutesTo(vm.component.end);\n if (delta < 0)\n vm.component.end = new Date(oldEndDate.getTime());\n else {\n vm.component.delta = delta;\n oldEndDate = new Date(vm.component.end.getTime());\n }\n updateFreeBusy();\n }\n\n function updateDueTime() {\n // When using the datepicker, the time is reset to 00:00; restore it\n vm.component.due.addMinutes(oldDueDate.getHours() * 60 + oldDueDate.getMinutes());\n adjustDueTime();\n }\n\n function adjustDueTime() {\n oldDueDate = new Date(vm.component.due.getTime());\n }\n\n function updateFreeBusy() {\n vm.attendeesEditor.days = getDays();\n vm.component.updateFreeBusy();\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .controller('ComponentController', ComponentController)\n .controller('ComponentEditorController', ComponentEditorController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgCalendarDay - An element that represents a day in the calendar's view\n * @memberof SOGo.SchedulerUI\n * @restrict element\n * @param {string} sgDay - the day of the events to display (YYYYMMDD)\n * @param {string} sgDayString - the day in ISO8601 format (YYYY-MM-DDTHH:MM+-HH:MM)\n * @param {number} sgDayNumber - the day index within the calendar's view\n *\n * @example:\n\n <sg-calendar-day\n sg-day-string=\"2015-11-01T00:00-05:00\"\n sg-day-number=\"0\"\n sg-day=\"20151101\">\n ..\n </sg-calendar-day-table>\n */\n function sgCalendarDay() {\n return {\n restrict: 'E',\n scope: {\n day: '@sgDay',\n dayNumber: '@sgDayNumber',\n dayString: '@sgDayString'\n },\n controller: sgCalendarDayController\n };\n }\n\n /**\n * @ngInject\n */\n sgCalendarDayController.$inject = ['$scope'];\n function sgCalendarDayController($scope) {\n // Expose some scope variables to the controller\n // See the sgCalendarDayTable directive\n this.day = $scope.day;\n this.dayNumber = $scope.dayNumber;\n this.dayString = $scope.dayString;\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarDay', sgCalendarDay);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarDayBlock - An event block to be displayed in a week\n * @memberof SOGo.SchedulerUI\n * @restrict element\n * @param {object} sgBlock - the event block definition\n * @param {function} sgClick - the function to call when clicking on a block.\n * Two variables are available: clickEvent (the event that triggered the mouse click),\n * and clickComponent (a Component object)\n *\n * @example:\n\n <sg-calendar-day-block\n ng-repeat=\"block in blocks[day]\"\n sg-block=\"block\"\n sg-click=\"open(clickEvent, clickComponent)\" />\n */\n sgCalendarDayBlock.$inject = ['CalendarSettings'];\n function sgCalendarDayBlock(CalendarSettings) {\n return {\n restrict: 'E',\n scope: {\n block: '=sgBlock',\n clickBlock: '&sgClick'\n },\n replace: true,\n template: [\n '<div class=\"sg-event\"',\n // Add a class while dragging\n ' ng-class=\"{\\'sg-event--dragging\\': block.dragging}\">',\n ' <div class=\"eventInside\"',\n ' ng-click=\"clickBlock({clickEvent: $event, clickComponent: block.component})\">',\n // Categories color stripes\n ' <div class=\"sg-category\" ng-repeat=\"category in block.component.categories\"',\n ' ng-class=\"\\'bg-category\\' + category\"',\n ' ng-style=\"{ right: ($index * 3) + \\'px\\' }\"></div>',\n ' <div class=\"text\">{{ block.component.summary }}',\n ' <span class=\"icons\">',\n // Component is reccurent\n ' <md-icon ng-if=\"block.component.occurrenceId\" class=\"material-icons icon-repeat\"></md-icon>',\n // Component has an alarm\n ' <md-icon ng-if=\"block.component.c_nextalarm\" class=\"material-icons icon-alarm\"></md-icon>',\n // Component is confidential\n ' <md-icon ng-if=\"block.component.c_classification == 1\" class=\"material-icons icon-visibility-off\"></md-icon>',\n // Component is private\n ' <md-icon ng-if=\"block.component.c_classification == 2\" class=\"material-icons icon-vpn-key\"></md-icon>',\n ' </span>',\n // Location\n ' <div class=\"secondary\" ng-if=\"block.component.c_location\">',\n ' <md-icon>place</md-icon> {{block.component.c_location}}',\n ' </div>',\n ' </div>',\n ' </div>',\n '</div>'\n ].join(''),\n link: link\n };\n\n function link(scope, iElement, attrs) {\n var pc, left, right;\n\n // Compute overlapping (2%)\n pc = 100 / scope.block.siblings;\n left = scope.block.position * pc;\n right = 100 - (scope.block.position + 1) * pc;\n if (pc < 100) {\n if (left > 0)\n left -= 2;\n if (right > 0)\n right -= 2;\n }\n\n // Add some padding (2%)\n if (left === 0)\n left = 2;\n if (right === 0)\n right = 2;\n\n // Set position\n iElement.css('left', left + '%');\n iElement.css('right', right + '%');\n iElement.addClass('starts' + scope.block.start);\n iElement.addClass('lasts' + scope.block.length);\n\n // Set background color\n if (scope.block.component)\n iElement.addClass('bg-folder' + scope.block.component.pid);\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarDayBlock', sgCalendarDayBlock);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarDayTable - Build list of blocks for a specific day\n * @memberof SOGo.SchedulerUI\n * @restrict element\n * @param {object} sgBlocks - the events blocks definitions for the current view\n * @param {string} sgDay - the day of the events to display\n * @param {function} sgClick - the function to call when clicking on a block.\n * Two variables are available: event (the event that triggered the mouse click),\n * and component (a Component object)\n *\n * @example:\n\n <sg-calendar-day-table\n sg-blocks=\"calendar.blocks\"\n sg-day=\"20150330\"\n sg-click=\"open({ event: clickEvent, component: clickComponent })\"/>\n */\n function sgCalendarDayTable() {\n return {\n restrict: 'E',\n scope: {\n blocks: '=sgBlocks',\n day: '@sgDay',\n clickBlock: '&sgClick'\n },\n template: [\n '<sg-calendar-day-block',\n ' class=\"sg-draggable-calendar-block\"',\n ' ng-repeat=\"block in blocks[day]\"',\n ' sg-block=\"block\"',\n ' sg-click=\"clickBlock({event: clickEvent, component: clickComponent})\"/>'\n ].join('')\n };\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarDayTable', sgCalendarDayTable);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarBlock - Applied to an event ghost block to be displayed while dragging an event block. Each day of the\n * calendar's view must have a ghost block.\n * @memberof SOGo.SchedulerUI\n * @restrict attribute\n *\n * @example:\n\n <sg-calendar-day-block\n sg-calendar-ghost\n sg-block=\"list.component.$ghost\">/\n */\n sgCalendarGhost.$inject = ['$rootScope', '$timeout', 'CalendarSettings', 'Calendar', 'Component'];\n function sgCalendarGhost($rootScope, $timeout, CalendarSettings, Calendar, Component) {\n return {\n restrict: 'A',\n require: ['^sgCalendarDay', '^sgCalendarScrollView'],\n link: link\n };\n\n function link(scope, iElement, attrs, ctrls) {\n var domElement, calendarDayCtrl, scrollViewCtrl;\n\n domElement = iElement[0];\n calendarDayCtrl = ctrls[0];\n scrollViewCtrl = ctrls[1];\n\n iElement.addClass('sg-event--ghost md-whiteframe-3dp ng-hide');\n\n // Listen on drag gestures\n var deregisterDragStart = $rootScope.$on('calendar:dragstart', initGhost);\n var deregisterDrag = $rootScope.$on('calendar:drag', updateGhost);\n var deregisterDragEnd = $rootScope.$on('calendar:dragend', hideGhost);\n\n // Deregister listeners on destroy\n scope.$on('$destroy', function() {\n deregisterDragStart();\n deregisterDrag();\n deregisterDragEnd();\n });\n\n function initGhost() {\n // Expose ghost block to the scope\n scope.block = Component.$ghost;\n // Set background color\n iElement.addClass('bg-folder' + scope.block.component.pid);\n }\n\n function hideGhost() {\n // Remove background color\n _.forEachRight(domElement.classList, function(c) {\n if (/^bg-folder/.test(c))\n iElement.removeClass(c);\n });\n // Hide ghost\n iElement.addClass('ng-hide');\n }\n\n function updateGhost() {\n // From SOGoEventDragGhostController._updateGhosts\n var showGhost, isRelative, originalDay, currentDay, wasOtherBlock,\n start, duration, durationLeft, maxDuration, enableTransition;\n\n showGhost = false;\n enableTransition = function() {\n iElement.removeClass('sg-event--notransition');\n };\n\n if (Calendar.$view && Calendar.$view.type == scrollViewCtrl.type) {\n // The view of the dragging block is the scrolling view of this ghost block\n\n isRelative = scrollViewCtrl.type === 'multiday-allday';\n originalDay = scope.block.pointerHandler.originalEventCoordinates.dayNumber;\n currentDay = scope.block.pointerHandler.currentEventCoordinates.dayNumber;\n start = scope.block.pointerHandler.currentEventCoordinates.start;\n durationLeft = scope.block.pointerHandler.currentEventCoordinates.duration;\n maxDuration = CalendarSettings.EventDragDayLength - start;\n\n if (angular.isUndefined(durationLeft))\n return;\n\n duration = durationLeft;\n if (duration > maxDuration)\n duration = maxDuration;\n\n delete scope.startHour;\n delete scope.endHour;\n\n if (currentDay > -1 && currentDay == calendarDayCtrl.dayNumber) {\n // This ghost block (day) is the first of the dragging event\n showGhost = true;\n if (!isRelative) {\n // Show start hour and set the vertical position\n scope.startHour = getStartTime(start);\n wasOtherBlock = parseInt(iElement.css('top')) === 0;\n if (wasOtherBlock)\n iElement.addClass('sg-event--notransition');\n // Set the height\n if (Calendar.$view.quarterHeight) {\n iElement.css('top', (start * Calendar.$view.quarterHeight) + 'px');\n iElement.css('height', (duration * Calendar.$view.quarterHeight) + 'px');\n }\n else\n iElement.css('top', Calendar.$view.topOffset + 'px');\n if (wasOtherBlock)\n $timeout(enableTransition);\n }\n iElement.removeClass('fg-folder' + scope.block.component.pid);\n iElement.removeClass('sg-event--ghost--last');\n iElement.addClass('sg-event--ghost--first');\n }\n\n durationLeft -= duration;\n currentDay++;\n\n // Search a subsequent block that matches the current ghost's day\n while (!showGhost && durationLeft && currentDay <= calendarDayCtrl.dayNumber) {\n duration = durationLeft;\n if (duration > CalendarSettings.EventDragDayLength)\n duration = CalendarSettings.EventDragDayLength;\n if (currentDay > -1 && currentDay == calendarDayCtrl.dayNumber) {\n // The dragging event overlaps this current ghost's day\n showGhost = true;\n if (!isRelative) {\n wasOtherBlock = parseInt(iElement.css('top')) !== 0;\n if (wasOtherBlock)\n iElement.addClass('sg-event--notransition');\n iElement.css('top', Calendar.$view.topOffset + 'px');\n // Set the height\n if (Calendar.$view.quarterHeight)\n iElement.css('height', (duration * Calendar.$view.quarterHeight) + 'px');\n if (wasOtherBlock)\n $timeout(enableTransition);\n }\n iElement.removeClass('sg-event--ghost--first');\n iElement.removeClass('sg-event--ghost--last');\n // Trick for all-day events: set the foreground color to the background color so the event's title\n // is not visible but the div size remains identical.\n iElement.addClass('fg-folder' + scope.block.component.pid);\n }\n durationLeft -= duration;\n currentDay++;\n start = 0;\n }\n if (!durationLeft) {\n // Reached last ghost block\n if (isRelative) {\n iElement.addClass('sg-event--ghost--last');\n }\n else {\n // Set the end date\n scope.endHour = getEndTime(start, duration);\n }\n }\n }\n\n if (showGhost)\n iElement.removeClass('ng-hide');\n else\n iElement.addClass('ng-hide');\n }\n\n function quartersToHM(quarters) {\n var minutes, hours, mins;\n\n minutes = quarters * 15;\n hours = Math.floor(minutes / 60);\n if (hours < 10)\n hours = \"0\" + hours;\n mins = minutes % 60;\n if (mins < 10)\n mins = \"0\" + mins;\n\n return \"\" + hours + \":\" + mins;\n }\n\n function getStartTime(start) {\n return quartersToHM(start);\n }\n\n function getEndTime(start, duration) {\n var end = (start + duration) % CalendarSettings.EventDragDayLength;\n return quartersToHM(end);\n }\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarGhost', sgCalendarGhost);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarMonthDay - Build list of blocks for a specific day in a month\n * @memberof SOGo.Common\n * @restrict element\n * @param {object} sgBlocks - the events blocks definitions for the current view\n * @param {string} sgDay - the day of the events to display\n * @ngInject\n * @example:\n\n <sg-calendar-monh-day\n sg-blocks=\"calendar.blocks\"\n sg-day=\"20150408\"\n sg-click=\"open({ event: clickEvent, component: clickComponent })\"/>\n */\n function sgCalendarMonthDay() {\n return {\n restrict: 'E',\n scope: {\n blocks: '=sgBlocks',\n day: '@sgDay',\n clickBlock: '&sgClick'\n },\n template: [\n '<sg-calendar-month-event',\n ' class=\"sg-draggable-calendar-block\"',\n ' ng-repeat=\"block in blocks[day]\"',\n ' sg-block=\"block\"',\n ' sg-click=\"clickBlock({event: clickEvent, component: clickComponent})\"/>'\n ].join('')\n };\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarMonthDay', sgCalendarMonthDay);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarMonthEvent - An event block to be displayed in a month\n * @memberof SOGo.Common\n * @restrict element\n * @param {object} sgBlock - the event block definition\n * @ngInject\n * @example:\n\n <sg-calendar-month-event\n ng-repeat=\"block in blocks[day]\"\n sg-block=\"block\"/>\n */\n function sgCalendarMonthEvent() {\n return {\n restrict: 'E',\n scope: {\n block: '=sgBlock',\n clickBlock: '&sgClick'\n },\n replace: true,\n template: [\n '<div class=\"sg-event\"',\n // Add a class while dragging\n ' ng-class=\"{\\'sg-event--dragging\\': block.dragging}\"',\n ' ng-click=\"clickBlock({clickEvent: $event, clickComponent: block.component})\">',\n ' <span class=\"secondary\" ng-if=\"!block.component.c_isallday\">{{ block.starthour }}</span>',\n ' {{ block.component.summary }}',\n ' <span class=\"icons\">',\n // Component is reccurent\n ' <md-icon ng-if=\"block.component.occurrenceId\" class=\"material-icons icon-repeat\"></md-icon>',\n // Component has an alarm\n ' <md-icon ng-if=\"block.component.c_nextalarm\" class=\"material-icons icon-alarm\"></md-icon>',\n // Component is confidential\n ' <md-icon ng-if=\"block.component.c_classification == 1\" class=\"material-icons icon-visibility-off\"></md-icon>',\n // Component is private\n ' <md-icon ng-if=\"block.component.c_classification == 2\" class=\"material-icons icon-vpn-key\"></md-icon>',\n ' </span>',\n '</div>'\n ].join(''),\n link: link\n };\n\n function link(scope, iElement, attrs) {\n if (scope.block.component)\n iElement.addClass('bg-folder' + scope.block.component.pid);\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarMonthEvent', sgCalendarMonthEvent);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgCalendarScrollView - scrollable view that contains draggable elements\n * @memberof SOGo.SchedulerUI\n * @restrict attribute\n * @param {string} sgCalendarScrollView - the view type (multiday, multiday-allday, or monthly)\n *\n * @example:\n\n <md-content sg-calendar-scroll-view=\"multiday\">\n ..\n </md-content>\n */\n sgCalendarScrollView.$inject = ['$rootScope', '$window', '$document', '$q', '$timeout', '$mdGesture', 'Calendar', 'Component', 'Preferences'];\n function sgCalendarScrollView($rootScope, $window, $document, $q, $timeout, $mdGesture, Calendar, Component, Preferences) {\n return {\n restrict: 'A',\n scope: {\n type: '@sgCalendarScrollView'\n },\n controller: sgCalendarScrollViewController,\n link: function(scope, element, attrs, controller) {\n var view, scrollView, type, lastScroll, deregisterDragStart, deregisterDragStop;\n\n scrollView = element[0];\n type = scope.type; // multiday, multiday-allday, monthly, unknown?\n lastScroll = 0;\n\n // Listen to dragstart and dragend events\n deregisterDragStart = $rootScope.$on('calendar:dragstart', onDragStart);\n deregisterDragStop = $rootScope.$on('calendar:dragend', onDragEnd);\n\n // Update the \"view\" object literal once the Angular template has been transformed\n $timeout(initView);\n\n // Deregister listeners when destroying the view\n scope.$on('$destroy', function() {\n deregisterDragStart();\n deregisterDragStop();\n element.off('mouseover', updateFromPointerHandler);\n angular.element($window).off('resize', updateCoordinates);\n });\n\n function initView() {\n var quarterHeight;\n\n // Quarter height doesn't change if window is resize; compute it only once\n quarterHeight = getQuarterHeight();\n\n view = {\n type: type,\n quarterHeight: quarterHeight,\n scrollStep: 6 * quarterHeight,\n maxX: getMaxColumns(),\n\n // Expose a reference of the view element\n element: scrollView\n };\n\n // Compute coordinates of view element; recompute it on window resize\n angular.element($window).on('resize', updateCoordinates);\n updateCoordinates();\n\n if (type != 'monthly')\n // Scroll to the day start hour defined in the user's defaults\n Preferences.ready().then(function() {\n var time, hourCell, quartersOffset;\n if (Preferences.defaults.SOGoDayStartTime) {\n time = Preferences.defaults.SOGoDayStartTime.split(':');\n hourCell = document.getElementById('hour' + parseInt(time[0]));\n quartersOffset = parseInt(time[1]) * quarterHeight;\n scrollView.scrollTop = hourCell.offsetTop + quartersOffset;\n }\n });\n }\n\n function getQuarterHeight() {\n var hour0, hour23, height = null;\n\n hour0 = document.getElementById('hour0');\n hour23 = document.getElementById('hour23');\n if (hour0 && hour23)\n height = ((hour23.offsetTop - hour0.offsetTop) / (23 * 4));\n\n return height;\n }\n\n function getDayDimensions(viewLeft) {\n var width, height, leftOffset, topOffset, nodes, domRect, tileHeader;\n\n height = width = leftOffset = topOffset = 0;\n nodes = scrollView.getElementsByClassName('day0');\n\n if (nodes.length > 0) {\n domRect = nodes[0].getBoundingClientRect();\n height = domRect.height;\n width = domRect.width;\n leftOffset = domRect.left - viewLeft;\n tileHeader = nodes[0].getElementsByClassName('sg-calendar-tile-header');\n if (tileHeader.length > 0)\n topOffset = tileHeader[0].clientHeight;\n }\n\n return { height: height, width: width, offset: { left: leftOffset, top: topOffset } };\n }\n\n function getMaxColumns() {\n var max = 0;\n\n //if (type == 'multiday') {\n max = scrollView.getElementsByClassName('day').length - 1;\n //}\n\n return max;\n }\n\n // View has been resized;\n // Compute the view's origins (x, y), a day's dimensions and left margin.\n function updateCoordinates() {\n var domRect, dayDimensions;\n\n domRect = scrollView.getBoundingClientRect();\n dayDimensions = getDayDimensions(domRect.left);\n\n angular.extend(view, {\n coordinates: {\n x: domRect.left,\n y: domRect.top\n },\n dayHeight: dayDimensions.height,\n dayWidth: dayDimensions.width,\n daysOffset: dayDimensions.offset.left,\n topOffset: dayDimensions.offset.top\n });\n }\n\n function onDragStart() {\n element.on('mouseover', updateFromPointerHandler);\n updateFromPointerHandler();\n }\n\n function onDragEnd() {\n element.off('mouseover', updateFromPointerHandler);\n Calendar.$view = null;\n }\n\n // From SOGoScrollController.updateFromPointerHandler\n function updateFromPointerHandler() {\n var scrollStep, pointerHandler, pointerCoordinates, now, scrollY, minY, delta;\n\n scrollStep = view.scrollStep;\n pointerHandler = Component.$ghost.pointerHandler;\n if (pointerHandler) {\n pointerCoordinates = pointerHandler.getContainerBasedCoordinates(view);\n\n if (pointerCoordinates) {\n // Pointer is inside view; Adjust scrollbar if necessary\n Calendar.$view = view;\n now = new Date().getTime();\n if (!lastScroll || now > lastScroll + 100) {\n lastScroll = now;\n scrollY = pointerCoordinates.y - scrollStep;\n if (scrollY < 0) {\n minY = -scrollView.scrollTop;\n if (scrollY < minY)\n scrollY = minY;\n scrollView.scrollTop += scrollY;\n }\n else {\n scrollY = pointerCoordinates.y + scrollStep;\n delta = scrollY - scrollView.clientHeight;\n if (delta > 0) {\n scrollView.scrollTop += delta;\n }\n }\n }\n }\n }\n }\n }\n };\n }\n\n sgCalendarScrollViewController.$inject = ['$scope'];\n function sgCalendarScrollViewController($scope) {\n // Expose the view type to the controller\n // See sgCalendarDayBlockGhost\n this.type = $scope.type;\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarScrollView', sgCalendarScrollView);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarDayTable - Build list of blocks for a specific day\n * @memberof SOGo.Common\n * @restrict element\n * @param {object} sgBlocks - the events blocks definitions for the current view\n * @param {string} sgDay - the day of the events to display\n * @param {function} sgClick - the function to call when clicking on a block.\n * Two variables are available: event (the event that triggered the mouse click),\n * and component (a Component object)\n *\n * @example:\n\n <sg-calendar-day-table\n sg-blocks=\"calendar.blocks\"\n sg-day=\"20150330\"\n sg-click=\"open({ event: clickEvent, component: clickComponent })\"/>\n */\n function sgCalendarTable() {\n return {\n restrict: 'E',\n scope: {\n calendars: '=sgCalendars',\n calendar: '@sgCalendar',\n blocksType: '@sgBlocksType',\n day: '@sgDay',\n clickBlock: '&sgClick'\n },\n template: [\n '<sg-calendar-day-table',\n ' sg-blocks=\"calendars[calendar][blocksType]\"',\n ' sg-day=\"day\"',\n ' sg-click=\"clickBlock({event: clickEvent, component: clickComponent})\"/>'\n ].join('')\n };\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarTable', sgCalendarTable);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgCategoryStylesheet - Add CSS stylesheet for a category's color\n * @memberof SOGo.SchedulerUI\n * @restrict attribute\n * @param {object} ngModel - the object literal describing the category\n * @example:\n\n <sg-category-stylesheet\n ng-repeat=\"category in categories\"\n ng-model=\"category\" />\n */\n function sgCategoryStylesheet() {\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n ngModel: '='\n },\n replace: true,\n template: [\n '<style type=\"text/css\">',\n /* Background color */\n ' .bg-category{{ ngModel.id }} {',\n ' background-color: {{ ngModel.color }} !important;',\n ' }',\n /* Border color */\n ' .bdr-category{{ ngModel.id }} {',\n ' border-color: {{ ngModel.color }} !important;',\n ' }',\n '</style>'\n ].join('')\n };\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCategoryStylesheet', sgCategoryStylesheet);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgDraggableCalendarBlock - Make an element draggable\n * @memberof SOGo.SchedulerUI\n * @restrict class or attribute\n *\n * @example:\n\n <div class=\"sg-draggable-calendar-block\"/>\n */\n sgDraggableCalendarBlock.$inject = ['$rootScope', '$timeout', '$log', 'Calendar', 'CalendarSettings', 'Component'];\n function sgDraggableCalendarBlock($rootScope, $timeout, $log, Calendar, CalendarSettings, Component) {\n return {\n restrict: 'CA',\n require: '^sgCalendarDay',\n link: link\n };\n\n function link(scope, element, attrs, calendarDayCtrl) {\n if (scope.block) {\n if (scope.block.component.editable) {\n // Add dragging grips to existing event block\n initGrips();\n }\n else {\n element.removeClass('sg-draggable-calendar-block');\n return;\n }\n }\n\n // Start dragging on mousedown\n element.on('mousedown', onDragDetect);\n\n // Deregister listeners when removing the element from the DOM\n scope.$on('$destroy', function() {\n element.off('mousedown', onDragDetect);\n element.off('mousemove', onDrag);\n });\n\n function initGrips() {\n var component, dayNumber, blockIndex, isFirstBlock, isLastBlock,\n dragGrip, leftGrip, rightGrip, topGrip, bottomGrip;\n\n component = scope.block.component;\n dayNumber = scope.block.dayNumber;\n blockIndex = _.findIndex(component.blocks, _.matchesProperty('dayNumber', dayNumber));\n isFirstBlock = (blockIndex === 0);\n isLastBlock = (blockIndex === component.blocks.length - 1);\n\n dragGrip = angular.element('<div class=\"dragGrip\"></div>');\n dragGrip.addClass('bdr-folder' + component.pid);\n\n if (component.c_isallday ||\n element[0].parentNode.tagName === 'SG-CALENDAR-MONTH-DAY') {\n if (isFirstBlock) {\n leftGrip = angular.element('<div class=\"dragGrip-left\"></div>').append(dragGrip);\n element.append(leftGrip);\n }\n if (isLastBlock) {\n rightGrip = angular.element('<div class=\"dragGrip-right\"></div>').append(dragGrip.clone());\n element.append(rightGrip);\n }\n }\n else {\n if (isFirstBlock) {\n topGrip = angular.element('<div class=\"dragGrip-top\"></div>').append(dragGrip);\n element.append(topGrip);\n }\n if (isLastBlock) {\n bottomGrip = angular.element('<div class=\"dragGrip-bottom\"></div>').append(dragGrip.clone());\n element.append(bottomGrip);\n }\n }\n }\n\n function onDragDetect(ev) {\n var block, dragMode, eventType, startDate, newData, newComponent, pointerHandler;\n\n ev.stopPropagation();\n\n dragMode = 'move-event';\n \n if (scope.block && scope.block.component) {\n // Move or resize existing component\n if (ev.target.className == 'dragGrip-top' ||\n ev.target.className == 'dragGrip-left')\n dragMode = 'change-start';\n else if (ev.target.className == 'dragGrip-bottom' ||\n ev.target.className == 'dragGrip-right' )\n dragMode = 'change-end';\n }\n else {\n // Create new component from dragging\n dragMode = 'change-end';\n }\n\n // Initialize pointer handler\n pointerHandler = new SOGoEventDragPointerHandler(dragMode);\n pointerHandler.initFromEvent(ev);\n\n // Update Component.$ghost\n Component.$ghost.pointerHandler = pointerHandler;\n\n // Stop dragging on the next \"mouseup\"\n angular.element(document).one('mouseup', onDragEnd);\n\n // Listen to mousemove and start dragging when mouse has moved from at least 3 pixels\n angular.element(document).on('mousemove', onDrag);\n }\n\n function dragStart(ev) {\n var block, dragMode, eventType, isHourCell, isMonthly, startDate, newData, newComponent, pointerHandler;\n\n isHourCell = element.hasClass('clickableHourCell');\n isMonthly = (element[0].parentNode.tagName == 'SG-CALENDAR-MONTH-DAY') ||\n element.hasClass('clickableDayCell');\n\n if (scope.block && scope.block.component) {\n // Move or resize existing component\n block = scope.block;\n }\n else {\n // Create new component from dragging\n startDate = new Date(calendarDayCtrl.dayString.substring(0,10) +\n ' ' +\n calendarDayCtrl.dayString.substring(11,16));\n newData = {\n type: 'appointment',\n pid: 'personal', // TODO respect SOGoDefaultCalendar\n summary: l('New Event'),\n startDate: startDate,\n isAllDay: isHourCell? 0 : 1\n };\n newComponent = new Component(newData);\n block = {\n component: newComponent,\n dayNumber: calendarDayCtrl.dayNumber,\n length: 0\n };\n block.component.blocks = [block];\n }\n\n // Determine event type\n eventType = 'multiday';\n if (isMonthly)\n eventType = 'monthly';\n else if (block.component.c_isallday)\n eventType = 'multiday-allday';\n\n // Mark all blocks as being dragged\n _.forEach(block.component.blocks, function(b) {\n b.dragging = true;\n });\n\n // Update pointer handler\n pointerHandler = Component.$ghost.pointerHandler;\n pointerHandler.prepareWithEventType(eventType);\n pointerHandler.initFromBlock(block);\n\n // Update Component.$ghost\n Component.$ghost.starthour = block.starthour;\n Component.$ghost.component = block.component;\n\n $log.debug('emit calendar:dragstart');\n $rootScope.$emit('calendar:dragstart');\n }\n\n function onDrag(ev) {\n var pointerHandler = Component.$ghost.pointerHandler;\n\n // Update\n // - currentCoordinates\n // - currentViewCoordinates\n // - currentEventCoordinates\n $timeout(function() {\n pointerHandler.updateFromEvent(ev);\n });\n }\n\n function onDragEnd(ev) {\n var block, pointer;\n\n block = scope.block;\n pointer = Component.$ghost.pointerHandler;\n\n // Deregister mouse events\n angular.element(document).off('mousemove', onDrag);\n\n if (pointer.dragHasStarted) {\n $rootScope.$emit('calendar:dragend');\n pointer.dragHasStarted = false;\n }\n\n // Unmark all blocks as being dragged\n if (block)\n _.forEach(block.component.blocks, function(b) {\n b.dragging = false;\n });\n }\n\n /**\n * SOGoCoordinates\n */\n function SOGoCoordinates() {\n }\n\n SOGoCoordinates.prototype = {\n x: -1,\n y: -1,\n\n getDelta: function SC_getDelta(otherCoordinates) {\n var delta = new SOGoCoordinates();\n delta.x = this.x - otherCoordinates.x;\n delta.y = this.y - otherCoordinates.y;\n\n return delta;\n },\n\n getDistance: function SC_getDistance(otherCoordinates) {\n var delta = this.getDelta(otherCoordinates);\n\n return Math.sqrt(delta.x * delta.x + delta.y * delta.y);\n },\n\n clone: function SC_clone() {\n var coordinates = new SOGoCoordinates();\n coordinates.x = this.x;\n coordinates.y = this.y;\n\n return coordinates;\n }\n };\n\n /**\n * SOGoEventDragEventCoordinates\n */\n function SOGoEventDragEventCoordinates(eventType) {\n this.setEventType(eventType);\n }\n\n SOGoEventDragEventCoordinates.prototype = {\n dayNumber: -1,\n start: -1,\n duration: -1,\n\n eventType: null,\n\n setEventType: function(eventType) {\n this.eventType = eventType;\n },\n\n initFromBlock: function(block) {\n if (this.eventType === 'monthly') {\n this.start = 0;\n this.duration = block.component.blocks.length * 96;\n }\n else {\n // Get the start (first quarter) from the event's first block\n // Compute overall length\n this.start = block.component.blocks[0].start;\n this.duration = _.sum(block.component.blocks, function(b) {\n return b.length;\n });\n }\n\n // Get the dayNumber from the event's first block\n this.dayNumber = block.component.blocks[0].dayNumber;\n },\n\n getDelta: function(otherCoordinates) {\n var delta = new SOGoEventDragEventCoordinates();\n delta.dayNumber = (this.dayNumber - otherCoordinates.dayNumber);\n delta.start = (this.start - otherCoordinates.start);\n delta.duration = (this.duration - otherCoordinates.duration);\n\n return delta;\n },\n\n _quartersToHM: function(quarters) {\n var minutes = quarters * 15;\n var hours = Math.floor(minutes / 60);\n if (hours < 10)\n hours = \"0\" + hours;\n var mins = minutes % 60;\n if (mins < 10)\n mins = \"0\" + mins;\n\n return \"\" + hours + \":\" + mins;\n },\n\n getStartTime: function() {\n return this._quartersToHM(this.start);\n },\n\n getEndTime: function() {\n var end = (this.start + this.duration) % CalendarSettings.EventDragDayLength;\n return this._quartersToHM(end);\n },\n\n clone: function() {\n var coordinates = new SOGoEventDragEventCoordinates();\n coordinates.dayNumber = this.dayNumber;\n coordinates.start = this.start;\n coordinates.duration = this.duration;\n\n return coordinates;\n }\n };\n\n /**\n * SOGoEventDragPointerHandler\n */\n function SOGoEventDragPointerHandler(dragMode) {\n this.dragMode = dragMode;\n }\n\n SOGoEventDragPointerHandler.prototype = {\n // Pointer absolute xy coordinates within page\n originalCoordinates: null,\n currentCoordinates: null,\n\n // Pointer relative xy coordinates within view (row-column)\n originalViewCoordinates: null,\n currentViewCoordinates: null,\n\n // Event start-duration coordinates\n originalEventCoordinates: null,\n currentEventCoordinates: null,\n\n dragHasStarted: false,\n\n // Function to return the day and quarter coordinates of the pointer cursor\n // within the day view\n getEventViewCoordinates: null,\n\n initFromBlock: function SEDPH_initFromBlock(block) {\n this.currentEventCoordinates = new SOGoEventDragEventCoordinates(this.eventType);\n this.originalEventCoordinates = new SOGoEventDragEventCoordinates(this.eventType);\n this.originalEventCoordinates.initFromBlock(block);\n },\n\n initFromEvent: function SEDPH_initFromEvent(event) {\n this.currentCoordinates = new SOGoCoordinates();\n this.updateFromEvent(event);\n this.originalCoordinates = this.currentCoordinates.clone();\n },\n\n // Method continuously called while dragging\n updateFromEvent: function SEDPH_updateFromEvent(event) {\n // Event here is a DOM event, not a calendar event!\n this.currentCoordinates.x = event.pageX;\n this.currentCoordinates.y = event.pageY;\n\n // From SOGoEventDragGhostController.updateFromPointerHandler\n if (this.dragHasStarted && Calendar.$view) {\n var newEventCoordinates = this.getEventViewCoordinates(Calendar.$view);\n if (!this.originalViewCoordinates) {\n this.originalViewCoordinates = this.getEventViewCoordinates(Calendar.$view, this.originalCoordinates);\n if (Component.$ghost.component.isNew) {\n this.setTimeFromQuarters(Component.$ghost.component.start, this.originalViewCoordinates.y);\n $log.debug('new event start date ' + Component.$ghost.component.start);\n }\n }\n if (!this.currentViewCoordinates ||\n !newEventCoordinates ||\n newEventCoordinates.x != this.currentViewCoordinates.x ||\n newEventCoordinates.y != this.currentViewCoordinates.y) {\n this.currentViewCoordinates = newEventCoordinates;\n if (this.originalViewCoordinates) {\n if (!newEventCoordinates) {\n this.currentViewCoordinates = this.originalViewCoordinates.clone();\n }\n this.updateEventCoordinates();\n }\n }\n }\n else if (this.originalCoordinates &&\n this.currentCoordinates &&\n !this.dragHasStarted) {\n var distance = this.getDistance();\n if (distance > 3) {\n this.dragHasStarted = true;\n dragStart(event);\n }\n }\n },\n\n // SOGoEventDragGhostController._updateCoordinates\n // Extend this.currentCoordinates with start, dayNumber and duration\n updateEventCoordinates: function SEDGC__updateCoordinates() {\n var newDuration;\n\n // Compute delta wrt to position of mouse at dragstart on the day/quarter grid\n var delta = this.currentViewCoordinates.getDelta(this.originalViewCoordinates);\n var deltaQuarters = delta.x * CalendarSettings.EventDragDayLength + delta.y;\n $log.debug('quarters delta ' + deltaQuarters);\n\n if (angular.isUndefined(this.originalEventCoordinates.start)) {\n this.originalEventCoordinates.dayNumber = this.originalViewCoordinates.x;\n this.originalEventCoordinates.start = this.originalViewCoordinates.y;\n }\n // if (currentView == \"multicolumndayview\")\n // this._updateMulticolumnViewDayNumber_SEDGC();\n // else\n this.currentEventCoordinates.dayNumber = this.originalEventCoordinates.dayNumber;\n\n if (this.dragMode == \"move-event\") {\n this.currentEventCoordinates.start = this.originalEventCoordinates.start + deltaQuarters;\n this.currentEventCoordinates.duration = this.originalEventCoordinates.duration;\n }\n else {\n if (this.dragMode == \"change-start\") {\n newDuration = this.originalEventCoordinates.duration - deltaQuarters;\n if (newDuration > 0) {\n this.currentEventCoordinates.start = this.originalEventCoordinates.start + deltaQuarters;\n this.currentEventCoordinates.duration = newDuration;\n }\n else if (newDuration < 0) {\n this.currentEventCoordinates.start = (this.originalEventCoordinates.start + this.originalEventCoordinates.duration);\n this.currentEventCoordinates.duration = -newDuration;\n }\n }\n else if (this.dragMode == \"change-end\") {\n newDuration = this.originalEventCoordinates.duration + deltaQuarters;\n if (newDuration > 0) {\n this.currentEventCoordinates.start = this.originalEventCoordinates.start;\n this.currentEventCoordinates.duration = newDuration;\n }\n else if (newDuration < 0) {\n this.currentEventCoordinates.start = this.originalEventCoordinates.start + newDuration;\n this.currentEventCoordinates.duration = -newDuration;\n }\n }\n }\n\n var deltaDays;\n if (this.currentEventCoordinates.start < 0) {\n deltaDays = Math.ceil(-this.currentEventCoordinates.start / CalendarSettings.EventDragDayLength);\n this.currentEventCoordinates.start += deltaDays * CalendarSettings.EventDragDayLength;\n this.currentEventCoordinates.dayNumber -= deltaDays;\n }\n else if (this.currentEventCoordinates.start >= CalendarSettings.EventDragDayLength) {\n deltaDays = Math.floor(this.currentEventCoordinates.start / CalendarSettings.EventDragDayLength);\n this.currentEventCoordinates.start -= deltaDays * CalendarSettings.EventDragDayLength;\n\n // This dayNumber needs to be updated with the calendar number.\n // if (currentView == \"multicolumndayview\")\n // this._updateMulticolumnViewDayNumber_SEDGC();\n this.currentEventCoordinates.dayNumber += deltaDays;\n }\n $log.debug('event coordinates ' + JSON.stringify(this.currentEventCoordinates));\n $rootScope.$emit('calendar:drag');\n },\n\n // SOGoEventDragPointerHandler.getContainerBasedCoordinates\n getContainerBasedCoordinates: function SEDPH_getCBC(view, pointerCoordinates) {\n var currentCoordinates = pointerCoordinates || this.currentCoordinates;\n var coordinates = currentCoordinates.getDelta(view.coordinates);\n var container = view.element;\n\n if (coordinates.x < view.daysOffset || coordinates.x > container.clientWidth ||\n coordinates.y < 0 || coordinates.y > container.clientHeight)\n coordinates = null;\n\n return coordinates;\n },\n\n prepareWithEventType: function SEDPH_prepareWithEventType(eventType) {\n var methods = { \"multiday\": this.getEventMultiDayViewCoordinates,\n \"multiday-allday\": this.getEventMultiDayAllDayViewCoordinates,\n \"monthly\": this.getEventMonthlyViewCoordinates,\n \"unknown\": null };\n var method = methods[eventType];\n this.eventType = eventType;\n this.getEventViewCoordinates = method;\n },\n\n getEventMultiDayViewCoordinates: function SEDPH_gEMultiDayViewC(view, pointerCoordinates) {\n /* x = day; y = quarter */\n var coordinates = this.getEventMultiDayAllDayViewCoordinates(view, pointerCoordinates); // get the x coordinate\n if (coordinates) {\n var quarterHeight = view.quarterHeight;\n var pxCoordinates = this.getContainerBasedCoordinates(view, pointerCoordinates);\n pxCoordinates.y += view.element.scrollTop;\n\n coordinates.y = Math.floor((pxCoordinates.y - CalendarSettings.EventDragHorizontalOffset) / quarterHeight);\n var maxY = CalendarSettings.EventDragDayLength - 1;\n if (coordinates.y < 0)\n coordinates.y = 0;\n else if (coordinates.y > maxY)\n coordinates.y = maxY;\n }\n\n return coordinates;\n },\n getEventMultiDayAllDayViewCoordinates: function SEDPH_gEMultiDayADVC(view, pointerCoordinates) {\n /* x = day; y = quarter */\n var coordinates;\n\n var pxCoordinates = this.getContainerBasedCoordinates(view, pointerCoordinates);\n if (pxCoordinates) {\n coordinates = new SOGoCoordinates();\n\n var dayWidth = view.dayWidth;\n var daysOffset = view.daysOffset;\n\n coordinates.x = Math.floor((pxCoordinates.x - daysOffset) / dayWidth);\n var maxX = Calendar.$view.maxX;\n if (coordinates.x < 0)\n coordinates.x = 0;\n else if (coordinates.x > maxX)\n coordinates.x = maxX;\n coordinates.y = 0;\n }\n else {\n coordinates = null;\n }\n\n return coordinates;\n },\n getEventMonthlyViewCoordinates: function SEDPH_gEMonthlyViewC(view, pointerCoordinates) {\n /* x = day; y = quarter */\n var coordinates;\n\n var pxCoordinates = this.getContainerBasedCoordinates(view, pointerCoordinates);\n if (pxCoordinates) {\n coordinates = new SOGoCoordinates();\n\n var daysTopOffset = 0;\n var dayWidth = view.dayWidth;\n var daysOffset = view.daysOffset;\n var dayHeight = view.dayHeight;\n var daysY = Math.floor((pxCoordinates.y - daysTopOffset) / dayHeight);\n if (daysY < 0)\n daysY = 0;\n\n coordinates.x = Math.floor((pxCoordinates.x - daysOffset) / dayWidth);\n if (coordinates.x < 0)\n coordinates.x = 0;\n else if (coordinates.x > 6)\n coordinates.x = 6;\n coordinates.x += 7 * daysY;\n coordinates.y = 0;\n }\n else {\n coordinates = null;\n }\n\n return coordinates;\n },\n\n getDistance: function SEDPH_getDistance() {\n return this.currentCoordinates.getDistance(this.originalCoordinates);\n },\n\n setTimeFromQuarters: function SEDPH_setTimeFromQuarters(date, quarters) {\n var hours, minutes;\n hours = Math.floor(quarters / 4);\n minutes = (quarters % 4) * 15;\n date.setHours(hours, minutes);\n }\n };\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgDraggableCalendarBlock', sgDraggableCalendarBlock);\n})();\n\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCalendarDayTable - Build list of blocks for a specific day\n * @memberof SOGo.Common\n * @restrict element\n * @param {object} sgBlocks - the events blocks definitions for the current view\n * @param {string} sgDay - the day of the events to display\n * @param {function} sgClick - the function to call when clicking on a block.\n * Two variables are available: event (the event that triggered the mouse click),\n * and component (a Component object)\n *\n * @example:\n\n http://www.html5rocks.com/en/tutorials/dnd/basics/\n https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_and_drop\n\n <sg-calendar-day-table\n sg-blocks=\"calendar.blocks\"\n sg-day=\"20150330\"\n sg-click=\"open({ event: clickEvent, component: clickComponent })\"/>\n */\n sgDroppableBlock.$inject = ['$rootScope', '$timeout', '$mdGesture', 'Calendar', 'CalendarSettings', 'Component'];\n function sgDroppableBlock($rootScope, $timeout, $mdGesture, Calendar, CalendarSettings, Component) {\n return {\n restrict: 'CA',\n scope: {\n onDrop: '&sgOnDrop'\n },\n link: function (scope, element, attrs, controller) {\n var deregister = $rootScope.$on('calendar:dragend', scope.onDrop);\n scope.$on('$destroy', deregister);\n }\n };\n }\n \n angular\n .module('SOGo.SchedulerUI')\n .directive('sgDroppableBlock', sgDroppableBlock);\n})();\n\n"]}