sogo/UI/WebServerResources/js/Scheduler.services.js.map
2016-01-04 15:59:01 -05:00

1 line
83 KiB
Plaintext

{"version":3,"sources":["Scheduler/Calendar.service.js","Scheduler/Component.service.js"],"names":["Calendar","futureCalendarData","this","init","name","id","newCalendarData","$$resource","create","$unwrap","$acl","$$Acl","$factory","$q","$timeout","$log","Settings","Resource","Preferences","Component","Acl","angular","extend","activeUser","$Preferences","$Component","$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","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","formatTime","hours","minutes","formatDate","getYear","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 if (this.id) {\n this.$acl = new Calendar.$$Acl('Calendar/' + this.id);\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 // 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;\n\n component = this.$omit();\n\n // Format dates and times\n component.startDate = component.start ? formatDate(component.start) : '';\n component.startTime = component.start ? formatTime(component.start) : '';\n component.endDate = component.end ? formatDate(component.end) : '';\n component.endTime = component.end ? formatTime(component.end) : '';\n component.dueDate = component.due ? formatDate(component.due) : '';\n component.dueTime = component.due ? formatTime(component.due) : '';\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 function formatTime(date) {\n var hours = date.getHours();\n if (hours < 10) hours = '0' + hours;\n\n var minutes = date.getMinutes();\n if (minutes < 10) minutes = '0' + minutes;\n return hours + ':' + minutes;\n }\n\n function formatDate(date) {\n var year = date.getYear();\n if (year < 1000) year += 1900;\n\n var month = '' + (date.getMonth() + 1);\n if (month.length == 1)\n month = '0' + month;\n\n var day = '' + date.getDate();\n if (day.length == 1)\n day = '0' + day;\n\n return year + '-' + month + '-' + day;\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"]}