sogo/UI/WebServerResources/js/Scheduler.services.js.map
2016-01-21 10:21:45 -05:00

1 line
82 KiB
Plaintext

{"version":3,"sources":["Scheduler/Calendar.service.js","Scheduler/Component.service.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","factory","$defaultCalendar","calendar","defaultCalendar","defaults","SOGoDefaultCalendar","_","find","$findAll","active","$add","list","sibling","i","isWebCalendar","$webcalendars","isSubscription","$subscriptions","$calendars","o","localeCompare","indexOf","pluck","splice","data","writable","_this","forEach","push","union","filter","acls","objectCreator","$get","$getIndex","$subscribe","uid","path","userResource","fetch","then","calendarData","$addWebCalendar","url","d","defer","urls","webCalendarURL","reject","post","isEditable","isRemote","owner","login","debug","JSON","stringify","undefined","resolve","promise","$deleteComponents","components","calendars","component","isDefined","c_folder","c_name","uids","$events","difference","$tasks","prototype","color","$acl","isOwned","isSuperUser","isUndefined","$shadowData","$omit","$id","when","$futureCalendarData","getClassName","base","$rename","$save","$delete","remove","$reset","key","save","error","$setActivation","$getComponent","componentId","recurrenceId","$find","isError","isObject","futureComponentData","pid","newComponentData","newguid","isNew","Card","Gravatar","$Card","$gravatar","baseURL","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","$refreshTimeout","$ghost","ready","settings","EventsFilterState","TasksFilterState","EventsSortingState","parseInt","TasksSortingState","show_completed","ShowCompletedTasks","$categories","SOGoCalendarCategoriesColors","SOGoTimeFormat","$selectedCount","count","event","selected","length","task","$startRefreshTimeout","type","cancel","refreshViewCheck","SOGoRefreshViewCheck","f","bind","$filter","timeInterval","options","now","Date","day","getDate","month","getMonth","year","getFullYear","queryKey","capitalize","params","otherType","dirty","each","keys","$unwrapCollection","calendarId","occurrenceId","join","filterCategories","query","re","RegExp","category","saveSelectedList","componentType","$eventsBlocksForView","view","date","viewAction","startDate","endDate","beginOfWeek","setTime","getTime","addDays","setDate","setMonth","endOfWeek","$eventsBlocks","j","dates","deferred","toLowerCase","sd","getDayString","ed","views","reduceComponent","associateComponent","objects","eventData","componentData","object","eventsFields","start","c_startdate","hour","getHourString","blocks","block","nbr","$views","viewData","allDayBlocks","reduce","events","flatten","dayNumber","calendarName","fields","invoke","$parseDate","dateString","time","substring","split","no_time","categories","repeat","alarm","action","quantity","unit","reference","relation","status","delta","classification","isString","setMinutes","Math","round","getMinutes","end","minutesTo","setDelta","dueDate","due","c_category","$isRecurrent","days","byDayMask","occurrence","frequency","byday","toString","interval","monthdays","months","until","$hasCustomRepeat","hasCustomRepeat","units","M","H","D","W","match","exec","SOGoCalendarDefaultReminder","$hasAlarm","destinationCalendar","updateFreeBusy","b","isReadOnly","isEditableOccurrence","isInvitation","userHasRSVP","isInvitationOccurrence","enablePercentComplete","coversFreeBusy","quarter","freebusy","updateFreeBusyCoverage","roundedStart","roundedEnd","startQuarter","endQuarter","daysUpTo","index","hourKey","currentDay","dayKey","getHours","beginOfDay","addMinutes","attendees","attendee","image","email","updateFreeBusyAttendee","sday","eday","map","addAttendee","card","$isList","isGroup","container","listId","refs","ref","c_cn","$preferredEmail","role","c_uid","hasAttendee","emails","deleteAttendee","findIndex","currentAttendee","canRemindAttendeesByEmail","addAttachUrl","attachUrl","attachUrls","deleteAttachUrl","$addDueDate","toISOString","$deleteDueDate","$addStartDate","$deleteStartDate","$reply","reply","delegatedTo","$adjust","every","values","v","dlp","constructor","$mdDateLocaleProvider","format","startTime","endTime","dueTime","stringWithSeparator","organizer","occurrenceOnly","$futureComponentData","copy","repeatDescription","localizedString","l","toUpperCase","alarmDescription"],"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,\n EventDragHorizontalOffset: 3\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, i;\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 = _.find(list, function(o) {\n return (o.id != 'personal' &&\n o.name.localeCompare(calendar.name) === 1);\n });\n i = sibling ? _.indexOf(_.pluck(list, 'id'), sibling.id) : 1;\n list.splice(i, 0, calendar);\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\n if (writable) {\n return _.union(this.$calendars, _.filter(this.$subscriptions, function(calendar) { return calendar.acls.objectCreator; }));\n }\n\n return _.union(this.$calendars, this.$subscriptions, this.$webcalendars);\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(_.pluck(Calendar.$calendars, 'id'), id);\n if (i < 0)\n i = _.indexOf(_.pluck(Calendar.$subscriptions, 'id'), id);\n if (i < 0)\n i = _.indexOf(_.pluck(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(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.$add(calendar);\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 });\n d.resolve();\n }, function() {\n d.reject();\n });\n }\n\n return d.promise;\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\n // We create a c_folder -> event hash\n var calendars = {}, _this = this;\n\n _.forEach(components, function(component) {\n if (!angular.isDefined(calendars[component.c_folder]))\n calendars[component.c_folder] = [];\n\n calendars[component.c_folder].push(component.c_name);\n });\n\n _.forEach(calendars, function(uids, c_folder) {\n Calendar.$$resource.post(c_folder, 'batchDelete', {uids: uids});\n });\n\n // We slice both arrays - might be useful if in the future, we can delete\n // events and tasks at the same time.\n _this.$Component.$events = _.difference(_this.$Component.$events, components);\n _this.$Component.$tasks = _.difference(_this.$Component.$tasks, components);\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 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(_.pluck(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(_.pluck(list, 'id'), _this.id);\n list.splice(i, 1);\n });\n };\n\n /**\n * @function $reset\n * @memberof Mailbox.prototype\n * @desc Reset the original state the mailbox'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 $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', 'sgSettings', 'Preferences', 'Card', 'Gravatar', 'Resource', function($q, $timeout, $log, Settings, Preferences, Card, Gravatar, Resource) {\n angular.extend(Component, {\n $q: $q,\n $timeout: $timeout,\n $log: $log,\n $Preferences: Preferences,\n $Card: Card,\n $gravatar: Gravatar,\n $$resource: new Resource(Settings.baseURL(), 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 Preferences.ready().then(function() {\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\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 .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 component type, for all calendars\n */\n Component.$startRefreshTimeout = function(type) {\n var _this = this;\n\n if (Component.$refreshTimeout)\n Component.$timeout.cancel(Component.$refreshTimeout);\n\n Component.$Preferences.ready().then(function() {\n // Restart the refresh timer, if needed\n var refreshViewCheck = Component.$Preferences.defaults.SOGoRefreshViewCheck;\n if (refreshViewCheck && refreshViewCheck != 'manually') {\n var f = angular.bind(_this, Component.$filter, type);\n Component.$refreshTimeout = Component.$timeout(f, refreshViewCheck.timeInterval()*1000);\n }\n });\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\n Component.$startRefreshTimeout(type);\n\n return this.$Preferences.ready().then(function() {\n var futureComponentData,\n dirty = false,\n otherType;\n\n angular.extend(_this.$query, params);\n\n if (options) {\n _.each(_.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 otherType = (type == 'tasks')? '$events' : '$tasks';\n if (dirty) {\n delete Component[otherType];\n Component.$log.debug('force reload of ' + otherType);\n }\n\n return _this.$unwrapCollection(type, futureComponentData);\n });\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, 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 viewAction, startDate, endDate, params;\n\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();\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();\n endDate = new Date();\n endDate.setTime(startDate.getTime());\n endDate.setMonth(endDate.getMonth() + 1);\n endDate.addDays(-1);\n endDate = endDate.endOfWeek();\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, dates = [],\n deferred = Component.$q.defer();\n\n params = { view: view.toLowerCase(), sd: startDate.getDayString(), ed: endDate.getDayString() };\n Component.$log.debug('eventsblocks ' + JSON.stringify(params, undefined, 2));\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 = _.object(this.eventsFields, eventData),\n start = new Date(componentData.c_startdate * 1000);\n componentData.hour = start.getHourString();\n componentData.blocks = [];\n objects.push(new Component(componentData));\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 };\n\n Component.$views = [];\n Component.$timeout(function() {\n _.forEach(views, function(data) {\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, reduceComponent, components, data);\n\n // Associate Component objects to blocks positions\n _.forEach(_.flatten(data.blocks), associateComponent, components);\n\n // Associate Component objects to all-day blocks positions\n _.each(_.flatten(data.allDayBlocks), associateComponent, components);\n\n // Build array of dates\n if (dates.length === 0)\n for (i = 0; i < data.blocks.length; i++) {\n dates.push(startDate.getDayString());\n startDate.addDays(1);\n }\n\n // Convert array of blocks to object with days 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].dayNumber = i;\n blocks[dates[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].dayNumber = i;\n allDayBlocks[dates[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 return futureComponentData.then(function(data) {\n return Component.$timeout(function() {\n var fields = _.invoke(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 _.reduce(data[type], function(components, componentData, i) {\n var data = _.object(fields, componentData);\n components.push(new Component(data));\n return components;\n }, components);\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 return components;\n });\n });\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 Component.$Preferences.ready().then(function() {\n var type = (_this.type == 'appointment')? 'Events' : 'Tasks';\n\n // Set default values from user's defaults\n _this.classification = _this.classification ||\n Component.$Preferences.defaults['SOGoCalendar' + type + 'DefaultClassification'].toLowerCase();\n });\n\n if (this.component == 'vevent')\n this.type = 'appointment';\n else if (this.component == 'vtoto')\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.c_category)\n this.categories = _.invoke(this.c_category, 'asCSSIdentifier');\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 (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.month))\n this.repeat.month = { occurrence: '1', day: 'SU', type: 'bymonthday' };\n if (angular.isUndefined(this.repeat.monthdays))\n // TODO: initialize this.repeat.monthdays with month day of start date\n this.repeat.monthdays = [];\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 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 alarm\n Component.$Preferences.ready().then(function() {\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 }\n else {\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 // Load freebusy of attendees\n this.updateFreeBusy();\n\n this.selected = false;\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.isDefined(this.repeat) &&\n (this.repeat.interval > 1 ||\n this.repeat.days && this.repeat.days.length > 0 ||\n this.repeat.monthdays && this.repeat.monthdays.length > 0 ||\n this.repeat.months && this.repeat.months.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 isReadOnly\n * @memberof Component.prototype\n * @desc Check if the component is not editable and not an invitation\n * @returns true or false\n */\n Component.prototype.isReadOnly = function() {\n return (this.isReadOnly && !this.userHasRSVP);\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 _.each(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 _.each(this.attendees, function(attendee) {\n attendee.image = Component.$gravatar(attendee.email, 32);\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 params, url, days;\n if (attendee.uid) {\n params =\n {\n sday: this.start.getDayString(),\n eday: this.end.getDayString()\n };\n url = ['..', '..', attendee.uid, 'freebusy.ifb'];\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 Component.$$resource.fetch(url.join('/'), 'ajaxRead', params).then(function(data) {\n _.each(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) {\n var _this = this, attendee, list, url, params;\n if (card) {\n if (card.$isList() && card.isGroup !== 1) {\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 status: 'needs-action',\n uid: ref.c_uid\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 name: card.c_cn,\n email: card.$preferredEmail(),\n role: 'req-participant',\n status: 'needs-action',\n uid: card.c_uid\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 $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, 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, 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 */\n Component.prototype.$save = function() {\n var _this = this, options, path, component, date, dlp;\n\n component = this.$omit();\n dlp = Component.$Preferences.constructor.$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\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' ||\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.month.type) {\n // montly recurrence by month days or yearly by month\n delete component.repeat.days;\n }\n }\n else if (this.repeat.frequency) {\n component.repeat = { frequency: this.repeat.frequency };\n }\n if (this.repeat.frequency) {\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 if (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, 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 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, 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[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, this.alarm.unit, this.alarm.reference].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),\n l('reminder_' + this.alarm.reference)].join(' ');\n }\n\n return localizedString;\n };\n\n Component.prototype.toString = function() {\n return '[Component ' + this.id + ']';\n };\n\n\n})();\n"]}