sogo/UI/WebServerResources/js/Scheduler.services.js.map
2015-12-15 08:37:55 -05:00

1 line
80 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","Gravatar","$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","categories","repeat","alarm","action","quantity","unit","reference","relation","status","delta","classification","isString","substring","setMinutes","Math","round","getMinutes","end","minutesTo","setDelta","dueDate","due","c_category","$isRecurrent","days","byDayMask","occurrence","frequency","byday","toString","interval","monthdays","months","until","asDate","$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","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","occurrenceOnly","$futureComponentData","formatTime","hours","minutes","formatDate","getYear","copy","startTime","endTime","dueTime","stringWithSeparator","organizer","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', 'Gravatar', 'Resource', function($q, $timeout, $log, Settings, Preferences, Gravatar, Resource) {\n angular.extend(Component, {\n $q: $q,\n $timeout: $timeout,\n $log: $log,\n $Preferences: Preferences,\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 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 = new Date(this.startDate.substring(0,10) + ' ' + this.startDate.substring(11,16));\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 = new Date(this.endDate.substring(0,10) + ' ' + this.endDate.substring(11,16));\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 = new Date(this.dueDate.substring(0,10) + ' ' + this.dueDate.substring(11,16));\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 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 = this.repeat.until.substring(0,10).asDate();\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 attendee, url, params;\n if (card) {\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 * @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(true);\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(true);\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 = [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('/'), this.$omit(), options)\n .then(function(data) {\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit(true);\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 = {}, date;\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 // 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 this.alarm.attendees = 0;\n this.alarm.organizer = 1;\n }\n }\n else {\n component.alarm = {};\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 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"]}