sogo/UI/WebServerResources/js/Scheduler.services.js.map
2015-08-25 11:46:14 -04:00

1 line
60 KiB
Plaintext

{"version":3,"file":"Scheduler.services.js","sources":["Scheduler/Calendar.service.js","Scheduler/Component.service.js"],"names":["Calendar","futureCalendarData","this","init","name","id","newCalendarData","$$resource","create","angular","extend","$acl","$$Acl","$factory","$q","$timeout","$log","Settings","Resource","Component","Acl","activeUser","$Component","module","e","factory","$add","calendar","list","sibling","i","isWebCalendar","$webcalendars","isSubscription","$subscriptions","$calendars","_","find","o","localeCompare","indexOf","pluck","splice","$findAll","data","_this","forEach","push","union","$get","$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","prototype","isOwned","isSuperUser","getClassName","base","isUndefined","$rename","$save","$delete","remove","status","$deleteComponents","components","calendars","component","isDefined","c_folder","c_name","uids","$events","difference","$tasks","save","$omit","$setActivation","active","$getComponent","componentId","recurrenceId","$find","value","key","futureComponentData","pid","newComponentData","newguid","$unwrap","isNew","Preferences","Gravatar","$Preferences","$gravatar","baseURL","timeFormat","$query","search","$queryEvents","sort","asc","filterpopup","$queryTasks","ready","settings","EventsFilterState","TasksFilterState","EventsSortingState","parseInt","TasksSortingState","show_completed","ShowCompletedTasks","$categories","defaults","SOGoCalendarCategoriesColors","SOGoTimeFormat","$selectedCount","count","filter","event","selected","length","$filter","type","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","deferred","toLowerCase","sd","getDayString","ed","blocks","reduce","events","objects","eventData","componentData","object","eventsFields","start","c_startdate","hour","getHourString","flatten","block","nbr","$blocks","fields","invoke","categories","repeat","alarm","action","quantity","unit","reference","relation","classification","substring","end","dueDate","due","$isRecurrent","days","byDayMask","occurrence","frequency","byday","toString","interval","monthdays","months","until","asDate","$hasCustomRepeat","hasCustomRepeat","units","M","H","D","W","match","exec","SOGoCalendarDefaultReminder","$hasAlarm","destinationCalendar","organizer","email","$image","freebusy","updateFreeBusyCoverage","attendees","attendee","image","updateFreeBusy","b","isReadOnly","isEditableOccurrence","isInvitation","userHasRSVP","isInvitationOccurrence","enablePercentComplete","coversFreeBusy","quarter","roundedStart","roundedEnd","startQuarter","getMinutes","endQuarter","setMinutes","daysUpTo","index","hourKey","currentDay","dayKey","getHours","beginOfDay","addMinutes","sday","eday","map","addAttendee","card","c_cn","$preferredEmail","role","c_uid","hasAttendee","emails","canRemindAttendeesByEmail","addAttachUrl","attachUrl","attachUrls","deleteAttachUrl","$reset","$shadowData","$reply","reply","delegatedTo","$futureComponentData","isError","error","formatTime","dateString","hours","minutes","copy","startTime","endTime","stringWithSeparator"],"mappings":"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","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 angular.extend(this, 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 });\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 .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 * @returns the list of calendars\n */\n Calendar.$findAll = function(data) {\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 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 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 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 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 };\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(name) {\n var i = _.indexOf(_.pluck(Calendar.$calendars, 'id'), this.id);\n this.name = name;\n Calendar.$calendars.splice(i, 1);\n Calendar.$add(this);\n return this.$save();\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 d = Calendar.$q.defer(),\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 promise.then(function() {\n var i = _.indexOf(_.pluck(list, 'id'), _this.id);\n list.splice(i, 1);\n d.resolve();\n }, function(data, status) {\n d.reject(data);\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 $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 return Calendar.$$resource.save(this.id, this.$omit()).then(function(data) {\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 $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 });\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(event) { return event.selected; })).length;\n }\n return count;\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 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 == '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' or 'week'\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,\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(data) {\n Component.$timeout(function() {\n var components = [], blocks = {};\n\n // Instantiate Component objects\n _.reduce(data.events, function(objects, eventData, i) {\n var componentData = _.object(data.eventsFields, eventData),\n start = new Date(componentData.c_startdate * 1000);\n componentData.hour = start.getHourString();\n objects.push(new Component(componentData));\n return objects;\n }, components);\n\n // Associate Component objects to blocks positions\n _.each(_.flatten(data.blocks), function(block) {\n block.component = components[block.nbr];\n });\n\n // Convert array of blocks to object with days as keys\n for (i = 0; i < data.blocks.length; i++) {\n blocks[startDate.getDayString()] = data.blocks[i];\n startDate.addDays(1);\n }\n\n Component.$log.debug('blocks ready (' + _.keys(blocks).length + ')');\n\n // Save the blocks to the object model\n Component.$blocks = blocks;\n\n deferred.resolve(blocks);\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\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 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.startDate)\n this.start = new Date(this.startDate.substring(0,10) + ' ' + this.startDate.substring(11,16));\n if (this.endDate)\n this.end = new Date(this.endDate.substring(0,10) + ' ' + this.endDate.substring(11,16));\n if (this.dueDate)\n this.due = new Date(this.dueDate.substring(0,10) + ' ' + this.dueDate.substring(11,16));\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.freebusy = this.updateFreeBusyCoverage();\n\n if (this.attendees) {\n _.each(this.attendees, function(attendee) {\n attendee.image = Component.$gravatar(attendee.email, 32);\n _this.updateFreeBusy(attendee);\n });\n }\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.component = 'vtodo' &&\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 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.updateFreeBusy = 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);\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.updateFreeBusy(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 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 $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 $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 $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' && key[0] != '$') {\n component[key] = angular.copy(value);\n }\n });\n\n // Format times\n component.startTime = component.startDate ? formatTime(component.startDate) : '';\n component.endTime = component.endDate ? formatTime(component.endDate) : '';\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(dateString) {\n // YYYY-MM-DDTHH:MM-ZZ:00 => YYYY-MM-DD HH:MM\n var date = new Date(dateString.substring(0,10) + ' ' + dateString.substring(11,16)),\n hours = date.getHours(),\n minutes = date.getMinutes();\n\n if (hours < 10) hours = '0' + hours;\n if (minutes < 10) minutes = '0' + minutes;\n\n return hours + ':' + minutes;\n }\n\n return component;\n };\n\n})();\n"]}