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

1 line
79 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","Component","Acl","angular","extend","activeUser","$Component","$view","module","e","value","EventDragDayLength","EventDragHorizontalOffset","factory","$add","calendar","list","sibling","i","isWebCalendar","$webcalendars","isSubscription","$subscriptions","$calendars","_","find","o","localeCompare","indexOf","pluck","splice","$findAll","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","active","$getComponent","componentId","recurrenceId","$find","isError","isObject","futureComponentData","pid","newComponentData","newguid","isNew","Preferences","Gravatar","$Preferences","$gravatar","baseURL","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","$refreshTimeout","$ghost","ready","settings","EventsFilterState","TasksFilterState","EventsSortingState","parseInt","TasksSortingState","show_completed","ShowCompletedTasks","$categories","defaults","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', 'Component', 'Acl', function($q, $timeout, $log, Settings, Resource, 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 $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 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"]}