sogo/UI/WebServerResources/js/Scheduler.services.js.map
2018-03-07 11:09:20 -05:00

1 line
275 KiB
Plaintext

{"version":3,"sources":["Scheduler/Calendar.service.js","Scheduler/Component.service.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/sgCalendarListEvent.directive.js","Scheduler/sgCalendarListItem.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","Scheduler/sgNowLine.directive.js"],"names":["Calendar","futureCalendarData","this","init","name","id","newCalendarData","$$resource","create","$unwrap","$factory","$q","$timeout","$log","Settings","Resource","Preferences","Component","Acl","angular","extend","activeUser","$Preferences","$Component","$$Acl","$view","module","e","value","EventDragDayLength","EventDragHorizontalOffset","ConflictHTTPErrorCode","factory","$defaultCalendar","calendar","defaultCalendar","defaults","SOGoDefaultCalendar","_","find","$findAll","active","$add","list","sibling","isWebCalendar","$webcalendars","isSubscription","$subscriptions","$calendars","findIndex","o","i","localeCompare","push","splice","settings","FoldersOrder","saveFoldersOrder","flatMap","$reloadAll","data","writable","_this","forEach","isUndefined","fetch","then","calendars","union","filter","isOwned","acls","objectCreator","calendarData","group","owner","login","$get","$getIndex","indexOf","map","$subscribe","uid","path","userResource","$addWebCalendar","url","d","defer","urls","webCalendarURL","reject","post","isEditable","isRemote","debug","JSON","stringify","undefined","resolve","response","status","promise","reloadWebCalendars","promises","$error","l","statusText","all","$deleteComponents","components","component","isDefined","pid","uids","saveFoldersActivation","ids","request","folders","prototype","color","$acl","isSuperUser","$shadowData","$omit","$id","when","$futureCalendarData","getClassName","base","$rename","$save","$delete","remove","$reset","key","save","error","setCredentials","username","password","export","options","type","filename","download","$setActivation","$getComponent","componentId","recurrenceId","$find","isError","isObject","futureComponentData","newComponentData","newguid","isNew","$rootScope","Component_STATUS","User","Card","Gravatar","STATUS","$settings","$User","$Card","$gravatar","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","$refreshTimeout","$ghost","EventsFilterState","TasksFilterState","EventsSortingState","parseInt","TasksSortingState","show_completed","ShowCompletedTasks","$categories","SOGoCalendarCategoriesColors","SOGoTimeFormat","constant","NOT_LOADED","DELAYED_LOADING","LOADING","LOADED","DELAYED_MS","$selectedCount","count","$events","event","selected","length","$tasks","task","$startRefreshTimeout","cancel","refreshViewCheck","SOGoRefreshViewCheck","f","bind","$emit","timeInterval","$isLoading","$loaded","$filter","otherType","now","Date","day","getDate","month","getMonth","year","getFullYear","queryKey","capitalize","params","dirty","keys","$unwrapCollection","calendarId","occurrenceId","encodeURIComponent","join","filterCategories","query","re","RegExp","category","saveSelectedList","componentType","$eventsBlocksForView","view","date","firstDayOfWeek","viewAction","startDate","endDate","SOGoFirstDayOfWeek","beginOfWeek","setTime","getTime","addDays","setDate","setMonth","endOfWeek","$eventsBlocks","j","dayDates","dayNumbers","deferred","toLowerCase","sd","getDayString","ed","views","reduceComponent","associateComponent","objects","eventData","componentData","zipObject","eventsFields","start","c_startdate","hour","getHourString","blocks","block","nbr","isFirst","$views","viewIndex","viewData","allDayBlocks","reduce","events","flatten","days","dayIndex","dayNumber","calendarName","fields","invokeMap","monthData","dayData","$resetGhost","pointerHandler","startHour","endHour","$parseDate","dateString","time","substring","split","no_time","categories","repeat","alarm","action","quantity","unit","reference","relation","delta","isString","setMinutes","Math","round","getMinutes","end","minutesTo","setDelta","dueDate","due","completedDate","completed","c_category","$isRecurrent","byDayMask","occurrence","frequency","byday","toString","dates","rdate","rdates","interval","monthdays","months","until","$hasCustomRepeat","hasCustomRepeat","classification","units","M","H","D","W","match","exec","SOGoCalendarDefaultReminder","$hasAlarm","sendAppointmentNotifications","SOGoAppointmentSendEMailNotifications","destinationCalendar","attendees","attendee","image","email","updateFreeBusy","initOrganizer","results","organizer","cn","c_email","updateFreeBusyAttendee","b","isReadOnly","isEditableOccurrence","isInvitation","userHasRSVP","isInvitationOccurrence","showPercentComplete","percentComplete","enablePercentComplete","coversFreeBusy","quarter","freebusy","updateFreeBusyCoverage","roundedStart","roundedEnd","startQuarter","endQuarter","daysUpTo","index","hourKey","currentDay","dayKey","getHours","beginOfDay","addMinutes","resource","domain","sday","eday","isMSExchange","c_folder","addAttendee","card","organizerCalendar","$isList","expandable","container","c_name","listId","refs","ref","c_cn","$preferredEmail","role","partstat","c_uid","$avatarIcon","c_domain","ismsexchange","hasAttendee","emails","deleteAttendee","currentAttendee","canRemindAttendeesByEmail","addAttachUrl","attachUrl","attachUrls","deleteAttachUrl","$addDueDate","toISOString","$deleteDueDate","$addStartDate","$deleteStartDate","$addRecurrenceDate","$deleteRecurrenceDate","$reply","reply","delegatedTo","$adjust","every","values","v","extraAttributes","dlp","$mdDateLocaleProvider","format","startTime","endTime","dueTime","stringWithSeparator","occurrenceOnly","$futureComponentData","copy","repeatDescription","localizedString","toUpperCase","alarmDescription","copyTo","destination","moveTo","CalendarController","$scope","$state","$stateParams","sgHotkeys","stateEventsBlocks","_registerHotkeys","createHotkey","description","callback","changeDate","args","changeView","_goToPeriod","registerHotkey","$event","direction","vm","selectedDate","_formatDate","setHours","$dateFormat","replace","toggleAllDays","expandedAllDays","updateView","asDate","newDate","element","currentTarget","attr","go","deregisterCalendarsList","hotkeys","$onInit","$on","deregisterHotkey","$inject","controller","CalendarListController","$mdDialog","focus","Dialog","CalendarSettings","Alarm","searchMode","newComponent","selectComponentType","reload","unselectComponents","mode","multiple","selectAll","toggleComponentSelection","preventDefault","stopPropagation","confirmDeleteSelectedComponents","confirm","ok","openEvent","openComponent","openTask","viewable","templateUrl","show","parent","document","body","targetEvent","clickOutsideToClose","escapeToClose","controllerAs","locals","stateComponent","baseComponent","updateComponentFromGhost","RecurrentComponentDialogController","updateThisOccurrence","hide","onComponentAdjustError","updateAllOccurrences","message","AttendeeConflictDialogController","conflictError","ignoreConflicts","coordinates","calendarNumber","activeCalendars","currentEventCoordinates","summary","isAllDay","duration","catch","finally","getDelta","originalEventCoordinates","originalCalendar","isException","getAlarms","template","filteredBy","field","sortedBy","cancelSearch","selectedList","SelectedList","CalendarsController","$window","$mdToast","_sortableAccept","sourceItemHandleScope","destSortableScope","destItemScope","sortableScope","_sortableEnd","toggleSortableMode","sortableMode","resetSort","newCalendar","ev","prompt","UserLogin","addWebCalendar","WebCalendarAuthDialogController","scope","parts","hostname","title","formatted","authenticate","form","$valid","required","reason","$setValidity","inputType","subscribeToFolder","simple","content","position","hideDelay","service","sortableCalendars","scrollableContainer","containment","orderChanged","accept","SOGoCalendarCategories","asCSSIdentifier","$watch","pick","newList","oldList","commonList","intersectionBy","oldObject","isEqual","ComponentController","AddressBook","Account","close","highPriority","priority","cardFilter","$filterAll","newMessageWithAllRecipients","recipients","_newMessage","newMessageWithRecipient","accounts","account","$getMailboxes","mailboxes","$newMessage","editable","to","subject","stateAccount","stateMessage","edit","editAllOccurrences","c","replyAllOccurrences","deleteOccurrence","deleteAllOccurrences","toggleRawSource","ComponentRawSourceDialogController","copySelectedComponent","moveSelectedComponent","calendarService","ComponentEditorController","toggleRecurrenceEditor","showRecurrenceEditor","toggleAttendeesEditor","showAttendeesEditor","recurrenceMonthDaysAreRequired","changeFrequency","changeCalendar","updateRequired","$cards","createCard","str","emailRE","searchText","trim","address","charCodeAt","test","charAt","removeAttendee","$setDirty","priorityLevel","changeAlarmRelation","alarmRelation","attendeeConflictError","reset","$setPristine","getDays","hours","addStartDate","oldStartDate","removeStartDate","addDueDate","oldDueDate","removeDueDate","adjustStartTime","valueOf","oldEndDate","adjustEndTime","adjustDueTime","attendeesEditor","sgCalendarDay","restrict","dayString","sgCalendarDayController","directive","sgCalendarDayBlock","tElem","tAttrs","p","has","link","iElement","attrs","pc","left","right","siblings","css","c_isallday","addClass","userState","c_isopaque","c_status","clickBlock","sgCalendarDayTable","sgCalendarGhost","ctrls","initGhost","calendarDayCtrl","originalCalendarNumber","hideGhost","forEachRight","domElement","classList","removeClass","updateGhost","showGhost","isRelative","durationLeft","maxDuration","scrollViewCtrl","getStartTime","quarterHeight","topOffset","getEndTime","quartersToHM","quarters","minutes","mins","floor","deregisterDragStart","deregisterDrag","deregisterDragEnd","require","sgCalendarListEvent","userstate","clickComponent","sgCalendarListItem","bindToController","sgCalendarListItemController","$element","$mdPanel","$mdMedia","$mdSidenav","sgConstant","$ctrl","editMode","$postLink","clickableElement","nameElements","getElementsByClassName","inputContainer","inputElement","moreOptionsButton","last","updateCalendarName","innerHTML","editFolder","add","select","saveFolder","disabled","revertEditing","confirmDelete","alert","showMenu","MenuController","mdPanelRef","FileUploader","$menuCtrl","showOnly","showAll","showProperties","PropertiesDialogController","srcCalendar","saveProperties","showLinks","LinksDialogController","importCalendar","CalendarImportDialogController","folder","filterByExtension","item","isTextFile","uploader","ApplicationBaseURL","autoUpload","queueLimit","filters","fn","onSuccessItem","headers","msg","imported","onErrorItem","share","$users","usersWithACL","users","panelPosition","newPanelPosition","relativeTo","addPanelPosition","xPosition","ALIGN_START","yPosition","ALIGN_TOPS","panelAnimation","newPanelAnimation","openFrom","withAnimation","animation","FADE","config","attachTo","itemCtrl","trapFocus","focusOnOpen","open","panelRef","panelEl","one","sgCalendarMonthDay","sgCalendarMonthEvent","sgCalendarScrollView","$document","$mdGesture","sgCalendarScrollViewController","initView","sgScrollView","hourCell","quartersOffset","SOGoDayStartTime","getElementById","scrollTop","offsetTop","getQuarterHeight","scrollStep","getDayNumbers","maxX","getMaxColumns","onDragStart","deregisterDragStop","onDragEnd","bindedUpdateCoordinates","updateCoordinates","bindedUpdateFromPointerHandler","updateFromPointerHandler","on","isMultiColumn","$destroy","off","hour0","hour23","height","getDayDimensions","viewLeft","width","leftOffset","nodes","domRect","tileHeader","getBoundingClientRect","clientHeight","offset","top","getElementsByTagName","el","attributes","mdGridList","max","dayDimensions","x","y","dayHeight","dayWidth","daysOffset","pointerCoordinates","scrollY","minY","getContainerBasedCoordinates","lastScroll","sgCalendarTable","blocksType","sgCategoryStylesheet","ngModel","sgDraggableCalendarBlock","initGrips","blockIndex","isFirstBlock","isLastBlock","dragGrip","leftGrip","rightGrip","topGrip","bottomGrip","parentNode","tagName","append","clone","onDragDetect","dragMode","hasVerticalScrollbar","rect","scrollableZone","target","scrollHeight","pageX","className","SOGoEventDragPointerHandler","initFromEvent","onDrag","dragStart","eventType","isHourCell","isMonthly","newData","hasClass","parseDate","dragging","prepareWithEventType","initFromBlock","initFromCalendar","updateFromEvent","pointer","dragHasStarted","SOGoCoordinates","SOGoEventDragEventCoordinates","setEventType","otherCoordinates","getDistance","sqrt","weekDay","prevDayNumber","sumBy","currentDayNumber","_quartersToHM","originalCoordinates","currentCoordinates","originalViewCoordinates","currentViewCoordinates","getEventViewCoordinates","pageY","newEventCoordinates","setTimeFromQuarters","updateEventCoordinates","distance","newDuration","deltaQuarters","deltaDays","ceil","clientWidth","methods","multiday","getEventMultiDayViewCoordinates","multiday-allday","getEventMultiDayAllDayViewCoordinates","monthly","getEventMonthlyViewCoordinates","unknown","method","pxCoordinates","maxY","minX","daysTopOffset","daysY","sgDroppableBlock","onDrop","deregister","sgNowLine","iAttr","sgCalendarScrollViewCtrl","_getDays","_getView","_unwatchView","_unwatchDays","updateLine","sgNowLineController","_updateLine","force","nowDay","hourHeight","minuteHeight","lineElement","_addLine","updater","$lineElement","dayElement","eq"],"mappings":"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","file":"Scheduler.services.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Calendar\n * @constructor\n * @param {object} futureCalendarData - either an object literal or a promise\n */\n function Calendar(futureCalendarData) {\n // Data is immediately available\n this.init(futureCalendarData);\n if (this.name && !this.id) {\n // Create a new calendar on the server\n var newCalendarData = Calendar.$$resource.create('createFolder', this.name);\n this.$unwrap(newCalendarData);\n }\n }\n\n /**\n * @memberof Calendar\n * @desc The factory we'll use to register with Angular\n * @returns the Calendar constructor\n */\n Calendar.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Preferences', 'Component', 'Acl', function($q, $timeout, $log, Settings, Resource, Preferences, Component, Acl) {\n angular.extend(Calendar, {\n $q: $q,\n $timeout: $timeout,\n $log: $log,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Calendar', Settings.activeUser()),\n $Preferences: Preferences,\n $Component: Component,\n $$Acl: Acl,\n activeUser: Settings.activeUser(),\n $view: null\n });\n\n return Calendar; // return constructor\n }];\n\n /**\n * @module SOGo.SchedulerUI\n * @desc Factory registration of Calendar in Angular module.\n */\n try {\n angular.module('SOGo.SchedulerUI');\n }\n catch(e) {\n angular.module('SOGo.SchedulerUI', ['SOGo.Common']);\n }\n angular.module('SOGo.SchedulerUI')\n .value('CalendarSettings', {\n EventDragDayLength: 24 * 4, // hour quarters\n EventDragHorizontalOffset: 3, // pixels\n ConflictHTTPErrorCode: 409\n })\n .factory('Calendar', Calendar.$factory);\n\n /**\n * @memberof Calendar\n * @desc Return the default calendar id according to the user's defaults.\n * @returns a calendar id\n */\n Calendar.$defaultCalendar = function() {\n var defaultCalendar = Calendar.$Preferences.defaults.SOGoDefaultCalendar,\n calendar;\n\n if (defaultCalendar == 'first') {\n calendar = _.find(Calendar.$findAll(null, true), function(calendar) {\n return calendar.active;\n });\n if (calendar)\n return calendar.id;\n }\n\n return 'personal';\n };\n\n /**\n * @memberof Calendar\n * @desc Add a new calendar to the static list of calendars\n * @param {Calendar} calendar - an Calendar object instance\n */\n Calendar.$add = function(calendar) {\n // Insert new calendar at proper index\n var list, sibling;\n\n if (calendar.isWebCalendar)\n list = this.$webcalendars;\n else if (calendar.isSubscription)\n list = this.$subscriptions;\n else\n list = this.$calendars;\n\n sibling = _.findIndex(list, function(o, i) {\n return (calendar.id == 'personal' ||\n (o.id != 'personal' && o.name.localeCompare(calendar.name) > 0));\n });\n if (sibling < 0)\n list.push(calendar);\n else\n list.splice(sibling, 0, calendar);\n\n if (Calendar.$Preferences.settings.Calendar.FoldersOrder)\n // Save list order\n Calendar.saveFoldersOrder(_.flatMap(Calendar.$findAll(), 'id'));\n // Refresh list of calendars to fetch links associated to new calendar\n Calendar.$reloadAll();\n };\n\n /**\n * @memberof Calendar\n * @desc Set or get the list of calendars. Will instanciate a new Calendar object for each item.\n * @param {object[]} [data] - the metadata of the calendars\n * @param {bool} [writable] - if true, returns only the list of writable calendars\n * @returns the list of calendars\n */\n Calendar.$findAll = function(data, writable) {\n var _this = this;\n if (data) {\n this.$calendars = [];\n this.$subscriptions = [];\n this.$webcalendars = [];\n // Instanciate Calendar objects\n angular.forEach(data, function(o, i) {\n var calendar = new Calendar(o);\n if (calendar.isWebCalendar)\n _this.$webcalendars.push(calendar);\n else if (calendar.isSubscription)\n _this.$subscriptions.push(calendar);\n else\n _this.$calendars.push(calendar);\n });\n }\n else if (angular.isUndefined(this.$calendars)) {\n this.$calendars = [];\n this.$subscriptions = [];\n this.$webcalendars = [];\n return Calendar.$$resource.fetch('calendarslist').then(function(data) {\n return Calendar.$findAll(data.calendars, writable);\n });\n }\n\n if (writable) {\n return _.union(this.$calendars, _.filter(this.$subscriptions, function(calendar) {\n return calendar.isOwned || calendar.acls.objectCreator;\n }));\n }\n\n return _.union(this.$calendars, this.$subscriptions, this.$webcalendars);\n };\n\n /**\n * @memberof Calendar\n * @desc Reload the list of known calendars.\n */\n Calendar.$reloadAll = function() {\n var _this = this;\n\n Calendar.$$resource.fetch('calendarslist').then(function(data) {\n _.forEach(data.calendars, function(calendarData) {\n var group, calendar;\n\n if (calendarData.isWebCalendar)\n group = _this.$webcalendars;\n else if (calendarData.owner != Calendar.activeUser.login)\n group = _this.$subscriptions;\n else\n group = _this.$calendars;\n\n calendar = _.find(group, function(o) { return o.id == calendarData.id; });\n if (calendar)\n calendar.init(calendarData);\n });\n });\n };\n\n /**\n * @memberof Calendar\n * @desc Find a calendar among local instances (personal calendars, subscriptions and Web calendars).\n * @param {string} id - the calendar ID\n * @returns an object literal of the matching Calendar instance\n */\n Calendar.$get = function(id) {\n var calendar;\n\n calendar = _.find(Calendar.$calendars, function(o) { return o.id == id; });\n if (!calendar)\n calendar = _.find(Calendar.$subscriptions, function(o) { return o.id == id; });\n if (!calendar)\n calendar = _.find(Calendar.$webcalendars, function(o) { return o.id == id; });\n\n return calendar;\n };\n\n /**\n * @memberof Calendar\n * @desc Find a calendar among local instances (personal calendars, subscriptions and Web calendars).\n * @param {string} id - the calendar ID\n * @returns an object literal of the matching Calendar instance\n */\n Calendar.$getIndex = function(id) {\n var i;\n\n i = _.indexOf(_.map(Calendar.$calendars, 'id'), id);\n if (i < 0)\n i = _.indexOf(_.map(Calendar.$subscriptions, 'id'), id);\n if (i < 0)\n i = _.indexOf(_.map(Calendar.$webcalendars, 'id'), id);\n\n return i;\n };\n\n /**\n * @memberOf Calendar\n * @desc Subscribe to another user's calendar and add it to the list of calendars.\n * @param {string} uid - user id\n * @param {string} path - path of folder for specified user\n * @returns a promise of the HTTP query result\n */\n Calendar.$subscribe = function(uid, path) {\n var _this = this;\n return Calendar.$$resource.userResource(uid).fetch(path, 'subscribe').then(function(calendarData) {\n var calendar = new Calendar(angular.extend({ active: 1 }, calendarData));\n if (!_.find(_this.$subscriptions, function(o) {\n return o.id == calendarData.id;\n })) {\n Calendar.$add(calendar);\n }\n return calendar;\n });\n };\n\n /**\n * @memberOf Calendar\n * @desc Subscribe to a remote Web calendar\n * @param {string} url - URL of .ics file\n * @returns a promise of the HTTP query result\n */\n Calendar.$addWebCalendar = function(url) {\n var _this = this,\n d = Calendar.$q.defer();\n\n if (_.find(_this.$webcalendars, function(o) {\n return o.urls.webCalendarURL == url;\n })) {\n // Already subscribed\n d.reject();\n }\n else {\n Calendar.$$resource.post(null, 'addWebCalendar', { url: url }).then(function(calendarData) {\n angular.extend(calendarData, {\n isWebCalendar: true,\n isEditable: true,\n isRemote: false,\n owner: Calendar.activeUser.login,\n urls: { webCalendarURL: url }\n });\n var calendar = new Calendar(calendarData);\n Calendar.$$resource.fetch(calendar.id, 'reload').then(function(data) {\n // TODO: show a toast of the reload status\n Calendar.$log.debug(JSON.stringify(data, undefined, 2));\n Calendar.$add(calendar);\n d.resolve();\n }, function(response) {\n if (response.status == 401) {\n // Web calendar requires authentication\n d.resolve(calendar);\n }\n else {\n d.reject();\n }\n });\n }, d.reject);\n }\n\n return d.promise;\n };\n\n /**\n * @function reloadWebCalendars\n * @memberof Calendar\n * @desc Reload all Web calendars\n * @return a promise combining the results of all HTTP operations\n */\n Calendar.reloadWebCalendars = function() {\n var promises = [];\n\n _.forEach(this.$webcalendars, function(calendar) {\n var promise = Calendar.$$resource.fetch(calendar.id, 'reload');\n promise.then(function(data) {\n calendar.$error = false;\n }, function(response) {\n calendar.$error = l(response.statusText);\n });\n promises.push(promise);\n });\n\n return Calendar.$q.all(promises);\n };\n\n /**\n * @function $deleteComponents\n * @memberof Calendar\n * @desc Delete multiple components from calendar.\n * @return a promise of the HTTP operation\n */\n Calendar.$deleteComponents = function(components) {\n var _this = this, calendars = {}, promises = [];\n\n _.forEach(components, function(component) {\n if (!angular.isDefined(calendars[component.pid]))\n calendars[component.pid] = [];\n calendars[component.pid].push(component.id);\n });\n\n _.forEach(calendars, function(uids, pid) {\n promises.push(Calendar.$$resource.post(pid, 'batchDelete', {uids: uids}));\n });\n\n return Calendar.$q.all(promises);\n };\n\n /**\n * @function saveFoldersActivation\n * @memberof Calendar\n * @desc Save to the user's settings the activation state of the calendars\n * @param {string[]} folders - the folders IDs\n * @returns a promise of the HTTP operation\n */\n Calendar.saveFoldersActivation = function(ids) {\n var request = {};\n\n _.forEach(ids, function(id) {\n var calendar = Calendar.$get(id);\n request[calendar.id] = calendar.active;\n });\n\n return Calendar.$$resource.post(null, 'saveFoldersActivation', request);\n };\n\n /**\n * @function saveFoldersOrder\n * @desc Save to the user's settings the current calendars order.\n * @param {string[]} folders - the folders IDs\n * @returns a promise of the HTTP operation\n */\n Calendar.saveFoldersOrder = function(folders) {\n return this.$$resource.post(null, 'saveFoldersOrder', { folders: folders }).then(function() {\n Calendar.$Preferences.settings.Calendar.FoldersOrder = folders;\n if (!folders)\n // Calendars order was reset; reload list\n return Calendar.$$resource.fetch('calendarslist').then(function(data) {\n return Calendar.$findAll(data.calendars);\n });\n });\n };\n\n /**\n * @function init\n * @memberof Calendar.prototype\n * @desc Extend instance with new data and compute additional attributes.\n * @param {object} data - attributes of calendar\n */\n Calendar.prototype.init = function(data) {\n this.color = this.color || '#AAAAAA';\n this.active = 1;\n angular.extend(this, data);\n if (this.id) {\n this.$acl = new Calendar.$$Acl('Calendar/' + this.id);\n }\n // Add 'isOwned' and 'isSubscription' attributes based on active user (TODO: add it server-side?)\n this.isOwned = Calendar.activeUser.isSuperUser || this.owner == Calendar.activeUser.login;\n this.isSubscription = !this.isRemote && this.owner != Calendar.activeUser.login;\n if (angular.isUndefined(this.$shadowData)) {\n // Make a copy of the data for an eventual reset\n this.$shadowData = this.$omit();\n }\n };\n\n /**\n * @function $id\n * @memberof Calendar.prototype\n * @desc Resolve the calendar id.\n * @returns a promise of the calendar id\n */\n Calendar.prototype.$id = function() {\n if (this.id) {\n // Object already unwrapped\n return Calendar.$q.when(this.id);\n }\n else {\n // Wait until object is unwrapped\n return this.$futureCalendarData.then(function(calendar) {\n return calendar.id;\n });\n }\n };\n\n /**\n * @function getClassName\n * @memberof Calendar.prototype\n * @desc Return the calendar CSS class name based on its ID.\n * @returns a string representing the foreground CSS class name\n */\n Calendar.prototype.getClassName = function(base) {\n if (angular.isUndefined(base))\n base = 'fg';\n return base + '-folder' + this.id;\n };\n\n /**\n * @function $rename\n * @memberof Calendar.prototype\n * @desc Rename the calendar and keep the list sorted\n * @param {string} name - the new name\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.$rename = function() {\n var _this = this,\n i,\n calendars;\n\n if (this.name == this.$shadowData.name) {\n // Name hasn't changed\n return Calendar.$q.when();\n }\n\n if (this.isWebCalendar)\n calendars = Calendar.$webcalendars;\n else if (this.isSubscription)\n calendars = Calendar.$subscriptions;\n else\n calendars = Calendar.$calendars;\n\n i = _.indexOf(_.map(calendars, 'id'), this.id);\n if (i > -1) {\n return this.$save().then(function() {\n calendars.splice(i, 1);\n Calendar.$add(_this);\n });\n }\n else {\n return Calendar.$q.reject();\n }\n };\n\n /**\n * @function $delete\n * @memberof Calendar.prototype\n * @desc Delete the calendar from the server and the static list of calendars.\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.$delete = function() {\n var _this = this,\n list,\n promise;\n\n if (this.isSubscription) {\n promise = Calendar.$$resource.fetch(this.id, 'unsubscribe');\n list = Calendar.$subscriptions;\n }\n else {\n promise = Calendar.$$resource.remove(this.id);\n if (this.isWebCalendar)\n list = Calendar.$webcalendars;\n else\n list = Calendar.$calendars;\n }\n\n return promise.then(function() {\n var i = _.indexOf(_.map(list, 'id'), _this.id);\n list.splice(i, 1);\n });\n };\n\n /**\n * @function $reset\n * @memberof Calendar.prototype\n * @desc Reset the original state the calendar's data.\n */\n Calendar.prototype.$reset = function() {\n var _this = this;\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n delete _this[key];\n }\n });\n angular.extend(this, this.$shadowData);\n this.$shadowData = this.$omit();\n };\n\n /**\n * @function $save\n * @memberof Calendar.prototype\n * @desc Save the calendar properties to the server.\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.$save = function() {\n var _this = this;\n\n return Calendar.$$resource.save(this.id, this.$omit()).then(function(data) {\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit();\n return data;\n }, function(data) {\n Calendar.$log.error(JSON.stringify(data, undefined, 2));\n // Restore previous version\n _this.$reset();\n return data;\n });\n };\n\n /**\n * @function setCredentials\n * @memberof Calendar.prototype\n * @desc Set the credentials for a Web calendar that requires authentication\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.setCredentials = function(username, password) {\n var _this = this,\n d = Calendar.$q.defer();\n\n Calendar.$$resource.post(this.id, 'set-credentials', { username: username, password: password }).then(function() {\n Calendar.$$resource.fetch(_this.id, 'reload').then(function(data) {\n Calendar.$add(_this);\n d.resolve();\n }, function(response) {\n if (response.status == 401) {\n // Authentication failed\n d.reject(l('Wrong username or password'));\n }\n else {\n d.reject(response.statusText);\n }\n });\n }, d.reject);\n\n return d.promise;\n };\n\n /**\n * @function export\n * @memberof Calendar.prototype\n * @desc Export the calendar\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.export = function() {\n var options;\n\n options = {\n type: 'application/octet-stream',\n filename: this.name + '.ics'\n };\n\n return Calendar.$$resource.download(this.id + '.ics', 'export', null, options);\n };\n\n /**\n * @function $setActivation\n * @memberof Calendar.prototype\n * @desc Either activate or deactivate the calendar.\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.$setActivation = function() {\n return Calendar.$$resource.fetch(this.id, (this.active?'':'de') + 'activateFolder');\n };\n\n /**\n * @function $getComponent\n * @memberof Calendar.prototype\n * @desc Fetch a component attributes from the server.\n * @returns a promise of the HTTP operation\n */\n Calendar.prototype.$getComponent = function(componentId, recurrenceId) {\n return Calendar.$Component.$find(this.id, componentId, recurrenceId);\n };\n\n /**\n * @function $unwrap\n * @memberof Calendar.prototype\n * @desc Unwrap a promise\n * @param {promise} futureCalendarData - a promise of the Calendar's data\n */\n Calendar.prototype.$unwrap = function(futureCalendarData) {\n var _this = this;\n\n // Expose and resolve the promise\n this.$futureCalendarData = futureCalendarData.then(function(data) {\n return Calendar.$timeout(function() {\n // Extend Calendar instance with received data\n _this.init(data);\n return _this;\n });\n }, function(data) {\n _this.isError = true;\n if (angular.isObject(data)) {\n Calendar.$timeout(function() {\n angular.extend(_this, data);\n });\n }\n });\n };\n\n /**\n * @function $omit\n * @memberof Calendar.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the Calendar instance\n */\n Calendar.prototype.$omit = function() {\n var calendar = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' &&\n key[0] != '$') {\n calendar[key] = value;\n }\n });\n return calendar;\n };\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Component\n * @constructor\n * @param {object} futureComponentData - either an object literal or a promise\n */\n function Component(futureComponentData) {\n // Data is immediately available\n if (typeof futureComponentData.then !== 'function') {\n this.init(futureComponentData);\n if (this.pid && !this.id) {\n // Prepare for the creation of a new component;\n // Get UID from the server.\n var newComponentData = Component.$$resource.newguid(this.pid);\n this.$unwrap(newComponentData);\n this.isNew = true;\n }\n }\n else {\n // The promise will be unwrapped first\n this.$unwrap(futureComponentData);\n }\n }\n\n /**\n * @memberof Component\n * @desc The factory we'll use to register with Angular\n * @returns the Component constructor\n */\n Component.$factory = ['$q', '$timeout', '$log', '$rootScope', 'sgSettings', 'sgComponent_STATUS', 'Preferences', 'User', 'Card', 'Gravatar', 'Resource', function($q, $timeout, $log, $rootScope, Settings, Component_STATUS, Preferences, User, Card, Gravatar, Resource) {\n angular.extend(Component, {\n STATUS: Component_STATUS,\n $q: $q,\n $timeout: $timeout,\n $log: $log,\n $rootScope: $rootScope,\n $settings: Settings,\n $User: User,\n $Preferences: Preferences,\n $Card: Card,\n $gravatar: Gravatar,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Calendar', Settings.activeUser()),\n timeFormat: \"%H:%M\",\n // Filter parameters common to events and tasks\n $query: { value: '', search: 'title_Category_Location' },\n // Filter paramaters specific to events\n $queryEvents: { sort: 'start', asc: 1, filterpopup: 'view_next7' },\n // Filter parameters specific to tasks\n $queryTasks: { sort: 'status', asc: 1, filterpopup: 'view_incomplete' },\n $refreshTimeout: null,\n $ghost: {}\n });\n // Initialize filter parameters from user's settings\n if (Preferences.settings.Calendar.EventsFilterState)\n Component.$queryEvents.filterpopup = Preferences.settings.Calendar.EventsFilterState;\n if (Preferences.settings.Calendar.TasksFilterState)\n Component.$queryTasks.filterpopup = Preferences.settings.Calendar.TasksFilterState;\n if (Preferences.settings.Calendar.EventsSortingState) {\n Component.$queryEvents.sort = Preferences.settings.Calendar.EventsSortingState[0];\n Component.$queryEvents.asc = parseInt(Preferences.settings.Calendar.EventsSortingState[1]);\n }\n if (Preferences.settings.Calendar.TasksSortingState) {\n Component.$queryTasks.sort = Preferences.settings.Calendar.TasksSortingState[0];\n Component.$queryTasks.asc = parseInt(Preferences.settings.Calendar.TasksSortingState[1]);\n }\n Component.$queryTasks.show_completed = parseInt(Preferences.settings.ShowCompletedTasks);\n // Initialize categories from user's defaults\n Component.$categories = Preferences.defaults.SOGoCalendarCategoriesColors;\n // Initialize time format from user's defaults\n if (Preferences.defaults.SOGoTimeFormat) {\n Component.timeFormat = Preferences.defaults.SOGoTimeFormat;\n }\n\n return Component; // return constructor\n }];\n\n /**\n * @module SOGo.SchedulerUI\n * @desc Factory registration of Component in Angular module.\n */\n try {\n angular.module('SOGo.SchedulerUI');\n }\n catch(e) {\n angular.module('SOGo.SchedulerUI', ['SOGo.Common']);\n }\n angular.module('SOGo.SchedulerUI')\n .constant('sgComponent_STATUS', {\n NOT_LOADED: 0,\n DELAYED_LOADING: 1,\n LOADING: 2,\n LOADED: 3,\n DELAYED_MS: 300\n })\n .factory('Component', Component.$factory);\n\n /**\n * @function $selectedCount\n * @memberof Component\n * @desc Return the number of events or tasks selected by the user.\n * @returns the number of selected events or tasks\n */\n Component.$selectedCount = function() {\n var count;\n\n count = 0;\n if (Component.$events) {\n count += (_.filter(Component.$events, function(event) { return event.selected; })).length;\n }\n if (Component.$tasks) {\n count += (_.filter(Component.$tasks, function(task) { return task.selected; })).length;\n }\n return count;\n };\n\n /**\n * @function $startRefreshTimeout\n * @memberof Component\n * @desc Starts the refresh timeout for the current selected list (events or tasks) and\n * current view.\n */\n Component.$startRefreshTimeout = function(type) {\n if (Component.$refreshTimeout)\n Component.$timeout.cancel(Component.$refreshTimeout);\n\n // Restart the refresh timer, if needed\n var refreshViewCheck = Component.$Preferences.defaults.SOGoRefreshViewCheck;\n if (refreshViewCheck && refreshViewCheck != 'manually') {\n var f = angular.bind(Component.$rootScope, Component.$rootScope.$emit, 'calendars:list');\n Component.$refreshTimeout = Component.$timeout(f, refreshViewCheck.timeInterval()*1000);\n }\n };\n\n /**\n * @function $isLoading\n * @memberof Component\n * @returns true if the components list is still being retrieved from server after a specific delay\n * @see sgMessage_STATUS\n */\n Component.$isLoading = function() {\n return Component.$loaded == Component.STATUS.LOADING;\n };\n\n /**\n * @function $filter\n * @memberof Component\n * @desc Search for components matching some criterias\n * @param {string} type - either 'events' or 'tasks'\n * @param {object} [options] - additional options to the query\n * @returns a collection of Components instances\n */\n Component.$filter = function(type, options) {\n var _this = this,\n now = new Date(),\n day = now.getDate(),\n month = now.getMonth() + 1,\n year = now.getFullYear(),\n queryKey = '$query' + type.capitalize(),\n params = {\n day: '' + year + (month < 10?'0':'') + month + (day < 10?'0':'') + day,\n },\n futureComponentData,\n dirty = false,\n otherType;\n\n Component.$startRefreshTimeout(type);\n\n angular.extend(this.$query, params);\n\n if (options) {\n _.forEach(_.keys(options), function(key) {\n // Query parameters common to events and tasks are compared\n dirty |= (_this.$query[key] && options[key] != Component.$query[key]);\n if (key == 'reload' && options[key])\n dirty = true;\n // Update either the common parameters or the type-specific parameters\n else if (angular.isDefined(_this.$query[key]))\n _this.$query[key] = options[key];\n else\n _this[queryKey][key] = options[key];\n });\n }\n\n // Perform query with both common and type-specific parameters\n futureComponentData = this.$$resource.fetch(null, type + 'list',\n angular.extend(this[queryKey], this.$query));\n\n // Invalidate cached results of other type if $query has changed\n if (dirty) {\n otherType = (type == 'tasks')? '$events' : '$tasks';\n delete Component[otherType];\n Component.$log.debug('force reload of ' + otherType);\n }\n\n return this.$unwrapCollection(type, futureComponentData);\n };\n\n /**\n * @function $find\n * @desc Fetch a component from a specific calendar.\n * @param {string} calendarId - the calendar ID\n * @param {string} componentId - the component ID\n * @param {string} [occurrenceId] - the component ID\n * @see {@link Calendar.$getComponent}\n */\n Component.$find = function(calendarId, componentId, occurrenceId) {\n var futureComponentData, path = [calendarId, encodeURIComponent(componentId)];\n\n if (occurrenceId)\n path.push(occurrenceId);\n\n futureComponentData = this.$$resource.fetch(path.join('/'), 'view');\n\n return new Component(futureComponentData);\n };\n\n /**\n * @function filterCategories\n * @desc Search for categories matching some criterias\n * @param {string} search - the search string to match\n * @returns a collection of strings\n */\n Component.filterCategories = function(query) {\n var re = new RegExp(query, 'i');\n return _.filter(_.keys(Component.$categories), function(category) {\n return category.search(re) != -1;\n });\n };\n\n /**\n * @function saveSelectedList\n * @desc Save to the user's settings the currently selected list.\n * @param {string} componentType - either \"events\" or \"tasks\"\n * @returns a promise of the HTTP operation\n */\n Component.saveSelectedList = function(componentType) {\n return this.$$resource.post(null, 'saveSelectedList', { list: componentType + 'ListView' });\n };\n\n /**\n * @function $eventsBlocksForView\n * @desc Events blocks for a specific week\n * @param {string} view - Either 'day' or 'week'\n * @param {Date} type - Date of any day of the desired period\n * @returns a promise of a collection of objects describing the events blocks\n */\n Component.$eventsBlocksForView = function(view, date) {\n var firstDayOfWeek, viewAction, startDate, endDate, params;\n\n firstDayOfWeek = Component.$Preferences.defaults.SOGoFirstDayOfWeek;\n if (view == 'day') {\n viewAction = 'dayView';\n startDate = endDate = date;\n }\n else if (view == 'multicolumnday') {\n viewAction = 'multicolumndayView';\n startDate = endDate = date;\n }\n else if (view == 'week') {\n viewAction = 'weekView';\n startDate = date.beginOfWeek(firstDayOfWeek);\n endDate = new Date();\n endDate.setTime(startDate.getTime());\n endDate.addDays(6);\n }\n else if (view == 'month') {\n viewAction = 'monthView';\n startDate = date;\n startDate.setDate(1);\n startDate = startDate.beginOfWeek(firstDayOfWeek);\n endDate = new Date();\n endDate.setTime(date.getTime());\n endDate.setMonth(endDate.getMonth() + 1);\n endDate.addDays(-1);\n endDate = endDate.endOfWeek(firstDayOfWeek);\n }\n return this.$eventsBlocks(viewAction, startDate, endDate);\n };\n\n /**\n * @function $eventsBlocks\n * @desc Events blocks for a specific view and period\n * @param {string} view - Either 'day', 'multicolumnday', 'week' or 'month'\n * @param {Date} startDate - period's start date\n * @param {Date} endDate - period's end date\n * @returns a promise of a collection of objects describing the events blocks\n */\n Component.$eventsBlocks = function(view, startDate, endDate) {\n var params, futureComponentData, i, j, dayDates = [], dayNumbers = [],\n deferred = Component.$q.defer();\n\n params = { view: view.toLowerCase(), sd: startDate.getDayString(), ed: endDate.getDayString() };\n futureComponentData = this.$$resource.fetch(null, 'eventsblocks', params);\n futureComponentData.then(function(views) {\n var reduceComponent, associateComponent;\n\n reduceComponent = function(objects, eventData, i) {\n var componentData = _.zipObject(this.eventsFields, eventData),\n start = new Date(componentData.c_startdate * 1000),\n component;\n componentData.hour = start.getHourString();\n componentData.blocks = [];\n component = new Component(componentData);\n objects.push(component);\n return objects;\n };\n\n associateComponent = function(block) {\n this[block.nbr].blocks.push(block); // Associate block to component\n block.component = this[block.nbr]; // Associate component to block\n block.isFirst = (this[block.nbr].blocks.length == 1);\n };\n\n Component.$views = [];\n Component.$timeout(function() {\n _.forEach(views, function(data, viewIndex) {\n var components = [], blocks = {}, allDayBlocks = {}, viewData;\n\n // Change some attributes names\n data.eventsFields.splice(_.indexOf(data.eventsFields, 'c_folder'), 1, 'pid');\n data.eventsFields.splice(_.indexOf(data.eventsFields, 'c_name'), 1, 'id');\n data.eventsFields.splice(_.indexOf(data.eventsFields, 'c_recurrence_id'), 1, 'occurrenceId');\n data.eventsFields.splice(_.indexOf(data.eventsFields, 'c_title'), 1, 'summary');\n\n // Instantiate Component objects\n _.reduce(data.events, _.bind(reduceComponent, data), components);\n\n // Associate Component objects to blocks positions\n _.forEach(_.flatten(data.blocks), _.bind(associateComponent, components));\n\n // Associate Component objects to all-day blocks positions\n _.forEach(_.flatten(data.allDayBlocks), _.bind(associateComponent, components));\n\n // Build array of dates\n if (dayDates.length === 0) {\n dayDates = _.flatMap(data.days, 'date');\n dayNumbers = _.flatMap(data.days, 'number');\n }\n\n // Convert array of blocks to an object literal with date strings as keys\n for (i = 0; i < data.blocks.length; i++) {\n for (j = 0; j < data.blocks[i].length; j++) {\n data.blocks[i][j].dayIndex = i + (viewIndex * data.blocks.length);\n data.blocks[i][j].dayNumber = dayNumbers[i];\n }\n blocks[dayDates[i]] = data.blocks[i];\n }\n\n // Convert array of all-day blocks to object with days as keys\n for (i = 0; i < data.allDayBlocks.length; i++) {\n for (j = 0; j < data.allDayBlocks[i].length; j++) {\n data.allDayBlocks[i][j].dayIndex = i + (viewIndex * data.allDayBlocks.length);\n data.allDayBlocks[i][j].dayNumber = dayNumbers[i];\n }\n allDayBlocks[dayDates[i]] = data.allDayBlocks[i];\n }\n\n // \"blocks\" is now an object literal with the following structure:\n // { day: [\n // { start: number,\n // length: number,\n // siblings: number,\n // realSiblings: number,\n // position: number,\n // nbr: number,\n // component: Component },\n // .. ],\n // .. }\n //\n // Where day is a string with format YYYYMMDD\n\n Component.$log.debug('blocks ready (' + _.flatten(data.blocks).length + ')');\n Component.$log.debug('all day blocks ready (' + _.flatten(data.allDayBlocks).length + ')');\n\n // Save the blocks to the object model\n viewData = { blocks: blocks, allDayBlocks: allDayBlocks };\n if (data.id && data.calendarName) {\n // The multicolumnday view also includes calendar information\n viewData.id = data.id;\n viewData.calendarName = data.calendarName;\n }\n Component.$views.push(viewData);\n });\n\n deferred.resolve(Component.$views);\n });\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function $unwrapCollection\n * @desc Unwrap a promise and instanciate new Component objects using received data.\n * @param {string} type - either 'events' or 'tasks'\n * @param {promise} futureComponentData - a promise of the components' metadata\n * @returns a promise of the HTTP operation\n */\n Component.$unwrapCollection = function(type, futureComponentData) {\n var _this = this,\n components = [];\n\n // Components list is not loaded yet\n Component.$loaded = Component.STATUS.DELAYED_LOADING;\n Component.$timeout(function() {\n if (Component.$loaded != Component.STATUS.LOADED)\n Component.$loaded = Component.STATUS.LOADING;\n }, Component.STATUS.DELAYED_MS);\n\n return futureComponentData.then(function(data) {\n return Component.$timeout(function() {\n var fields = _.invokeMap(data.fields, 'toLowerCase');\n fields.splice(_.indexOf(fields, 'c_folder'), 1, 'pid');\n fields.splice(_.indexOf(fields, 'c_name'), 1, 'id');\n fields.splice(_.indexOf(fields, 'c_recurrence_id'), 1, 'occurrenceId');\n\n // Instanciate Component objects\n\n if (type == 'events') {\n _.forEach(data[type], function(monthData, month) {\n _.forEach(monthData.days, function(dayData, day) {\n _.forEach(dayData.events, function(componentData, i) {\n var data = _.zipObject(fields, componentData), component;\n component = new Component(data);\n dayData.events[i] = component;\n });\n });\n });\n components = data[type];\n }\n else if (type == 'tasks') {\n _.reduce(data[type], function(components, componentData, i) {\n var data = _.zipObject(fields, componentData), component;\n component = new Component(data);\n components.push(component);\n return components;\n }, components);\n }\n\n Component.$log.debug('list of ' + type + ' ready (' + components.length + ')');\n\n // Save the list of components to the object model\n Component['$' + type] = components;\n\n Component.$loaded = Component.STATUS.LOADED;\n\n return components;\n });\n });\n };\n\n /**\n * @function $resetGhost\n * @desc Prepare the ghost object for the next drag by resetting appropriate attributes\n */\n Component.$resetGhost = function() {\n this.$ghost.pointerHandler = null;\n this.$ghost.component = null;\n this.$ghost.startHour = null;\n this.$ghost.endHour = null;\n };\n\n /**\n * @function $parseDate\n * @desc Parse a date string with format YYYY-MM-DDTHH:MM\n * @param {string} dateString - the string representing the date\n * @param {object} [options] - additional options (use {no_time: true} to ignore the time)\n * @returns a date object\n */\n Component.$parseDate = function(dateString, options) {\n var date, time;\n\n date = dateString.substring(0,10).split('-');\n\n if (options && options.no_time)\n return new Date(parseInt(date[0]), parseInt(date[1]) - 1, parseInt(date[2]));\n\n time = dateString.substring(11,16).split(':');\n\n return new Date(parseInt(date[0]), parseInt(date[1]) - 1, parseInt(date[2]),\n parseInt(time[0]), parseInt(time[1]), 0, 0);\n };\n\n /**\n * @function init\n * @memberof Component.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of component\n */\n Component.prototype.init = function(data) {\n var _this = this;\n\n this.categories = [];\n this.repeat = {};\n this.alarm = { action: 'display', quantity: 5, unit: 'MINUTES', reference: 'BEFORE', relation: 'START' };\n this.status = 'not-specified';\n this.delta = 60;\n angular.extend(this, data);\n\n if (this.component == 'vevent')\n this.type = 'appointment';\n else if (this.component == 'vtodo')\n this.type = 'task';\n\n if (this.startDate) {\n if (angular.isString(this.startDate))\n // Ex: 2015-10-25T22:34:51+00:00\n this.start = Component.$parseDate(this.startDate);\n else\n // Date object\n this.start = this.startDate;\n }\n else if (this.type == 'appointment') {\n this.start = new Date();\n this.start.setMinutes(Math.round(this.start.getMinutes()/15)*15);\n }\n\n if (this.endDate) {\n this.end = Component.$parseDate(this.endDate);\n this.delta = this.start.minutesTo(this.end);\n }\n else if (this.type == 'appointment') {\n this.setDelta(this.delta);\n }\n\n if (this.dueDate)\n this.due = Component.$parseDate(this.dueDate);\n\n if (this.completedDate)\n this.completed = Component.$parseDate(this.completedDate);\n else if (this.type == 'task')\n this.completed = new Date();\n\n if (this.c_category) {\n // c_category is only defined in list mode (when calling $filter)\n // Filter out categories for which there's no associated color\n this.categories = _.invokeMap(_.filter(this.c_category, function(name) {\n return Component.$Preferences.defaults.SOGoCalendarCategoriesColors[name];\n }), 'asCSSIdentifier');\n }\n\n // Parse recurrence rule definition and initialize default values\n this.$isRecurrent = angular.isDefined(data.repeat);\n if (this.repeat.days) {\n var byDayMask = _.find(this.repeat.days, function(o) {\n return angular.isDefined(o.occurrence);\n });\n if (byDayMask) {\n if (this.repeat.frequency == 'yearly')\n this.repeat.year = { byday: true };\n this.repeat.month = {\n type: 'byday',\n occurrence: byDayMask.occurrence.toString(),\n day: byDayMask.day\n };\n }\n }\n else {\n this.repeat.days = [];\n }\n if (this.repeat.dates) {\n this.repeat.frequency = 'custom';\n _.forEach(this.repeat.dates, function(rdate, i, rdates) {\n if (angular.isString(rdate))\n // Ex: 2015-10-25T22:34:51+00:00\n rdates[i] = Component.$parseDate(rdate);\n });\n }\n else if (angular.isUndefined(this.repeat.frequency))\n this.repeat.frequency = 'never';\n if (angular.isUndefined(this.repeat.interval))\n this.repeat.interval = 1;\n if (angular.isUndefined(this.repeat.monthdays))\n // TODO: initialize this.repeat.monthdays with month day of start date\n this.repeat.monthdays = [];\n else if (this.repeat.monthdays.length > 0)\n this.repeat.month = { type: 'bymonthday' };\n if (angular.isUndefined(this.repeat.month))\n this.repeat.month = {};\n if (angular.isUndefined(this.repeat.month.occurrence))\n angular.extend(this.repeat.month, { occurrence: '1', day: 'SU' });\n if (angular.isUndefined(this.repeat.months))\n // TODO: initialize this.repeat.months with month of start date\n this.repeat.months = [];\n if (angular.isUndefined(this.repeat.year))\n this.repeat.year = {};\n if (this.repeat.count)\n this.repeat.end = 'count';\n else if (this.repeat.until) {\n this.repeat.end = 'until';\n if (angular.isString(this.repeat.until))\n this.repeat.until = Component.$parseDate(this.repeat.until, { no_time: true });\n }\n else\n this.repeat.end = 'never';\n this.$hasCustomRepeat = this.hasCustomRepeat();\n\n if (this.isNew) {\n // Set default values\n var type = (this.type == 'appointment')? 'Events' : 'Tasks';\n\n // Set default classification\n this.classification = Component.$Preferences.defaults['SOGoCalendar' + type + 'DefaultClassification'].toLowerCase();\n\n // Set default alarm\n var units = { M: 'MINUTES', H: 'HOURS', D: 'DAYS', W: 'WEEKS' };\n var match = /-PT?([0-9]+)([MHDW])/.exec(Component.$Preferences.defaults.SOGoCalendarDefaultReminder);\n if (match) {\n this.$hasAlarm = true;\n this.alarm.quantity = parseInt(match[1]);\n this.alarm.unit = units[match[2]];\n }\n\n // Set notitifications\n this.sendAppointmentNotifications = Component.$Preferences.defaults.SOGoAppointmentSendEMailNotifications;\n }\n else if (angular.isUndefined(data.$hasAlarm)) {\n this.$hasAlarm = angular.isDefined(data.alarm);\n }\n\n // Allow the component to be moved to a different calendar\n this.destinationCalendar = this.pid;\n\n // if (this.organizer && this.organizer.email) {\n // this.organizer.$image = Component.$gravatar(this.organizer.email, 32);\n // }\n\n if (this.attendees) {\n _.forEach(this.attendees, function(attendee) {\n attendee.image = Component.$gravatar(attendee.email, 32);\n });\n }\n\n // Load freebusy of attendees\n this.updateFreeBusy();\n\n this.selected = false;\n };\n\n\n /**\n * @function initOrganizer\n * @memberof Component.prototype\n * @desc Extend instance with organizer including her freebusy information.\n * @param {object} calendar - Calendar instance associated to current component\n */\n Component.prototype.initOrganizer = function(calendar) {\n var _this = this, promise;\n if (calendar && calendar.isSubscription) {\n promise = Component.$User.$filter(calendar.owner).then(function(results) {\n var owner = results[0];\n _this.organizer = {\n uid: owner.uid,\n name: owner.cn,\n email: owner.c_email\n };\n });\n }\n else {\n this.organizer = {\n uid: Component.$settings.activeUser('login'),\n name: Component.$settings.activeUser('identification'),\n email: Component.$settings.activeUser('email')\n };\n promise = Component.$q.when();\n }\n // Fetch organizer's freebusy\n promise.then(function() {\n _this.updateFreeBusyAttendee(_this.organizer);\n });\n };\n\n /**\n * @function hasCustomRepeat\n * @memberof Component.prototype\n * @desc Check if the component has a custom recurrence rule.\n * @returns true if the recurrence rule requires the full recurrence editor\n */\n Component.prototype.hasCustomRepeat = function() {\n var b = angular.isUndefined(this.occurrenceId) &&\n angular.isDefined(this.repeat) &&\n (this.repeat.interval > 1 ||\n angular.isDefined(this.repeat.days) && this.repeat.days.length > 0 ||\n angular.isDefined(this.repeat.monthdays) && this.repeat.monthdays.length > 0 ||\n angular.isDefined(this.repeat.months) && this.repeat.months.length > 0 ||\n angular.isDefined(this.repeat.month) && angular.isDefined(this.repeat.month.type) ||\n angular.isDefined(this.repeat.dates) && this.repeat.dates.length > 0);\n return b;\n };\n\n /**\n * @function isEditable\n * @memberof Component.prototype\n * @desc Check if the component is editable and not an occurrence of a recurrent component\n * @returns true or false\n */\n Component.prototype.isEditable = function() {\n return (!this.occurrenceId && !this.isReadOnly);\n };\n\n /**\n * @function isEditableOccurrence\n * @memberof Component.prototype\n * @desc Check if the component is editable and an occurrence of a recurrent component\n * @returns true or false\n */\n Component.prototype.isEditableOccurrence = function() {\n return (this.occurrenceId && !this.isReadOnly);\n };\n\n /**\n * @function isInvitation\n * @memberof Component.prototype\n * @desc Check if the component an invitation and not an occurrence of a recurrent component\n * @returns true or false\n */\n Component.prototype.isInvitation = function() {\n return (!this.occurrenceId && this.userHasRSVP);\n };\n\n /**\n * @function isInvitationOccurrence\n * @memberof Component.prototype\n * @desc Check if the component an invitation and an occurrence of a recurrent component\n * @returns true or false\n */\n Component.prototype.isInvitationOccurrence = function() {\n return (this.occurrenceId && this.userHasRSVP);\n };\n\n /**\n * @function showPercentComplete\n * @memberof Component.prototype\n * @desc Check if the percent completion should be displayed with respect to the\n * component's type and status.\n * @returns true if the percent completion should be displayed\n */\n Component.prototype.showPercentComplete = function() {\n return (this.type == 'task' &&\n this.percentComplete > 0 &&\n this.status != 'cancelled');\n };\n\n /**\n * @function enablePercentComplete\n * @memberof Component.prototype\n * @desc Check if the percent completion should be enabled with respect to the\n * component's type and status.\n * @returns true if the percent completion should be displayed\n */\n Component.prototype.enablePercentComplete = function() {\n return (this.type == 'task' &&\n this.status != 'not-specified' &&\n this.status != 'cancelled');\n };\n\n /**\n * @function coversFreeBusy\n * @memberof Component.prototype\n * @desc Check if a specific quarter matches the component's period\n * @returns true if the quarter covers the component's period\n */\n Component.prototype.coversFreeBusy = function(day, hour, quarter) {\n var b = (angular.isDefined(this.freebusy[day]) &&\n angular.isDefined(this.freebusy[day][hour]) &&\n this.freebusy[day][hour][quarter] == 1);\n return b;\n };\n\n /**\n * @function updateFreeBusyCoverage\n * @memberof Component.prototype\n * @desc Build a 15-minute-based representation of the component's period.\n * @returns an object literal hashed by days and hours and arrays of four 1's and 0's\n */\n Component.prototype.updateFreeBusyCoverage = function() {\n var _this = this, freebusy = {};\n\n if (this.start && this.end) {\n var roundedStart = new Date(this.start.getTime()),\n roundedEnd = new Date(this.end.getTime()),\n startQuarter = parseInt(roundedStart.getMinutes()/15 + 0.5),\n endQuarter = parseInt(roundedEnd.getMinutes()/15 + 0.5);\n roundedStart.setMinutes(15*startQuarter);\n roundedEnd.setMinutes(15*endQuarter);\n\n _.forEach(roundedStart.daysUpTo(roundedEnd), function(date, index) {\n var currentDay = date.getDate(),\n dayKey = date.getDayString(),\n hourKey;\n if (dayKey == _this.start.getDayString()) {\n hourKey = date.getHours().toString();\n freebusy[dayKey] = {};\n freebusy[dayKey][hourKey] = [];\n while (startQuarter > 0) {\n freebusy[dayKey][hourKey].push(0);\n startQuarter--;\n }\n }\n else {\n date = date.beginOfDay();\n freebusy[dayKey] = {};\n }\n while (date.getTime() < _this.end.getTime() &&\n date.getDate() == currentDay) {\n hourKey = date.getHours().toString();\n if (angular.isUndefined(freebusy[dayKey][hourKey]))\n freebusy[dayKey][hourKey] = [];\n freebusy[dayKey][hourKey].push(1);\n date.addMinutes(15);\n }\n });\n return freebusy;\n }\n };\n\n /**\n * @function updateFreeBusy\n * @memberof Component.prototype\n * @desc Update the freebusy coverage representation and the attendees freebusy information\n */\n Component.prototype.updateFreeBusy = function() {\n var _this = this;\n\n this.freebusy = this.updateFreeBusyCoverage();\n\n if (this.attendees) {\n if (this.organizer)\n this.updateFreeBusyAttendee(this.organizer);\n _.forEach(this.attendees, function(attendee) {\n _this.updateFreeBusyAttendee(attendee);\n });\n }\n };\n\n /**\n * @function setDelta\n * @memberof Component.prototype\n * @desc Set the end time to the specified number of minutes after the start time.\n * @param {number} delta - the number of minutes\n */\n Component.prototype.setDelta = function(delta) {\n this.delta = delta;\n this.end = new Date(this.start.getTime());\n this.end.setMinutes(Math.round(this.end.getMinutes()/15)*15);\n this.end.addMinutes(this.delta);\n };\n\n /**\n * @function updateFreeBusyAttendee\n * @memberof Component.prototype\n * @desc Update the freebusy information for the component's period for a specific attendee.\n * @param {Object} card - an Card object instance of the attendee\n */\n Component.prototype.updateFreeBusyAttendee = function(attendee) {\n var resource, uid, params, days;\n\n if (attendee.uid) {\n uid = attendee.uid;\n if (attendee.domain)\n uid += '@' + attendee.domain;\n params =\n {\n sday: this.start.getDayString(),\n eday: this.end.getDayString()\n };\n\n if (attendee.isMSExchange) {\n // Attendee is not a local user, but her freebusy data is available from an external MS Exchange server;\n // we query /SOGo/so/<login_user>/freebusy.ifb/ajaxRead?uid=<uid>\n resource = Component.$$resource.userResource();\n params.uid = uid;\n }\n else {\n // Attendee is a user;\n // web query /SOGo/so/<uid>/freebusy.ifb/ajaxRead\n resource = Component.$$resource.userResource(uid);\n }\n\n days = _.map(this.start.daysUpTo(this.end), function(day) { return day.getDayString(); });\n\n if (angular.isUndefined(attendee.freebusy))\n attendee.freebusy = {};\n\n // Fetch FreeBusy information\n resource.fetch('freebusy.ifb', 'ajaxRead', params).then(function(data) {\n _.forEach(days, function(day) {\n var hour;\n\n if (angular.isUndefined(attendee.freebusy[day]))\n attendee.freebusy[day] = {};\n\n if (angular.isUndefined(data[day]))\n data[day] = {};\n\n for (var i = 0; i <= 23; i++) {\n hour = i.toString();\n if (data[day][hour])\n attendee.freebusy[day][hour] = [\n data[day][hour][\"0\"],\n data[day][hour][\"15\"],\n data[day][hour][\"30\"],\n data[day][hour][\"45\"]\n ];\n else\n attendee.freebusy[day][hour] = [0, 0, 0, 0];\n }\n });\n });\n }\n };\n\n /**\n * @function getClassName\n * @memberof Component.prototype\n * @desc Return the component CSS class name based on its container (calendar) ID.\n * @param {string} [base] - the prefix to add to the class name (defaults to \"fg\")\n * @returns a string representing the foreground CSS class name\n */\n Component.prototype.getClassName = function(base) {\n if (angular.isUndefined(base))\n base = 'fg';\n return base + '-folder' + (this.destinationCalendar || this.c_folder || this.pid);\n };\n\n /**\n * @function addAttendee\n * @memberof Component.prototype\n * @desc Add an attendee and fetch his freebusy info.\n * @param {Object} card - an Card object instance to be added to the attendees list\n */\n Component.prototype.addAttendee = function(card, options) {\n var _this = this, attendee, list, url, params;\n if (card) {\n if (!this.attendees || (options && options.organizerCalendar)) {\n // No attendee yet; initialize the organizer\n this.initOrganizer(options? options.organizerCalendar : undefined);\n }\n if (card.$isList({expandable: true})) {\n // Decompose list members\n list = Component.$Card.$find(card.container, card.c_name);\n list.$id().then(function(listId) {\n _.forEach(list.refs, function(ref) {\n attendee = {\n name: ref.c_cn,\n email: ref.$preferredEmail(),\n role: 'req-participant',\n partstat: 'needs-action',\n uid: ref.c_uid,\n $avatarIcon: 'person',\n };\n if (!_.find(_this.attendees, function(o) {\n return o.email == attendee.email;\n })) {\n // Contact is not already an attendee, add it\n attendee.image = Component.$gravatar(attendee.email, 32);\n if (_this.attendees)\n _this.attendees.push(attendee);\n else\n _this.attendees = [attendee];\n _this.updateFreeBusyAttendee(attendee);\n }\n });\n });\n }\n else {\n // Single contact\n attendee = {\n uid: card.c_uid,\n domain: card.c_domain,\n isMSExchange: card.ismsexchange,\n name: card.c_cn,\n email: card.$preferredEmail(),\n role: 'req-participant',\n partstat: 'needs-action',\n $avatarIcon: card.$avatarIcon\n };\n if (!_.find(this.attendees, function(o) {\n return o.email == attendee.email;\n })) {\n attendee.image = Component.$gravatar(attendee.email, 32);\n if (this.attendees)\n this.attendees.push(attendee);\n else\n this.attendees = [attendee];\n this.updateFreeBusyAttendee(attendee);\n }\n }\n }\n };\n\n /**\n * @function hasAttendee\n * @memberof Component.prototype\n * @desc Verify if one of the email addresses of a Card instance matches an attendee.\n * @param {Object} card - an Card object instance\n * @returns true if the Card matches an attendee\n */\n Component.prototype.hasAttendee = function(card) {\n var attendee = _.find(this.attendees, function(attendee) {\n return _.find(card.emails, function(email) {\n return email.value == attendee.email;\n });\n });\n return angular.isDefined(attendee);\n };\n\n /**\n * @function deleteAttendee\n * @memberof Component.prototype\n * @desc Remove an attendee from the component\n * @param {Object} attendee - an object literal defining an attendee\n */\n Component.prototype.deleteAttendee = function(attendee) {\n var index = _.findIndex(this.attendees, function(currentAttendee) {\n return currentAttendee.email == attendee.email;\n });\n this.attendees.splice(index, 1);\n };\n\n /**\n * @function canRemindAttendeesByEmail\n * @memberof Component.prototype\n * @desc Verify if the component's reminder must be send by email and if it has at least one attendee.\n * @returns true if attendees can receive a reminder by email\n */\n Component.prototype.canRemindAttendeesByEmail = function() {\n return this.alarm.action == 'email' &&\n !this.isReadOnly &&\n this.attendees && this.attendees.length > 0;\n };\n\n /**\n * @function addAttachUrl\n * @memberof Component.prototype\n * @desc Add a new attach URL if not already defined\n * @param {string} attachUrl - the URL\n * @returns the number of values in the list of attach URLs\n */\n Component.prototype.addAttachUrl = function(attachUrl) {\n if (angular.isUndefined(this.attachUrls)) {\n this.attachUrls = [{value: attachUrl}];\n }\n else {\n for (var i = 0; i < this.attachUrls.length; i++) {\n if (this.attachUrls[i].value == attachUrl) {\n break;\n }\n }\n if (i == this.attachUrls.length)\n this.attachUrls.push({value: attachUrl});\n }\n return this.attachUrls.length - 1;\n };\n\n /**\n * @function deleteAttachUrl\n * @memberof Component.prototype\n * @desc Remove an attach URL\n * @param {number} index - the URL index in the list of attach URLs\n */\n Component.prototype.deleteAttachUrl = function(index) {\n if (index > -1 && this.attachUrls.length > index) {\n this.attachUrls.splice(index, 1);\n }\n };\n\n /**\n * @function $addDueDate\n * @memberof Component.prototype\n * @desc Add a due date\n */\n Component.prototype.$addDueDate = function() {\n this.due = new Date();\n this.due.setMinutes(Math.round(this.due.getMinutes()/15)*15);\n this.dueDate = this.due.toISOString();\n };\n\n /**\n * @function $deleteDueDate\n * @memberof Component.prototype\n * @desc Delete a due date\n */\n Component.prototype.$deleteDueDate = function() {\n delete this.due;\n delete this.dueDate;\n };\n\n /**\n * @function $addStartDate\n * @memberof Component.prototype\n * @desc Add a start date\n */\n Component.prototype.$addStartDate = function() {\n this.start = new Date();\n this.start.setMinutes(Math.round(this.start.getMinutes()/15)*15);\n };\n\n /**\n * @function $deleteStartDate\n * @memberof Component.prototype\n * @desc Delete a start date\n */\n Component.prototype.$deleteStartDate = function() {\n delete this.start;\n delete this.startDate;\n };\n\n /**\n * @function $addRecurrenceDate\n * @memberof Component.prototype\n * @desc Add a start date\n */\n Component.prototype.$addRecurrenceDate = function() {\n var now = new Date();\n now.setMinutes(Math.round(now.getMinutes()/15)*15);\n\n if (angular.isUndefined(this.repeat.dates))\n this.repeat = { frequency: 'custom', dates: [] };\n this.repeat.dates.push(now);\n };\n\n /**\n * @function $deleteRecurrenceDate\n * @memberof Component.prototype\n * @desc Delete a recurrence date\n */\n Component.prototype.$deleteRecurrenceDate = function(index) {\n if (index > -1 && this.repeat && this.repeat.dates && this.repeat.dates.length > index) {\n this.repeat.dates.splice(index, 1);\n }\n };\n\n /**\n * @function $reset\n * @memberof Component.prototype\n * @desc Reset the original state the component's data.\n */\n Component.prototype.$reset = function() {\n var _this = this;\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n delete _this[key];\n }\n });\n this.init(this.$shadowData);\n this.$shadowData = this.$omit();\n };\n\n /**\n * @function $reply\n * @memberof Component.prototype\n * @desc Reply to an invitation.\n * @returns a promise of the HTTP operation\n */\n Component.prototype.$reply = function() {\n var _this = this, data, path = [this.pid, encodeURIComponent(this.id)];\n\n if (this.occurrenceId)\n path.push(this.occurrenceId);\n\n data = {\n reply: this.reply,\n delegatedTo: this.delegatedTo,\n alarm: this.$hasAlarm? this.alarm : {}\n };\n\n return Component.$$resource.save(path.join('/'), data, { action: 'rsvpAppointment' })\n .then(function(data) {\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit();\n return data;\n });\n };\n\n /**\n * @function $adjust\n * @memberof Component.prototype\n * @desc Adjust the start, day, and/or duration of the component\n * @returns a promise of the HTTP operation\n */\n Component.prototype.$adjust = function(params) {\n var path = [this.pid, encodeURIComponent(this.id)];\n\n if (_.every(_.values(params), function(v) { return v === 0; }))\n // No changes\n return Component.$q.when();\n\n if (this.occurrenceId)\n path.push(this.occurrenceId);\n\n Component.$log.debug('adjust ' + path.join('/') + ' ' + JSON.stringify(params));\n\n return Component.$$resource.save(path.join('/'), params, { action: 'adjust' });\n };\n\n /**\n * @function $save\n * @memberof Component.prototype\n * @desc Save the component to the server.\n * @param {object} extraAttributes - additional attributes to send to the server\n */\n Component.prototype.$save = function(extraAttributes) {\n var _this = this, options, path, component, date, dlp;\n\n component = this.$omit();\n dlp = Component.$Preferences.$mdDateLocaleProvider;\n\n // Format dates and times\n component.startDate = component.start ? component.start.format(dlp, '%Y-%m-%d') : '';\n component.startTime = component.start ? component.start.format(dlp, '%H:%M') : '';\n component.endDate = component.end ? component.end.format(dlp, '%Y-%m-%d') : '';\n component.endTime = component.end ? component.end.format(dlp, '%H:%M') : '';\n component.dueDate = component.due ? component.due.format(dlp, '%Y-%m-%d') : '';\n component.dueTime = component.due ? component.due.format(dlp, '%H:%M') : '';\n component.completedDate = component.completed ? component.completed.format(dlp, '%Y-%m-%d') : '';\n\n // Update recurrence definition depending on selections\n if (this.hasCustomRepeat()) {\n if (this.repeat.frequency == 'monthly' && this.repeat.month.type && this.repeat.month.type == 'byday' && this.repeat.month.day != 'relative' ||\n this.repeat.frequency == 'yearly' && this.repeat.year.byday) {\n // BYDAY mask for a monthly or yearly recurrence\n delete component.repeat.monthdays;\n component.repeat.days = [{ day: this.repeat.month.day, occurrence: this.repeat.month.occurrence.toString() }];\n }\n else if ((this.repeat.frequency == 'monthly' || this.repeat.frequency == 'yearly') &&\n this.repeat.month.type) {\n // montly recurrence by month days or yearly by month\n delete component.repeat.days;\n if (this.repeat.month.day == 'relative')\n component.repeat.monthdays = [this.repeat.month.occurrence];\n }\n else if (this.repeat.frequency == 'custom' && this.repeat.dates) {\n _.forEach(component.repeat.dates, function(rdate, i, rdates) {\n rdates[i] = {\n date: rdate.format(dlp, '%Y-%m-%d'),\n time: rdate.format(dlp, '%H:%M')\n };\n });\n }\n }\n else if (this.repeat.frequency && this.repeat.frequency != 'never') {\n component.repeat = { frequency: this.repeat.frequency };\n }\n if (component.startDate && this.repeat.frequency && this.repeat.frequency != 'never') {\n if (this.repeat.end == 'until' && this.repeat.until)\n component.repeat.until = this.repeat.until.stringWithSeparator('-');\n else if (this.repeat.end == 'count' && this.repeat.count)\n component.repeat.count = this.repeat.count;\n else {\n delete component.repeat.until;\n delete component.repeat.count;\n }\n }\n else {\n delete component.repeat;\n }\n\n // Check status\n if (this.status == 'not-specified')\n delete component.status;\n else if (this.status != 'completed')\n delete component.completedDate;\n\n // Verify alarm\n if (component.startDate && this.$hasAlarm) {\n if (this.alarm.action && this.alarm.action == 'email' &&\n !(this.attendees && this.attendees.length > 0)) {\n // No attendees; email reminder must be sent to organizer only\n component.alarm.attendees = 0;\n component.alarm.organizer = 1;\n }\n }\n else {\n component.alarm = {};\n }\n\n // Build URL\n path = [this.pid, encodeURIComponent(this.id)];\n\n if (this.isNew)\n options = { action: 'saveAs' + this.type.capitalize() };\n\n if (this.occurrenceId)\n path.push(this.occurrenceId);\n\n angular.extend(component, extraAttributes);\n\n return Component.$$resource.save(path.join('/'), component, options)\n .then(function(data) {\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit();\n return data;\n });\n };\n\n /**\n * @function $delete\n * @memberof Component.prototype\n * @desc Delete the component from the server.\n * @param {boolean} occurrenceOnly - delete this occurrence only\n */\n Component.prototype.remove = function(occurrenceOnly) {\n var _this = this, path = [this.pid, encodeURIComponent(this.id)];\n\n if (occurrenceOnly && this.occurrenceId)\n path.push(this.occurrenceId);\n\n return Component.$$resource.remove(path.join('/'));\n };\n\n /**\n * @function $unwrap\n * @memberof Component.prototype\n * @desc Unwrap a promise.\n * @param {promise} futureComponentData - a promise of some of the Component's data\n */\n Component.prototype.$unwrap = function(futureComponentData) {\n var _this = this;\n\n // Expose the promise\n this.$futureComponentData = futureComponentData;\n\n // Resolve the promise\n this.$futureComponentData.then(function(data) {\n _this.init(data);\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit();\n }, function(data) {\n angular.extend(_this, data);\n _this.isError = true;\n Component.$log.error(_this.error);\n });\n };\n\n /**\n * @function $omit\n * @memberof Component.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the Component instance\n */\n Component.prototype.$omit = function() {\n var component = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' &&\n (key == '$hasAlarm' || key[0] != '$') &&\n key != 'blocks') {\n component[key] = angular.copy(value);\n }\n });\n\n return component;\n };\n\n /**\n * @function repeatDescription\n * @memberof Component.prototype\n * @desc Return a localized description of the recurrence definition\n * @return a localized string\n */\n Component.prototype.repeatDescription = function() {\n var localizedString = null;\n if (this.repeat)\n localizedString = l('repeat_' + this.repeat.frequency.toUpperCase());\n\n return localizedString;\n };\n\n /**\n * @function alarmDescription\n * @memberof Component.prototype\n * @desc Return a localized description of the reminder definition\n * @return a localized string\n */\n Component.prototype.alarmDescription = function() {\n var key, localizedString = null;\n if (this.alarm) {\n key = ['reminder', this.alarm.quantity];\n if (this.alarm.quantity > 0)\n key.push(this.alarm.unit.toUpperCase(), this.alarm.reference.toUpperCase());\n key = key.join('_');\n localizedString = l(key);\n if (key === localizedString)\n // No localized string for this reminder definition\n localizedString = [this.alarm.quantity,\n l('reminder_' + this.alarm.unit.toUpperCase()),\n l('reminder_' + this.alarm.reference.toUpperCase())].join(' ');\n }\n\n return localizedString;\n };\n\n /**\n * @function copyTo\n * @memberof Component.prototype\n * @desc Copy an event to a calendar\n * @param {string} calendar - a target calendar UID\n * @returns a promise of the HTTP operation\n */\n Component.prototype.copyTo = function(calendar) {\n return Component.$$resource.post(this.pid + '/' + encodeURIComponent(this.id), 'copy', {destination: calendar});\n };\n\n /**\n * @function moveTo\n * @memberof Component.prototype\n * @desc Move an event to a calendar\n * @param {string} calendar - a target calendar UID\n * @returns a promise of the HTTP operation\n */\n Component.prototype.moveTo = function(calendar) {\n return Component.$$resource.post(this.pid + '/' + encodeURIComponent(this.id), 'move', {destination: calendar});\n };\n\n Component.prototype.toString = function() {\n return '[Component ' + this.id + ']';\n };\n\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint loopfunc: true */\n 'use strict';\n\n /**\n * @ngInject\n */\n CalendarController.$inject = ['$scope', '$rootScope', '$state', '$stateParams', 'sgHotkeys', 'Calendar', 'Component', 'Preferences', 'stateEventsBlocks'];\n function CalendarController($scope, $rootScope, $state, $stateParams, sgHotkeys, Calendar, Component, Preferences, stateEventsBlocks) {\n var vm = this, deregisterCalendarsList, hotkeys = [];\n\n // Make the toolbar state of all-day events persistent\n if (angular.isUndefined(CalendarController.expandedAllDays))\n CalendarController.expandedAllDays = false;\n\n vm.selectedDate = $stateParams.day.asDate();\n vm.expandedAllDays = CalendarController.expandedAllDays;\n vm.toggleAllDays = toggleAllDays;\n vm.views = stateEventsBlocks;\n vm.changeDate = changeDate;\n vm.changeView = changeView;\n\n\n this.$onInit = function() {\n _registerHotkeys(hotkeys);\n\n _formatDate(vm.selectedDate);\n\n // Refresh current view when the list of calendars is modified\n deregisterCalendarsList = $rootScope.$on('calendars:list', updateView);\n\n $scope.$on('$destroy', function() {\n // Destroy event listener when the controller is being deactivated\n deregisterCalendarsList();\n // Deregister hotkeys\n _.forEach(hotkeys, function(key) {\n sgHotkeys.deregisterHotkey(key);\n });\n });\n };\n\n\n function _registerHotkeys(keys) {\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_today'),\n description: l('Today'),\n callback: changeDate,\n args: new Date()\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_dayview'),\n description: l('Day'),\n callback: changeView,\n args: 'day'\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_weekview'),\n description: l('Week'),\n callback: changeView,\n args: 'week'\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_monthview'),\n description: l('Month'),\n callback: changeView,\n args: 'month'\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_multicolumndayview'),\n description: l('Multicolumn Day View'),\n callback: changeView,\n args: 'multicolumnday'\n }));\n keys.push(sgHotkeys.createHotkey({\n key: 'left',\n description: l('Move backward'),\n callback: _goToPeriod,\n args: -1\n }));\n keys.push(sgHotkeys.createHotkey({\n key: 'right',\n description: l('Move forward'),\n callback: _goToPeriod,\n args: +1\n }));\n\n // Register the hotkeys\n _.forEach(keys, function(key) {\n sgHotkeys.registerHotkey(key);\n });\n }\n\n\n function _goToPeriod($event, direction) {\n var date;\n\n if ($stateParams.view == 'week') {\n date = vm.selectedDate.beginOfWeek(Preferences.defaults.SOGoFirstDayOfWeek).addDays(7 * direction);\n }\n else if ($stateParams.view == 'month') {\n date = vm.selectedDate;\n date.setDate(1);\n date.setMonth(date.getMonth() + direction);\n }\n else {\n date = vm.selectedDate.addDays(direction);\n }\n\n changeDate($event, date);\n }\n\n /**\n * Format a date according to the current view.\n * - Day/Multicolumn: name of weekday\n * - Week: week number\n * - Month: name of month\n */\n function _formatDate(date) {\n if ($stateParams.view == 'month') {\n date.setDate(1);\n date.setHours(12);\n date.$dateFormat = '%B %Y';\n }\n else if ($stateParams.view == 'week') {\n date.setTime(date.beginOfWeek(Preferences.defaults.SOGoFirstDayOfWeek).getTime());\n date.$dateFormat = l('Week %d').replace('%d', '%U');\n }\n else {\n date.$dateFormat = '%A';\n }\n }\n\n // Expand or collapse all-day events\n function toggleAllDays() {\n CalendarController.expandedAllDays = !CalendarController.expandedAllDays;\n vm.expandedAllDays = CalendarController.expandedAllDays;\n }\n\n function updateView() {\n // The list of calendars has changed; update the views\n // See stateEventsBlocks in Scheduler.app.js\n Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function(data) {\n var i, j, view;\n for (i = 0; i < data.length; i++) {\n view = data[i];\n if (vm.views[i]) {\n _.forEach(view.allDayBlocks, function(blocks, day) {\n vm.views[i].allDayBlocks[day] = blocks;\n });\n _.forEach(view.blocks, function(blocks, day) {\n vm.views[i].blocks[day] = blocks;\n });\n }\n else {\n vm.views[i] = view;\n }\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 vm.views[i].calendar = new Calendar({ id: view.id, name: view.calendarName });\n }\n }\n // Remove previous views\n for (j = vm.views.length; j >= i; j--)\n vm.views.splice(j, 1);\n });\n }\n\n // Change calendar's date\n function changeDate($event, newDate) {\n var date = newDate? newDate.getDayString() : angular.element($event.currentTarget).attr('date');\n if (newDate)\n _formatDate(newDate);\n $state.go('calendars.view', { day: date });\n }\n\n // Change calendar's view\n function changeView($event, view) {\n $state.go('calendars.view', { view: view });\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', '$scope', '$q', '$timeout', '$state', '$mdDialog', 'sgHotkeys', 'sgFocus', 'Dialog', 'Preferences', 'CalendarSettings', 'Calendar', 'Component', 'Alarm'];\n function CalendarListController($rootScope, $scope, $q, $timeout, $state, $mdDialog, sgHotkeys, focus, Dialog, Preferences, CalendarSettings, Calendar, Component, Alarm) {\n var vm = this, hotkeys = [], type;\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.searchMode = searchMode;\n vm.toggleComponentSelection = toggleComponentSelection;\n vm.confirmDeleteSelectedComponents = confirmDeleteSelectedComponents;\n vm.openEvent = openEvent;\n vm.openTask = openTask;\n vm.newComponent = newComponent;\n vm.filterpopup = filterpopup;\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, multiple: 0 };\n\n\n this.$onInit = function() {\n _registerHotkeys(hotkeys);\n\n // Select list based on user's settings\n type = 'events';\n if (Preferences.settings.Calendar.SelectedList == 'tasksListView') {\n vm.selectedList = 1;\n type = 'tasks';\n }\n selectComponentType(type, { reload: true }); // fetch events/tasks lists\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 $scope.$on('$destroy', function() {\n // Deregister hotkeys\n _.forEach(hotkeys, function(key) {\n sgHotkeys.deregisterHotkey(key);\n });\n });\n };\n\n\n function _registerHotkeys(keys) {\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_search'),\n description: l('Search'),\n callback: searchMode\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_create_event'),\n description: l('Create a new event'),\n callback: newComponent,\n args: 'appointment'\n }));\n keys.push(sgHotkeys.createHotkey({\n key: l('hotkey_create_task'),\n description: l('Create a new task'),\n callback: newComponent,\n args: 'task'\n }));\n\n // Register the hotkeys\n _.forEach(keys, function(key) {\n sgHotkeys.registerHotkey(key);\n });\n }\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 _.forEach(Component['$' + vm.componentType], function(component) {\n component.selected = false;\n });\n vm.mode.multiple = 0;\n }\n\n function selectAll() {\n _.forEach(Component['$' + vm.componentType], function(component) {\n component.selected = true;\n });\n vm.mode.multiple = Component['$' + vm.componentType].length;\n }\n\n function toggleComponentSelection($event, component) {\n component.selected = !component.selected;\n vm.mode.multiple += component.selected? 1 : -1;\n $event.preventDefault();\n $event.stopPropagation();\n }\n\n function searchMode() {\n vm.mode.search = true;\n focus('search');\n }\n\n function confirmDeleteSelectedComponents() {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the selected components?'),\n { ok: l('Delete') })\n .then(function() {\n // User confirmed the deletion\n var components = _.filter(Component['$' + vm.componentType], function(component) {\n return component.selected;\n });\n Calendar.$deleteComponents(components).then(function() {\n vm.mode.multiple = 0;\n $rootScope.$emit('calendars:list');\n });\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 var promise = $q.when();\n\n // Load component before opening dialog\n if (angular.isUndefined(component.$futureComponentData)) {\n component = Calendar.$get(component.pid).$getComponent(component.id, component.occurrenceId);\n promise = component.$futureComponentData;\n }\n\n promise.then(function() {\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\n function newComponent($event, type, baseComponent) {\n var component;\n\n if (baseComponent) {\n component = baseComponent;\n component.updateFreeBusy();\n }\n else {\n component = new Component({ pid: Calendar.$defaultCalendar(), 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, calendarNumber, activeCalendars;\n\n component = Component.$ghost.component;\n pointerHandler = Component.$ghost.pointerHandler;\n\n if (component.isNew) {\n coordinates = pointerHandler.currentEventCoordinates;\n component.summary = '';\n if (component.isAllDay)\n coordinates.duration -= 96;\n component.setDelta(coordinates.duration * 15);\n newComponent(null, 'appointment', component)\n .catch()\n .finally(function() {\n $timeout(function() {\n Component.$resetGhost();\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 (pointerHandler.originalCalendar && delta.dayNumber !== 0) {\n // The day number actually represents the destination calendar among the active calendars\n calendarNumber = pointerHandler.currentEventCoordinates.dayNumber;\n activeCalendars = _.filter(Calendar.$findAll(), { active: 1 });\n params.destination = activeCalendars[calendarNumber].id;\n params.days = 0;\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 Alarm.getAlarms();\n }, function(response) {\n onComponentAdjustError(response, component, params);\n }).finally(function() {\n $timeout(function() {\n Component.$resetGhost();\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\" sm-flex=\"80\" xs-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 }, function() {\n // Cancel\n }).finally(function() {\n $timeout(function() {\n Component.$resetGhost();\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, function(response) {\n $mdDialog.cancel().then(function() {\n onComponentAdjustError(response, component, params);\n }, function() {\n // Cancel\n });\n });\n };\n $scope.updateAllOccurrences = function() {\n delete component.occurrenceId;\n component.$adjust(params).then($mdDialog.hide, function(response) {\n $mdDialog.cancel().then(function() {\n onComponentAdjustError(response, component, params);\n }, function() {\n // Cancel\n });\n });\n };\n }\n\n function onComponentAdjustError(response, component, params) {\n if (response.status == CalendarSettings.ConflictHTTPErrorCode &&\n response.data && response.data.message && angular.isObject(response.data.message)) {\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: false,\n escapeToClose: false,\n templateUrl: 'UIxAttendeeConflictDialog',\n controller: AttendeeConflictDialogController,\n controllerAs: '$AttendeeConflictDialogController',\n locals: {\n component: component,\n params: params,\n conflictError: response.data.message\n }\n }).then(function() {\n $rootScope.$emit('calendars:list');\n }, function() {\n // Cancel\n });\n }\n }\n\n /**\n * @ngInject\n */\n AttendeeConflictDialogController.$inject = ['$scope', '$mdDialog', 'component', 'params', 'conflictError'];\n function AttendeeConflictDialogController($scope, $mdDialog, component, params, conflictError) {\n var vm = this;\n\n vm.conflictError = conflictError;\n vm.cancel = $mdDialog.cancel;\n vm.save = save;\n\n function save() {\n component.$adjust(angular.extend({ ignoreConflicts: true }, params)).then($mdDialog.hide);\n }\n }\n }\n\n function filterpopup() {\n return Component['$query' + vm.componentType.capitalize()].filterpopup;\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 Calendar.reloadWebCalendars().finally(function() {\n $rootScope.$emit('calendars:list');\n });\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', 'Dialog', 'sgSettings', 'Preferences', 'Calendar'];\n function CalendarsController($rootScope, $scope, $window, $mdDialog, $log, $mdToast, Dialog, Settings, Preferences, Calendar) {\n var vm = this;\n\n vm.activeUser = Settings.activeUser;\n vm.service = Calendar;\n vm.newCalendar = newCalendar;\n vm.addWebCalendar = addWebCalendar;\n vm.subscribeToFolder = subscribeToFolder;\n\n vm.filter = { name: '' };\n vm.sortableMode = false;\n vm.toggleSortableMode = toggleSortableMode;\n vm.resetSort = resetSort;\n vm.sortableCalendars = {\n scrollableContainer: '#sidenav-content',\n containment: 'md-list',\n orderChanged: _sortableEnd,\n accept: _sortableAccept\n };\n\n this.$onInit = 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 // 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 var commonList, ids, promise;\n\n // Identify which calendar has changed\n commonList = _.intersectionBy(newList, oldList, 'id');\n ids = _.map(_.filter(commonList, function(o) {\n var oldObject = _.find(oldList, { id: o.id });\n return !_.isEqual(o, oldObject);\n }), 'id');\n promise = Calendar.$q.when();\n\n if (ids.length > 0) {\n $log.debug(ids.join(', ') + ' changed');\n promise = Calendar.saveFoldersActivation(ids);\n }\n if (ids.length > 0 || commonList.length != newList.length || commonList.length != oldList.length)\n promise.then(function() {\n $rootScope.$emit('calendars:list');\n });\n },\n true // compare for object equality\n );\n };\n\n /**\n * Only allow to sort items within the same list.\n */\n function _sortableAccept(sourceItemHandleScope, destSortableScope, destItemScope) {\n return sourceItemHandleScope.sortableScope.element[0] == destSortableScope.element[0];\n }\n\n function _sortableEnd() {\n Calendar.saveFoldersOrder(_.flatMap(Calendar.$findAll(), 'id'));\n }\n\n function toggleSortableMode() {\n vm.sortableMode = !vm.sortableMode;\n vm.filter.name = '';\n }\n\n function resetSort() {\n Calendar.saveFoldersOrder();\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).then(function(calendar) {\n if (angular.isObject(calendar)) {\n // Web calendar requires HTTP authentication\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: 'UIxWebCalendarAuthDialog',\n controller: WebCalendarAuthDialogController,\n controllerAs: '$WebCalendarAuthDialogController',\n locals: {\n url: url,\n calendar: calendar\n }\n });\n }\n });\n });\n\n /**\n * @ngInject\n */\n WebCalendarAuthDialogController.$inject = ['scope', '$mdDialog', 'url', 'calendar'];\n function WebCalendarAuthDialogController(scope, $mdDialog, url, calendar) {\n var vm = this,\n parts = url.split(\"/\"),\n hostname = parts[2];\n\n vm.title = l(\"Please identify yourself to %{0}\").formatted(hostname);\n vm.url = url;\n vm.authenticate = function(form) {\n if (form.$valid || !form.$error.required) {\n calendar.setCredentials(vm.username, vm.password).then(function(message) {\n $mdDialog.hide();\n }, function(reason) {\n form.password.$setValidity('credentials', false);\n });\n }\n };\n vm.cancel = function() {\n $mdDialog.cancel();\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('Successfully subscribed to calendar'))\n .position('top right')\n .hideDelay(3000));\n });\n }\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', 'Component', 'AddressBook', 'Alarm', 'Account', 'stateComponent'];\n function ComponentController($rootScope, $mdDialog, Calendar, Component, AddressBook, Alarm, Account, stateComponent) {\n var vm = this, component;\n\n vm.calendarService = Calendar;\n vm.service = Component;\n vm.component = stateComponent;\n vm.close = close;\n vm.highPriority = highPriority;\n vm.cardFilter = cardFilter;\n vm.newMessageWithAllRecipients = newMessageWithAllRecipients;\n vm.newMessageWithRecipient = newMessageWithRecipient;\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 vm.copySelectedComponent = copySelectedComponent;\n vm.moveSelectedComponent = moveSelectedComponent;\n\n // Put organizer in an array to display it as an mdChip\n vm.organizer = [stateComponent.organizer];\n\n function close() {\n $mdDialog.hide();\n }\n\n function highPriority() {\n return (vm.component &&\n vm.component.priority &&\n vm.component.priority < 5);\n }\n\n // Autocomplete cards for attendees\n function cardFilter($query) {\n return AddressBook.$filterAll($query);\n }\n\n function newMessageWithAllRecipients($event) {\n var recipients = _.map(vm.component.attendees, function(attendee) {\n return attendee.name + \" <\" + attendee.email + \">\";\n });\n _newMessage($event, recipients);\n }\n\n function newMessageWithRecipient($event, name, email) {\n _newMessage($event, [name + \" <\" + email + \">\"]);\n }\n\n function _newMessage($event, recipients) {\n Account.$findAll().then(function(accounts) {\n var account = _.find(accounts, function(o) {\n if (o.id === 0)\n return o;\n });\n\n // We must initialize the Account with its mailbox\n // list before proceeding with message's creation\n account.$getMailboxes().then(function(mailboxes) {\n account.$newMessage().then(function(message) {\n angular.extend(message.editable, { to: recipients, subject: vm.component.summary });\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: false,\n escapeToClose: false,\n templateUrl: '../Mail/UIxMailEditor',\n controller: 'MessageEditorController',\n controllerAs: 'editor',\n locals: {\n stateAccount: account,\n stateMessage: message\n }\n });\n });\n });\n });\n\n $event.preventDefault();\n $event.stopPropagation();\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 Alarm.getAlarms();\n $mdDialog.hide();\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=\"40\" flex-sm=\"80\" flex-xs=\"100\" aria-label=\"' + l('View Raw Source') + '\">',\n ' <md-dialog-content class=\"md-dialog-content\">',\n ' <pre ng-bind-html=\"data\"></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 locals: { data: data }\n });\n\n /**\n * @ngInject\n */\n ComponentRawSourceDialogController.$inject = ['scope', '$mdDialog', 'data'];\n function ComponentRawSourceDialogController(scope, $mdDialog, data) {\n scope.data = data;\n scope.close = function() {\n $mdDialog.hide();\n };\n }\n });\n }\n\n function copySelectedComponent(calendar) {\n vm.component.copyTo(calendar).then(function() {\n $mdDialog.hide();\n $rootScope.$emit('calendars:list');\n });\n }\n\n function moveSelectedComponent(calendar) {\n vm.component.moveTo(calendar).then(function() {\n $mdDialog.hide();\n $rootScope.$emit('calendars:list');\n });\n }\n }\n\n /**\n * @ngInject\n */\n ComponentEditorController.$inject = ['$rootScope', '$scope', '$log', '$timeout', '$mdDialog', 'sgFocus', 'User', 'CalendarSettings', 'Calendar', 'Component', 'AddressBook', 'Card', 'Alarm', 'stateComponent'];\n function ComponentEditorController($rootScope, $scope, $log, $timeout, $mdDialog, focus, User, CalendarSettings, 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.recurrenceMonthDaysAreRequired = recurrenceMonthDaysAreRequired;\n vm.showAttendeesEditor = vm.component.attendees && vm.component.attendees.length;\n vm.toggleAttendeesEditor = toggleAttendeesEditor;\n //vm.searchText = null;\n vm.changeFrequency = changeFrequency;\n vm.changeCalendar = changeCalendar;\n vm.cardFilter = cardFilter;\n vm.addAttendee = addAttendee;\n vm.removeAttendee = removeAttendee;\n vm.addAttachUrl = addAttachUrl;\n vm.priorityLevel = priorityLevel;\n vm.changeAlarmRelation = changeAlarmRelation;\n vm.reset = reset;\n vm.cancel = cancel;\n vm.edit = edit;\n vm.save = save;\n vm.attendeeConflictError = false;\n vm.attendeesEditor = {\n days: getDays(),\n hours: getHours()\n };\n vm.addStartDate = addStartDate;\n vm.removeStartDate = removeStartDate;\n vm.addDueDate = addDueDate;\n vm.removeDueDate = removeDueDate;\n\n // Synchronize start and end dates\n vm.adjustStartTime = adjustStartTime;\n vm.adjustEndTime = adjustEndTime;\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 function recurrenceMonthDaysAreRequired() {\n return vm.component &&\n vm.component.repeat.frequency == 'monthly' &&\n vm.component.repeat.month.type == 'bymonthday';\n }\n\n function changeFrequency() {\n if (vm.component.repeat.frequency == 'custom')\n vm.showRecurrenceEditor = true;\n }\n\n function changeCalendar() {\n var updateRequired = (vm.component.attendees && vm.component.attendees.length > 0);\n if (updateRequired)\n vm.component.initOrganizer(Calendar.$get(vm.component.destinationCalendar));\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 var initOrganizer = (!vm.component.attendees || vm.component.attendees.length === 0),\n destinationCalendar = Calendar.$get(vm.component.destinationCalendar),\n options = initOrganizer? { organizerCalendar: destinationCalendar } : {};\n var emailRE = /([\\w\\!\\#$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`{\\|\\}\\~]+\\.)*[\\w\\!\\#$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`{\\|\\}\\~]+@((((([a-z0-9]{1}[a-z0-9\\-]{0,62}[a-z0-9]{1})|[a-z])\\.)+[a-z]{2,})|(\\d{1,3}\\.){3}\\d{1,3}(\\:\\d{1,5})?)/i,\n i, address;\n\n function createCard(str) {\n var match = str.match(emailRE),\n email = match[0],\n name = str.replace(new RegExp(\" *<?\" + email + \">? *\"), '');\n vm.showAttendeesEditor |= initOrganizer;\n vm.searchText = '';\n return new Card({ c_cn: _.trim(name, ' \"'), emails: [{ value: email }] });\n }\n\n if (angular.isString(card)) {\n // User pressed \"Enter\" in search field, adding a non-matching card\n // Examples that are handled:\n // Smith, John <john@smith.com>\n // <john@appleseed.com>;<foo@bar.com>\n // foo@bar.com abc@xyz.com\n address = '';\n for (i = 0; i < card.length; i++) {\n if ((card.charCodeAt(i) == 9 || // tab\n card.charCodeAt(i) == 32 || // space\n card.charCodeAt(i) == 44 || // ,\n card.charCodeAt(i) == 59) && // ;\n emailRE.test(address)) {\n vm.component.addAttendee(createCard(address), options);\n address = '';\n }\n else {\n address += card.charAt(i);\n }\n }\n if (address)\n vm.component.addAttendee(createCard(address), options);\n }\n else {\n vm.component.addAttendee(card, options);\n vm.showAttendeesEditor |= initOrganizer;\n }\n }\n\n function removeAttendee(attendee, form) {\n vm.component.deleteAttendee(attendee);\n if (vm.component.attendees.length === 0)\n vm.showAttendeesEditor = false;\n form.$setDirty();\n }\n\n function priorityLevel() {\n if (vm.component && vm.component.priority) {\n if (vm.component.priority > 5)\n return l('low'); // 6-7-8-9\n else if (vm.component.priority > 4)\n return l('normal'); // 5\n else\n return l('high'); // 1-2-3-4\n }\n }\n\n function changeAlarmRelation(form) {\n if (vm.component.type == 'task' &&\n ((!vm.component.start && vm.component.alarm.relation == 'START') ||\n (!vm.component.due && vm.component.alarm.relation == 'END'))) {\n form.alarmRelation.$setValidity('alarm', false);\n }\n else {\n form.alarmRelation.$setValidity('alarm', true);\n }\n }\n\n function save(form, options) {\n if (form.$valid) {\n vm.component.$save(options)\n .then(function(data) {\n $rootScope.$emit('calendars:list');\n Alarm.getAlarms();\n $mdDialog.hide();\n }, function(response) {\n if (response.status == CalendarSettings.ConflictHTTPErrorCode &&\n _.isObject(response.data.message))\n vm.attendeeConflictError = response.data.message;\n else\n edit(form);\n });\n }\n }\n\n function reset(form) {\n vm.component.$reset();\n form.$setPristine();\n }\n\n function cancel(form) {\n reset(form);\n if (vm.component.isNew) {\n // Cancelling the creation of a component\n vm.component = null;\n }\n $mdDialog.hide();\n }\n\n function edit(form) {\n vm.attendeeConflictError = false;\n form.$setPristine();\n form.$setDirty();\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(i.toString());\n }\n return hours;\n }\n\n function addStartDate(form) {\n vm.component.$addStartDate();\n oldStartDate = new Date(vm.component.start.getTime());\n if (!vm.component.due) {\n vm.component.alarm.relation = 'START';\n }\n changeAlarmRelation(form);\n }\n\n function removeStartDate(form) {\n vm.component.$deleteStartDate();\n if (vm.component.due) {\n vm.component.alarm.relation = 'END';\n }\n changeAlarmRelation(form);\n }\n\n function addDueDate(form) {\n vm.component.$addDueDate();\n oldDueDate = new Date(vm.component.due.getTime());\n if (!vm.component.start) {\n vm.component.alarm.relation = 'END';\n }\n changeAlarmRelation(form);\n }\n\n function removeDueDate(form) {\n vm.component.$deleteDueDate();\n if (vm.component.start) {\n vm.component.alarm.relation = 'START';\n }\n changeAlarmRelation(form);\n }\n\n function adjustStartTime() {\n if (vm.component.start) {\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 updateFreeBusy();\n }\n }\n }\n\n function adjustEndTime() {\n if (vm.component.end) {\n // The end date must be after the start date\n var delta = oldEndDate.valueOf() - vm.component.end.valueOf();\n if (delta !== 0) {\n 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 }\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 calendar: '@sgCalendar'\n },\n controller: sgCalendarDayController\n };\n }\n\n /**\n * @ngInject\n */\n sgCalendarDayController.$inject = ['$scope', 'Calendar'];\n function sgCalendarDayController($scope, Calendar) {\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 this.calendarData = function() {\n var pid, index, activeCalendars;\n if ($scope.calendar) {\n // A calendar is associated to the day; identify its index among active calendars\n pid = $scope.calendar;\n activeCalendars = _.filter(Calendar.$findAll(), { active: 1 });\n index = _.findIndex(activeCalendars, function(calendar) {\n return calendar.id == pid;\n });\n return { pid: pid, index: index };\n }\n\n return null;\n };\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: template,\n link: link\n };\n\n function template(tElem, tAttrs) {\n var p = _.has(tAttrs, 'sgCalendarGhost')? '' : '::';\n\n return [\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 '+p+'block.component.categories\"',\n ' ng-class=\"'+p+'(\\'bg-category\\' + category)\"',\n ' ng-style=\"'+p+'{ right: ($index * 3) + \\'px\\' }\"></div>',\n ' <div class=\"text\">',\n // Priority\n ' <span ng-show=\"'+p+'block.component.c_priority\" class=\"sg-priority\">{{'+p+'block.component.c_priority}}</span>',\n // Summary\n ' {{ '+p+'block.component.summary }}',\n ' <span class=\"icons\">',\n // Component is reccurent\n ' <md-icon ng-if=\"'+p+'block.component.occurrenceId\" class=\"material-icons icon-repeat\"></md-icon>',\n // Component has an alarm\n ' <md-icon ng-if=\"'+p+'block.component.c_nextalarm\" class=\"material-icons icon-alarm\"></md-icon>',\n // Component is confidential\n ' <md-icon ng-if=\"'+p+'block.component.c_classification == 2\" class=\"material-icons icon-visibility-off\"></md-icon>',\n // Component is private\n ' <md-icon ng-if=\"'+p+'block.component.c_classification == 1\" class=\"material-icons icon-vpn-key\"></md-icon>',\n ' </span>',\n // Location\n ' <div class=\"secondary\" ng-if=\"'+p+'block.component.c_location\">',\n ' <md-icon>place</md-icon> <span ng-bind=\"'+p+'block.component.c_location\"></span>',\n ' </div>',\n ' </div>',\n ' </div>',\n ' <div class=\"ghostStartHour\" ng-if=\"block.startHour\">{{ block.startHour }}</div>',\n ' <div class=\"ghostEndHour\" ng-if=\"block.endHour\">{{ block.endHour }}</div>',\n '</div>'\n ].join('');\n }\n\n function link(scope, iElement, attrs) {\n var pc, left, right;\n\n if (!_.has(attrs, 'sgCalendarGhost')) {\n\n // Compute position\n pc = 100 / scope.block.siblings;\n left = scope.block.position * pc;\n right = 100 - (scope.block.position + 1) * pc;\n\n // Add right margin (10%) for easier creation of events by mouse dragging\n if (right === 0)\n right = 10;\n\n // Set position\n iElement.css('left', left + '%');\n iElement.css('right', right + '%');\n if (!scope.block.component || !scope.block.component.c_isallday) {\n iElement.addClass('starts' + scope.block.start);\n iElement.addClass('lasts' + scope.block.length);\n }\n\n // Add class for user's participation state\n if (scope.block.userState)\n iElement.addClass('sg-event--' + scope.block.userState);\n\n if (scope.block.component) {\n // Set background color\n iElement.addClass('bg-folder' + scope.block.component.pid);\n iElement.addClass('contrast-bdr-folder' + scope.block.component.pid);\n\n // Add class for transparency\n if (scope.block.component.c_isopaque === 0)\n iElement.addClass('sg-event--transparent');\n\n // Add class for cancelled event\n if (scope.block.component.c_status === 0)\n iElement.addClass('sg-event--cancelled');\n }\n\n }\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, calendarNumber, originalCalendarNumber;\n\n domElement = iElement[0];\n calendarDayCtrl = ctrls[0];\n scrollViewCtrl = ctrls[1];\n calendarNumber = -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 var pid, calendarData, userState;\n\n // Expose ghost block to the scope\n scope.block = Component.$ghost;\n\n calendarData = calendarDayCtrl.calendarData();\n if (calendarData) {\n // A calendar is associated to the day; this is a special multicolumn day view\n calendarNumber = calendarData.index;\n pid = calendarData.pid;\n originalCalendarNumber = scope.block.pointerHandler.originalCalendar.index;\n }\n\n if (!pid)\n pid = scope.block.component.pid;\n\n // Add class for user's participation state\n userState = scope.block.component.blocks[0].userState;\n if (userState)\n iElement.addClass('sg-event--' + userState);\n\n // Set background color\n iElement.addClass('bg-folder' + 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, isAllDay, currentDay,\n start, duration, durationLeft, maxDuration;\n\n showGhost = false;\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 isAllDay = scope.block.component.c_isallday;\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 duration = durationLeft;\n if (duration > maxDuration)\n duration = maxDuration;\n\n if (currentDay > -1 && // pointer is inside viewport\n ((calendarNumber < 0 && // day is not associated to a calendar\n currentDay == calendarDayCtrl.dayNumber) || // pointer is inside ghost's day\n currentDay == calendarNumber && // pointer is inside ghost's calendar\n (originalCalendarNumber == calendarNumber || // still inside original calendar\n !scope.block.component.isException) // not an exception, event can be moved to a\n // different calendar\n )) {\n // This ghost block (day) is the first of the dragging event\n showGhost = true;\n if (!isRelative) {\n if (!isAllDay)\n // Show start hour and set the vertical position\n scope.block.startHour = getStartTime(start);\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 }\n iElement.removeClass('fg-folder' + scope.block.component.pid);\n iElement.removeClass('sg-event--ghost--last');\n iElement.addClass('sg-event--ghost--first');\n scope.block.isFirst = true;\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 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 }\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 if (!isAllDay) {\n // Set the end date\n scope.block.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 * sgCalendarListEvent - An event block to be displayed in a list\n * @memberof SOGo.SchedulerUI\n * @restrict element\n * @param {object} sgComponent - the Component object.\n * @param {function} sgClick - the function to call when clicking on the event.\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-list-event\n ng-repeat=\"event in dayData.events\"\n sg-component=\"event\"\n sg-click=\"list.openEvent($event, clickComponent)\" />\n */\n sgCalendarListEvent.$inject = ['CalendarSettings'];\n function sgCalendarListEvent(CalendarSettings) {\n return {\n restrict: 'E',\n scope: {\n component: '=sgComponent',\n clickComponent: '&sgClick'\n },\n replace: true,\n template: template,\n link: link\n };\n\n function template(tElem, tAttrs) {\n return [\n '<div class=\"sg-event\"',\n ' ng-click=\"clickComponent({clickEvent: $event, clickComponent: component})\">',\n // Categories color stripes\n ' <div class=\"sg-category\" ng-repeat=\"category in ::component.categories\"',\n ' ng-class=\"::(\\'bg-category\\' + category)\"',\n ' ng-style=\"::{ right: ($index * 3) + \\'px\\' }\"></div>',\n // Priority\n ' <span ng-show=\"::component.c_priority\" class=\"sg-priority\" ng-bind=\"::component.c_priority\"></span>',\n // Summary\n ' {{ ::component.c_title }}',\n ' <span class=\"icons\">',\n // Component is reccurent\n ' <md-icon ng-if=\"::component.occurrenceId\" class=\"material-icons icon-repeat\"></md-icon>',\n // Component has an alarm\n ' <md-icon ng-if=\"::component.c_nextalarm\" class=\"material-icons icon-alarm\"></md-icon>',\n // Component is confidential\n ' <md-icon ng-if=\"::component.c_classification == 2\" class=\"material-icons icon-visibility-off\"></md-icon>',\n // Component is private\n ' <md-icon ng-if=\"::component.c_classification == 1\" class=\"material-icons icon-vpn-key\"></md-icon>',\n ' </span>',\n // Time\n ' <div class=\"secondary\" ng-if=\"::!component.c_isallday\">',\n ' <md-icon>access_time</md-icon> <span ng-bind=\"::component.starthour\"></span>',\n ' </div>',\n // Location\n ' <div class=\"secondary\" ng-if=\"::component.c_location\">',\n ' <md-icon>place</md-icon> <span ng-bind=\"::component.c_location\"></span>',\n ' </div>',\n '</div>'\n ].join('');\n }\n\n function link(scope, iElement, attrs) {\n /**\n * No data binding here since the view is completely redraw when\n * a change is detected.\n */\n\n if (scope.component.viewable)\n iElement.addClass('md-clickable');\n\n // Add class for user's participation state\n if (scope.component.userstate)\n iElement.addClass('sg-event--' + scope.component.userstate);\n\n // Set background color\n iElement.addClass('bg-folder' + scope.component.pid);\n iElement.addClass('contrast-bdr-folder' + scope.component.pid);\n\n // Add class for transparency\n if (scope.component.c_isopaque === 0)\n iElement.addClass('sg-event--transparent');\n\n // Add class for cancelled event\n if (scope.component.c_status === 0)\n iElement.addClass('sg-event--cancelled');\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgCalendarListEvent', sgCalendarListEvent);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n\n /**\n * sgCalendarListItem - A directive that defines the content of a md-list-item for a calendar.\n * @memberof SOGo.SchedulerUI\n */\n function sgCalendarListItem() {\n return {\n restrict: 'C',\n scope: {},\n bindToController: {\n calendar: '=sgCalendar'\n },\n template: [\n '<md-switch ng-model=\"$ctrl.calendar.active\"',\n ' ng-class=\"$ctrl.calendar.getClassName(\\'md-switch\\')\"',\n ' ng-true-value=\"1\"',\n ' ng-false-value=\"0\"',\n ' aria-label=\"' + l('Enable') + '\"></md-switch>',\n '<p class=\"sg-item-name\"',\n ' ng-dblclick=\"$ctrl.editFolder($event)\">',\n ' <span ng-bind=\"$ctrl.calendar.name\"></span>',\n ' <md-icon ng-if=\"$ctrl.calendar.$error\" class=\"md-warn\">error</md-icon>',\n ' <md-tooltip md-delay=\"1000\"',\n ' md-autohide=\"true\"',\n ' ng-bind=\"$ctrl.calendar.name\"></md-tooltip>',\n ' <span class=\"sg-counter-badge ng-hide\"',\n ' ng-show=\"calendar.activeTasks\"',\n ' ng-bind=\"calendar.activeTasks\"></span>',\n '</p>',\n '<md-input-container class=\"md-flex ng-hide\">',\n ' <input class=\"sg-item-name\" type=\"text\"',\n ' aria-label=\"' + l('Name of the Calendar') + '\"',\n ' ng-blur=\"$ctrl.saveFolder($event)\"',\n ' sg-enter=\"$ctrl.saveFolder($event)\"',\n ' sg-escape=\"$ctrl.revertEditing()\" />',\n '</md-input-container>',\n '<md-button class=\"md-secondary md-icon-button\" ',\n ' as-sortable-item-handle=\"as-sortable-item-handle\">',\n ' <md-icon md-colors=\"::{color: \\'accent-400\\'}\">drag_handle</md-icon>',\n '</md-button>',\n '<md-icon class=\"md-menu sg-list-sortable-hide\"',\n ' ng-click=\"$ctrl.showMenu($event)\"',\n ' aria-label=\"' + l(\"Options\") + '\">more_vert</md-icon>'\n ].join(''),\n controller: 'sgCalendarListItemController',\n controllerAs: '$ctrl'\n };\n }\n\n /**\n * @ngInject\n */\n sgCalendarListItemController.$inject = ['$rootScope', '$scope', '$element', '$mdToast', '$mdPanel', '$mdMedia', '$mdSidenav', 'sgConstant', 'Dialog', 'Calendar'];\n function sgCalendarListItemController($rootScope, $scope, $element, $mdToast, $mdPanel, $mdMedia, $mdSidenav, sgConstant, Dialog, Calendar) {\n var $ctrl = this;\n\n\n this.$onInit = function() {\n this.editMode = false;\n };\n\n\n this.$postLink = function() {\n this.clickableElement = $element.find('p')[0];\n this.nameElements = this.clickableElement.getElementsByClassName('sg-calendar-name');\n this.inputContainer = $element.find('md-input-container')[0];\n this.inputElement = $element.find('input')[0];\n this.moreOptionsButton = _.last($element.find('md-icon'));\n this.updateCalendarName();\n };\n\n\n this.updateCalendarName = function() {\n _.forEach(this.nameElements, function(e) {\n e.innerHTML = $ctrl.calendar.name;\n });\n };\n\n\n this.editFolder = function($event) {\n this.editMode = true;\n this.inputElement.value = this.calendar.name;\n this.clickableElement.classList.add('ng-hide');\n this.inputContainer.classList.remove('ng-hide');\n this.inputElement.focus();\n this.inputElement.select();\n if ($event) {\n $event.stopPropagation();\n $event.preventDefault();\n }\n };\n\n\n this.saveFolder = function($event) {\n if (this.inputElement.disabled)\n return;\n\n this.calendar.name = this.inputElement.value;\n this.inputElement.disabled = true;\n this.calendar.$rename()\n .then(function(data) {\n $ctrl.editMode = false;\n $ctrl.inputContainer.classList.add('ng-hide');\n $ctrl.clickableElement.classList.remove('ng-hide');\n $ctrl.updateCalendarName();\n })\n .finally(function() {\n $ctrl.inputElement.disabled = false;\n });\n };\n\n\n this.revertEditing = function() {\n this.editMode = false;\n this.clickableElement.classList.remove('ng-hide');\n this.inputContainer.classList.add('ng-hide');\n this.inputElement.value = this.calendar.name;\n };\n\n\n this.confirmDelete = function() {\n if (this.calendar.isSubscription) {\n // Unsubscribe without confirmation\n this.calendar.$delete()\n .catch(function(data, status) {\n Dialog.alert(l('An error occured while deleting the calendar \"%{0}\".', $ctrl.calendar.name),\n l(data.error));\n });\n }\n else {\n Dialog.confirm(l('Warning'), l('Are you sure you want to delete the calendar \"%{0}\"?', this.calendar.name),\n { ok: l('Delete') })\n .then(function() {\n $ctrl.calendar.$delete()\n .catch(function(data, status) {\n Dialog.alert(l('An error occured while deleting the calendar \"%{0}\".', $ctrl.calendar.name),\n l(data.error));\n });\n });\n }\n };\n\n\n this.showMenu = function($event) {\n var panelPosition = $mdPanel.newPanelPosition()\n .relativeTo(this.moreOptionsButton)\n .addPanelPosition(\n $mdPanel.xPosition.ALIGN_START,\n $mdPanel.yPosition.ALIGN_TOPS\n );\n\n var panelAnimation = $mdPanel.newPanelAnimation()\n .openFrom(this.moreOptionsButton)\n .duration(100)\n .withAnimation($mdPanel.animation.FADE);\n\n var config = {\n attachTo: angular.element(document.body),\n locals: {\n itemCtrl: this,\n calendar: this.calendar,\n editFolder: angular.bind(this, this.editFolder),\n confirmDelete: angular.bind(this, this.confirmDelete)\n },\n bindToController: true,\n controller: MenuController,\n controllerAs: '$menuCtrl',\n position: panelPosition,\n animation: panelAnimation,\n targetEvent: $event,\n templateUrl: 'UIxCalendarMenu',\n trapFocus: true,\n clickOutsideToClose: true,\n escapeToClose: true,\n focusOnOpen: true\n };\n\n $mdPanel.open(config)\n .then(function(panelRef) {\n // Automatically close panel when clicking inside of it\n panelRef.panelEl.one('click', function() {\n panelRef.close();\n });\n });\n\n MenuController.$inject = ['mdPanelRef', '$mdDialog', 'FileUploader', 'User'];\n function MenuController(mdPanelRef, $mdDialog, FileUploader, User) {\n var $menuCtrl = this;\n\n this.showOnly = function() {\n _.forEach(Calendar.$findAll(), function(o) {\n if ($menuCtrl.calendar.id == o.id)\n o.active = 1;\n else\n o.active = 0;\n });\n };\n\n this.showAll = function() {\n _.forEach(Calendar.$findAll(), function(o) { o.active = 1; });\n };\n\n this.showProperties = function() {\n var color = this.calendar.color;\n $mdDialog.show({\n templateUrl: this.calendar.id + '/properties',\n controller: PropertiesDialogController,\n controllerAs: 'properties',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n srcCalendar: this.calendar\n }\n }).catch(function() {\n // Restore original color when cancelling or closing the dialog\n $menuCtrl.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(function() { return vm.calendar.color; }, function() {\n srcCalendar.color = vm.calendar.color;\n });\n\n function saveProperties(form) {\n if (form.$valid) {\n vm.calendar.$save();\n // Refresh list instance\n srcCalendar.init(vm.calendar.$omit());\n $mdDialog.hide();\n }\n }\n\n function close() {\n $mdDialog.cancel();\n }\n }\n };\n\n this.showLinks = function() {\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: this.calendar.id + '/links',\n controller: LinksDialogController,\n controllerAs: 'links',\n locals: {\n calendar: this.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 this.importCalendar = function() {\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: 'UIxCalendarImportDialog', // subtemplate of UIxCalMainView.wox\n controller: CalendarImportDialogController,\n controllerAs: '$CalendarImportDialogController',\n locals: {\n folder: this.calendar\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 this.share = function() {\n // Fetch list of ACL users\n this.calendar.$acl.$users().then(function() {\n // Show ACL editor\n $mdDialog.show({\n templateUrl: $menuCtrl.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: $menuCtrl.calendar.$acl.users,\n User: User,\n folder: $menuCtrl.calendar\n }\n });\n });\n };\n\n } // MenuController\n\n\n };\n }\n\n\n angular\n .module('SOGo.SchedulerUI')\n .controller('sgCalendarListItemController', sgCalendarListItemController)\n .directive('sgCalendarListItem', sgCalendarListItem);\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.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-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: template,\n link: link\n };\n\n function template(tElem, tAttrs) {\n var p = _.has(tAttrs, 'sgCalendarGhost')? '' : '::';\n\n return [\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 // Categories color stripes\n ' <div class=\"sg-category\" ng-repeat=\"category in '+p+'block.component.categories\"',\n ' ng-class=\"'+p+'(\\'bg-category\\' + category)\"',\n ' ng-style=\"'+p+'{ right: ($index * 3) + \\'px\\' }\"></div>',\n ' <span class=\"secondary\" ng-if=\"'+p+'(!block.component.c_isallday && block.isFirst)\">{{ '+p+'block.component.startHour }}</span>',\n // Priority\n ' <span ng-show=\"'+p+'block.component.c_priority\" class=\"sg-priority\">{{'+p+'block.component.c_priority}}</span>',\n // Summary\n ' {{ '+p+'block.component.summary }}',\n ' <span class=\"icons\">',\n // Component is reccurent\n ' <md-icon ng-if=\"'+p+'block.component.occurrenceId\" class=\"material-icons icon-repeat\"></md-icon>',\n // Component has an alarm\n ' <md-icon ng-if=\"'+p+'block.component.c_nextalarm\" class=\"material-icons icon-alarm\"></md-icon>',\n // Component is confidential\n ' <md-icon ng-if=\"'+p+'block.component.c_classification == 2\" class=\"material-icons icon-visibility-off\"></md-icon>',\n // Component is private\n ' <md-icon ng-if=\"'+p+'block.component.c_classification == 1\" class=\"material-icons icon-vpn-key\"></md-icon>',\n ' </span>',\n '</div>'\n ].join('');\n }\n\n function link(scope, iElement, attrs) {\n if (!_.has(attrs, 'sgCalendarGhost')) {\n\n // Add class for user's participation state\n if (scope.block.userState)\n iElement.addClass('sg-event--' + scope.block.userState);\n\n if (scope.block.component) {\n // Set background color\n iElement.addClass('bg-folder' + scope.block.component.pid);\n\n // Add class for transparency\n if (scope.block.component.c_isopaque === 0)\n iElement.addClass('sg-event--transparent');\n\n // Add class for cancelled event\n if (scope.block.component.c_status === 0)\n iElement.addClass('sg-event--cancelled');\n }\n\n }\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, type, isMultiColumn = false;\n\n view = null;\n type = scope.type; // multiday, multiday-allday, monthly, unknown?\n isMultiColumn = (element.attr('sg-view') == 'multicolumndayview');\n\n // Expose isMultiColumn in the controller\n // See sgNowLine directive\n controller.isMultiColumn = isMultiColumn;\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 if (view) {\n view.$destroy();\n }\n });\n\n function initView() {\n view = new sgScrollView(element, type);\n\n if (type != 'monthly') {\n // Scroll to the day start hour defined in the user's defaults\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]) * view.quarterHeight;\n view.element.scrollTop = hourCell.offsetTop + quartersOffset;\n }\n }\n\n // Expose quarter height to the controller\n // See sgNowLine directive\n controller.quarterHeight = view.quarterHeight;\n }\n\n /**\n * sgScrollView\n */\n function sgScrollView($element, type) {\n this.$element = $element;\n this.element = $element[0];\n this.type = type;\n this.quarterHeight = this.getQuarterHeight();\n this.scrollStep = 6 * this.quarterHeight;\n this.dayNumbers = this.getDayNumbers();\n this.maxX = this.getMaxColumns();\n\n // Listen to dragstart and dragend events\n this.deregisterDragStart = $rootScope.$on('calendar:dragstart', angular.bind(this, this.onDragStart));\n this.deregisterDragStop = $rootScope.$on('calendar:dragend', angular.bind(this, this.onDragEnd));\n\n this.bindedUpdateCoordinates = angular.bind(this, this.updateCoordinates);\n this.bindedUpdateFromPointerHandler = angular.bind(this, this.updateFromPointerHandler);\n\n // Compute coordinates of view element; recompute it on window resize\n this.updateCoordinates();\n angular.element($window).on('resize', this.bindedUpdateCoordinates);\n }\n\n sgScrollView.prototype = {\n\n $destroy: function() {\n this.deregisterDragStart();\n this.deregisterDragStop();\n this.$element.off('mousemove', this.bindedUpdateFromPointerHandler);\n angular.element($window).off('resize', this.bindedUpdateCoordinates);\n },\n\n onDragStart: function() {\n this.$element.on('mousemove', this.bindedUpdateFromPointerHandler);\n this.updateCoordinates();\n this.updateFromPointerHandler();\n },\n\n onDragEnd: function() {\n this.$element.off('mousemove', this.bindedUpdateFromPointerHandler);\n Calendar.$view = null;\n },\n\n getQuarterHeight: function() {\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\n getDayDimensions: function(viewLeft) {\n var width, height, leftOffset, topOffset, nodes, domRect, tileHeader;\n\n height = width = leftOffset = topOffset = 0;\n nodes = this.element.getElementsByClassName('day');\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\n getDayNumbers: function() {\n var viewType = null, days, total, sum;\n\n days = this.element.getElementsByTagName('sg-calendar-day');\n\n return _.map(days, function(el, index) {\n if (isMultiColumn)\n return index;\n else\n return parseInt(el.attributes['sg-day-number'].value);\n });\n },\n\n\n getMaxColumns: function() {\n var mdGridList, max = 0;\n\n if (this.type == 'monthly') {\n mdGridList = this.element.getElementsByTagName('md-grid-list')[0];\n max = parseInt(mdGridList.attributes['md-cols'].value) - 1;\n }\n else {\n max = this.element.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 updateCoordinates: function() {\n var domRect, dayDimensions;\n\n domRect = this.element.getBoundingClientRect();\n dayDimensions = this.getDayDimensions(domRect.left);\n\n angular.extend(this, {\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\n // From SOGoScrollController.updateFromPointerHandler\n updateFromPointerHandler: function() {\n var pointerHandler, pointerCoordinates, now, scrollY, minY, delta;\n\n pointerHandler = Component.$ghost.pointerHandler;\n if (this.coordinates && pointerHandler) {\n pointerCoordinates = pointerHandler.getContainerBasedCoordinates(this);\n\n if (pointerCoordinates) {\n // Pointer is inside view; Adjust scrollbar if necessary\n Calendar.$view = this;\n now = new Date().getTime();\n if (!this.lastScroll || now > this.lastScroll + 100) {\n this.lastScroll = now;\n scrollY = pointerCoordinates.y - this.scrollStep;\n if (scrollY < 0) {\n minY = -this.element.scrollTop;\n if (scrollY < minY)\n scrollY = minY;\n this.element.scrollTop += scrollY;\n }\n else {\n scrollY = pointerCoordinates.y + this.scrollStep;\n delta = scrollY - this.element.clientHeight;\n if (delta > 0) {\n this.element.scrollTop += delta;\n }\n }\n }\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 sgCalendarGhost directive\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', 'Preferences', 'Calendar', 'CalendarSettings', 'Component'];\n function sgDraggableCalendarBlock($rootScope, $timeout, $log, Preferences, 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 && !scope.block.userState) {\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, dayIndex, blockIndex, isFirstBlock, isLastBlock,\n dragGrip, leftGrip, rightGrip, topGrip, bottomGrip;\n\n // Don't show grips for blocks of less than 45 minutes\n if (scope.block.length < 3) return;\n\n component = scope.block.component;\n dayIndex = scope.block.dayIndex;\n blockIndex = _.findIndex(component.blocks, ['dayIndex', dayIndex]);\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 dragMode, pointerHandler, hasVerticalScrollbar, rect, scrollableZone;\n\n ev.stopPropagation();\n\n hasVerticalScrollbar = ev.target.scrollHeight > ev.target.clientHeight + 1;\n\n if (hasVerticalScrollbar) {\n // Check if mouse click is inside scrollbar\n rect = ev.target.getBoundingClientRect();\n scrollableZone = rect.left + rect.width - 18;\n if (ev.pageX > scrollableZone)\n return;\n }\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, eventType, isHourCell, isMonthly, startDate, newData, newComponent, pointerHandler, calendarData;\n\n isHourCell = element.hasClass('clickableHourCell');\n isMonthly = (element[0].parentNode.tagName == 'SG-CALENDAR-MONTH-DAY') ||\n element.hasClass('clickableDayCell');\n\n calendarData = calendarDayCtrl.calendarData();\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 = calendarDayCtrl.dayString.parseDate(Preferences.$mdDateLocaleProvider, '%Y-%m-%e');\n newData = {\n type: 'appointment',\n pid: calendarData? calendarData.pid : Calendar.$defaultCalendar(),\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 if (calendarData)\n // When the day is associated to a calendar, the day number becomes the calendar index\n // among the active calendars\n pointerHandler.initFromCalendar(calendarData);\n\n // Update Component.$ghost\n Component.$ghost.component = block.component;\n\n $log.debug('emit calendar:dragstart ' + eventType);\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 && block.component)\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 if (Calendar.$view) {\n delta.days = Calendar.$view.dayNumbers[this.x] - Calendar.$view.dayNumbers[otherCoordinates.x];\n }\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 weekDay: -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 var prevDayNumber = -1;\n\n if (this.eventType === 'monthly') {\n this.start = 0;\n this.duration = block.component.blocks.length * CalendarSettings.EventDragDayLength;\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 = _.sumBy(block.component.blocks, function(b) {\n var delta, currentDayNumber;\n\n currentDayNumber = b.dayNumber;\n if (prevDayNumber < 0)\n delta = 0;\n else\n delta = currentDayNumber - prevDayNumber - 1;\n prevDayNumber = currentDayNumber;\n\n return b.length + delta * CalendarSettings.EventDragDayLength;\n });\n }\n },\n\n initFromCalendar: function(calendarNumber) {\n this.dayNumber = calendarNumber;\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 originalCalendar: 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 initFromCalendar: function SEDPH_initFromCalendar(calendarData) {\n this.originalCalendar = calendarData;\n this.currentEventCoordinates.initFromCalendar(calendarData.index);\n this.originalEventCoordinates.initFromCalendar(calendarData.index);\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.days * CalendarSettings.EventDragDayLength + delta.y;\n $log.debug('quarters delta ' + deltaQuarters);\n\n if (angular.isUndefined(this.originalEventCoordinates.start)) {\n // Creating new appointment from DnD\n this.originalEventCoordinates.dayNumber = Calendar.$view.dayNumbers[this.originalViewCoordinates.x];\n this.originalEventCoordinates.start = this.originalViewCoordinates.y;\n }\n else if (this.originalEventCoordinates.dayNumber < 0) {\n this.originalEventCoordinates.dayNumber = Calendar.$view.dayNumbers[scope.block.component.blocks[0].dayIndex];\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 this.currentEventCoordinates.dayNumber += deltaDays;\n }\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 minX = 0;\n var maxX = Calendar.$view.maxX;\n if (this.dragMode != 'move-event') {\n var calendarData = calendarDayCtrl.calendarData();\n if (calendarData)\n // Resizing an event can't span a different day when in multicolumn view\n minX = maxX = calendarData.index;\n }\n if (coordinates.x < minX)\n coordinates.x = minX;\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 maxX = view.maxX;\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 > maxX)\n coordinates.x = maxX;\n coordinates.x += (maxX + 1) * 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","/* -*- Mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgNowLine - Now line to be displayed on top of current day\n * @restrict class\n */\n function sgNowLine() {\n return {\n restrict: 'C',\n require: '^^sgCalendarScrollView',\n link: link,\n controller: sgNowLineController\n };\n\n function link(scope, iElement, iAttr, sgCalendarScrollViewCtrl) {\n function _getDays() {\n return iElement.find('sg-calendar-day');\n }\n function _getView() {\n return sgCalendarScrollViewCtrl.quarterHeight;\n }\n\n // We need to wait for the view to be compiled\n var _unwatchView = scope.$watch(_getView, function(quarterHeight) {\n if (quarterHeight) {\n _unwatchView(); // self release\n scope.quarterHeight = quarterHeight;\n // We need to wait for the days to be compiled\n var _unwatchDays = scope.$watch(_getDays, function(days) {\n if (days.length) {\n _unwatchDays(); // self release\n scope.days = days;\n // Draw the line\n scope.updateLine();\n }\n });\n }\n });\n }\n }\n\n /**\n * @ngInject\n */\n sgNowLineController.$inject = ['$scope', '$element', '$timeout'];\n function sgNowLineController($scope, $element, $timeout) {\n var _this = this, updater,\n scrollViewCtrl = $element.controller('sgCalendarScrollView');\n\n $scope.nowDay = null;\n $scope.lineElement = null;\n $scope.updateLine = _updateLine;\n\n $scope.$on('$destroy', function() {\n if (updater)\n $timeout.cancel(updater);\n });\n\n\n function _updateLine(force) {\n var now = new Date(), // TODO: adjust to user's timezone\n nowDay = now.getDayString(),\n hours = now.getHours(),\n hourHeight = $scope.quarterHeight * 4,\n minutes = now.getMinutes(),\n minuteHeight = $scope.quarterHeight/15,\n position = parseInt(hours * hourHeight +\n minutes * minuteHeight -\n 1);\n\n if (force || nowDay != $scope.nowDay) {\n if ($scope.lineElement)\n $scope.lineElement.remove();\n $scope.lineElement = _addLine(nowDay, $scope.days);\n $scope.nowDay = nowDay;\n }\n\n if ($scope.lineElement) {\n // Current day is displayed\n $scope.lineElement.css('top', position + \"px\");\n // Update line every minute\n updater = $timeout(angular.bind(_this, $scope.updateLine), 60000);\n }\n }\n\n function _addLine(nowDay, days) {\n var $lineElement = angular.element('<sg-now-line>');\n\n if (scrollViewCtrl.isMultiColumn) {\n // In multicolumn day view, the line must go over all columns\n if (days && days[0].attributes['sg-day'].value == nowDay)\n $element.append($lineElement);\n }\n else\n _.forEach(days, function(dayElement) {\n if (dayElement.attributes['sg-day'].value == nowDay) {\n angular.element(dayElement).find('div').eq(0).append($lineElement);\n }\n });\n\n return $lineElement;\n }\n }\n\n angular\n .module('SOGo.SchedulerUI')\n .directive('sgNowLine', sgNowLine);\n})();\n"]}