1 line
69 KiB
Plaintext
1 line
69 KiB
Plaintext
{"version":3,"sources":["Contacts/AddressBook.service.js","Contacts/Card.service.js"],"names":["AddressBook","futureAddressBookData","then","this","init","name","id","newAddressBookData","$$resource","create","$unwrap","acls","objectEditor","objectCreator","objectEraser","$acl","$$Acl","$factory","$q","$timeout","$log","Settings","AddressBook_PRELOAD","Resource","Card","Acl","Preferences","angular","extend","PRELOAD","activeUser","$Card","$Preferences","$query","search","value","sort","asc","selectedFolder","$refreshTimeout","ready","settings","Contact","SortingState","parseInt","module","e","constant","LOOKAHEAD","SIZE","factory","$filterAll","options","excludedCards","params","isUndefined","$cards","fetch","response","results","card","index","compareIds","data","_","filter","contacts","find","bind","length","splice","forEach","mapKeys","key","toLowerCase","debug","when","$add","addressbook","list","sibling","i","isSubscription","$subscriptions","$addressbooks","o","localeCompare","indexOf","map","$findAll","_this","$remotes","isRemote","push","union","$subscribe","uid","path","userResource","addressbookData","prototype","$$cards","idsMap","isOwned","isSuperUser","owner","login","$id","$futureAddressBookData","getLength","getItemAtIndex","$isLoading","$lastVisibleIndex","Math","max","$loadCard","endIndex","ids","futureHeadersData","cardId","startIndex","loaded","isDefined","$loaded","STATUS","NOT_LOADED","min","LOADED","LOADING","join","post","$unwrapHeaders","hasSelectedCard","selectedCard","isSelectedCard","$selectedCard","$selectedCardIndex","$selectedCards","selected","$selectedCount","count","$startRefreshTimeout","cancel","refreshViewCheck","defaults","SOGoRefreshViewCheck","f","$reload","timeInterval","$filter","query","dry","copy","partial","addressbookId","futureData","fields","idFieldIndex","cards","headers","invokeMap","pid","oldIndex","removedCards","findIndex","zipObject","$rename","$save","$delete","promise","d","defer","remove","resolve","reject","$_deleteCards","forEachRight","selectedIndex","$deleteCards","uids","$copyCards","folder","$moveCards","save","$omit","exportCards","selectedOnly","selectedUIDs","selectedCards","download","type","$topIndex","reduce","isError","isObject","j","cardHeaders","futureCardData","newCardData","newguid","isNew","$TEL_TYPES","$EMAIL_TYPES","$URL_TYPES","$ADDRESS_TYPES","Card_STATUS","SOGoContactsCategories","$categories","SOGoAlternateAvatar","$alternateAvatar","DELAYED_LOADING","DELAYED_MS","$find","$unwrapCollection","filterCategories","re","RegExp","category","collection","$futureCardData","refs","categories","c_screenname","$$fullname","$fullname","$$email","$preferredEmail","$$image","image","avatar","no_404","url","isgroup","c_component","notes","note","email","emails","reference","birthday","dlp","$mdDateLocaleProvider","parseDate","$birthday","formatDate","c_name","empty","action","ref","$shadowData","attribute","selectedIDs","names","fn","c_cn","html","c_givenname","nickname","c_sn","c_org","$description","description","title","role","orgUnits","unit","test","c_mail","$shortFormat","fullname","$isCard","$isList","condition","expandable","$addOrgUnit","orgUnit","$addEmail","$addScreenName","screenName","$addPhone","phones","$addUrl","urls","$addAddress","postoffice","street","street2","locality","region","country","postalcode","addresses","$addMember","explode","$reset","deep","format","toString","desc"],"mappings":"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","file":"Contacts.services.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name AddressBook\n * @constructor\n * @param {object} futureAddressBookData - either an object literal or a promise\n */\n function AddressBook(futureAddressBookData) {\n // Data is immediately available\n if (typeof futureAddressBookData.then !== 'function') {\n this.init(futureAddressBookData);\n if (this.name && !this.id) {\n // Create a new addressbook on the server\n var newAddressBookData = AddressBook.$$resource.create('createFolder', this.name);\n this.$unwrap(newAddressBookData);\n this.acls = {'objectEditor': 1, 'objectCreator': 1, 'objectEraser': 1};\n }\n else if (this.id) {\n this.$acl = new AddressBook.$$Acl('Contacts/' + this.id);\n }\n }\n else {\n // The promise will be unwrapped first\n this.$unwrap(futureAddressBookData);\n }\n }\n\n /**\n * @memberof AddressBook\n * @desc The factory we'll use to register with Angular\n * @returns the AddressBook constructor\n */\n AddressBook.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgAddressBook_PRELOAD', 'Resource', 'Card', 'Acl', 'Preferences', function($q, $timeout, $log, Settings, AddressBook_PRELOAD, Resource, Card, Acl, Preferences) {\n angular.extend(AddressBook, {\n $q: $q,\n $timeout: $timeout,\n $log: $log,\n PRELOAD: AddressBook_PRELOAD,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $Card: Card,\n $$Acl: Acl,\n $Preferences: Preferences,\n $query: {search: 'name_or_address', value: '', sort: 'c_cn', asc: 1},\n activeUser: Settings.activeUser(),\n selectedFolder: null,\n $refreshTimeout: null\n });\n // Initialize sort parameters from user's settings\n Preferences.ready().then(function() {\n if (Preferences.settings.Contact.SortingState) {\n AddressBook.$query.sort = Preferences.settings.Contact.SortingState[0];\n AddressBook.$query.asc = parseInt(Preferences.settings.Contact.SortingState[1]);\n }\n });\n return AddressBook; // return constructor\n }];\n\n /**\n * @module SOGo.ContactsUI\n * @desc Factory registration of AddressBook in Angular module.\n */\n try {\n angular.module('SOGo.ContactsUI');\n }\n catch(e) {\n angular.module('SOGo.ContactsUI', ['SOGo.Common', 'SOGo.PreferencesUI']);\n }\n angular.module('SOGo.ContactsUI')\n .constant('sgAddressBook_PRELOAD', {\n LOOKAHEAD: 50,\n SIZE: 100\n })\n .factory('AddressBook', AddressBook.$factory);\n\n /**\n * @memberof AddressBook\n * @desc Search for cards among all addressbooks matching some criterias.\n * @param {string} search - the search string to match\n * @param {object} [options] - additional options to the query (excludeGroups and excludeLists)\n * @param {object[]} excludedCards - a list of Card objects that must be excluded from the results\n * @returns a collection of Cards instances\n */\n AddressBook.$filterAll = function(search, options, excludedCards) {\n var params = { search: search };\n\n if (!search) {\n // No query specified\n AddressBook.$cards = [];\n return AddressBook.$q.when(AddressBook.$cards);\n }\n if (angular.isUndefined(AddressBook.$cards)) {\n // First session query\n AddressBook.$cards = [];\n }\n\n angular.extend(params, options);\n\n return AddressBook.$$resource.fetch(null, 'allContactSearch', params).then(function(response) {\n var results, card, index,\n compareIds = function(data) {\n return this.id == data.id;\n };\n if (excludedCards) {\n // Remove excluded cards from results\n results = _.filter(response.contacts, function(data) {\n return _.isUndefined(_.find(excludedCards, _.bind(compareIds, data)));\n });\n }\n else {\n results = response.contacts;\n }\n // Remove cards that no longer match the search query\n for (index = AddressBook.$cards.length - 1; index >= 0; index--) {\n card = AddressBook.$cards[index];\n if (_.isUndefined(_.find(results, _.bind(compareIds, card)))) {\n AddressBook.$cards.splice(index, 1);\n }\n }\n // Add new cards matching the search query\n _.forEach(results, function(data, index) {\n if (_.isUndefined(_.find(AddressBook.$cards, _.bind(compareIds, data)))) {\n var card = new AddressBook.$Card(_.mapKeys(data, function(value, key) {\n return key.toLowerCase();\n }), search);\n AddressBook.$cards.splice(index, 0, card);\n }\n });\n AddressBook.$log.debug(AddressBook.$cards);\n return AddressBook.$cards;\n });\n };\n\n /**\n * @memberof AddressBook\n * @desc Add a new addressbook to the static list of addressbooks\n * @param {AddressBook} addressbook - an Addressbook object instance\n */\n AddressBook.$add = function(addressbook) {\n // Insert new addressbook at proper index\n var list, sibling, i;\n\n list = addressbook.isSubscription? this.$subscriptions : this.$addressbooks;\n sibling = _.find(list, function(o) {\n return (addressbook.id == 'personal' ||\n (o.id != 'personal' &&\n o.name.localeCompare(addressbook.name) === 1));\n });\n i = sibling ? _.indexOf(_.map(list, 'id'), sibling.id) : 1;\n list.splice(i, 0, addressbook);\n };\n\n /**\n * @memberof AddressBook\n * @desc Set or get the list of addressbooks. Will instantiate a new AddressBook object for each item.\n * @param {array} [data] - the metadata of the addressbooks\n * @returns the list of addressbooks\n */\n AddressBook.$findAll = function(data) {\n var _this = this;\n if (data) {\n this.$addressbooks = [];\n this.$subscriptions = [];\n this.$remotes = [];\n // Instanciate AddressBook objects\n angular.forEach(data, function(o, i) {\n var addressbook = new AddressBook(o);\n if (addressbook.isRemote)\n _this.$remotes.push(addressbook);\n else if (addressbook.isSubscription)\n _this.$subscriptions.push(addressbook);\n else\n _this.$addressbooks.push(addressbook);\n });\n }\n return _.union(this.$addressbooks, this.$subscriptions, this.$remotes);\n };\n\n /**\n * @memberOf AddressBook\n * @desc Subscribe to another user's addressbook and add it to the list of addressbooks.\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 AddressBook.$subscribe = function(uid, path) {\n var _this = this;\n return AddressBook.$$resource.userResource(uid).fetch(path, 'subscribe').then(function(addressbookData) {\n var addressbook = new AddressBook(addressbookData);\n if (_.isUndefined(_.find(_this.$subscriptions, function(o) {\n return o.id == addressbookData.id;\n }))) {\n // Not already subscribed\n AddressBook.$add(addressbook);\n }\n return addressbook;\n });\n };\n\n /**\n * @function init\n * @memberof AddressBook.prototype\n * @desc Extend instance with new data and compute additional attributes.\n * @param {object} data - attributes of addressbook\n */\n AddressBook.prototype.init = function(data, options) {\n var _this = this;\n if (!this.$$cards) {\n // Array of cards for \"dry\" searches (see $filter)\n this.$$cards = [];\n }\n this.idsMap = {};\n this.$cards = [];\n // Extend instance with all attributes of data except headers\n angular.forEach(data, function(value, key) {\n if (key != 'headers' && key != 'cards') {\n _this[key] = value;\n }\n });\n // Add 'isOwned' and 'isSubscription' attributes based on active user (TODO: add it server-side?)\n this.isOwned = AddressBook.activeUser.isSuperUser || this.owner == AddressBook.activeUser.login;\n this.isSubscription = !this.isRemote && this.owner != AddressBook.activeUser.login;\n };\n\n /**\n * @function $id\n * @memberof AddressBook.prototype\n * @desc Resolve the addressbook id.\n * @returns a promise of the addressbook id\n */\n AddressBook.prototype.$id = function() {\n if (this.id) {\n // Object already unwrapped\n return AddressBook.$q.when(this.id);\n }\n else {\n // Wait until object is unwrapped\n return this.$futureAddressBookData.then(function(addressbook) {\n return addressbook.id;\n });\n }\n };\n\n /**\n * @function getLength\n * @memberof AddressBook.prototype\n * @desc Used by md-virtual-repeat / md-on-demand\n * @returns the number of cards in the addressbook\n */\n AddressBook.prototype.getLength = function() {\n return this.$cards.length;\n };\n\n /**\n * @function getItemAtIndex\n * @memberof AddressBook.prototype\n * @desc Used by md-virtual-repeat / md-on-demand\n * @returns the card at the specified index\n */\n AddressBook.prototype.getItemAtIndex = function(index) {\n var card;\n\n if (!this.$isLoading && index >= 0 && index < this.$cards.length) {\n card = this.$cards[index];\n this.$lastVisibleIndex = Math.max(0, index - 3); // Magic number is NUM_EXTRA from virtual-repeater.js\n\n if (this.$loadCard(card))\n return card;\n }\n return null;\n };\n\n /**\n * @function $loadCard\n * @memberof AddressBook.prototype\n * @desc Check if the card is loaded and in any case, fetch more cards headers from the server.\n * @returns true if the card metadata are already fetched\n */\n AddressBook.prototype.$loadCard = function(card) {\n var cardId = card.id,\n startIndex = this.idsMap[cardId],\n endIndex,\n index,\n max = this.$cards.length,\n loaded = false,\n ids,\n futureHeadersData;\n\n if (angular.isUndefined(this.ids) && card.id) {\n loaded = true;\n }\n else if (angular.isDefined(startIndex) && startIndex < this.$cards.length) {\n // Index is valid\n if (card.$loaded != AddressBook.$Card.STATUS.NOT_LOADED) {\n // Card headers are loaded or data is coming\n loaded = true;\n }\n\n // Preload more headers if possible\n endIndex = Math.min(startIndex + AddressBook.PRELOAD.LOOKAHEAD, max - 1);\n if (this.$cards[endIndex].$loaded != AddressBook.$Card.STATUS.NOT_LOADED) {\n index = Math.max(startIndex - AddressBook.PRELOAD.LOOKAHEAD, 0);\n if (this.$cards[index].$loaded != AddressBook.$Card.STATUS.LOADED) {\n // Previous cards not loaded; preload more headers further up\n endIndex = startIndex;\n startIndex = Math.max(startIndex - AddressBook.PRELOAD.SIZE, 0);\n }\n }\n else\n // Next cards not load; preload more headers further down\n endIndex = Math.min(startIndex + AddressBook.PRELOAD.SIZE, max - 1);\n\n if (this.$cards[startIndex].$loaded == AddressBook.$Card.STATUS.NOT_LOADED ||\n this.$cards[endIndex].$loaded == AddressBook.$Card.STATUS.NOT_LOADED) {\n\n for (ids = []; startIndex < endIndex && startIndex < max; startIndex++) {\n if (this.$cards[startIndex].$loaded != AddressBook.$Card.STATUS.NOT_LOADED) {\n // Card at this index is already loaded; increase the end index\n endIndex++;\n }\n else {\n // Card at this index will be loaded\n ids.push(this.$cards[startIndex].id);\n this.$cards[startIndex].$loaded = AddressBook.$Card.STATUS.LOADING;\n }\n }\n\n AddressBook.$log.debug('Loading Ids ' + ids.join(' ') + ' (' + ids.length + ' cards)');\n if (ids.length > 0) {\n futureHeadersData = AddressBook.$$resource.post(this.id, 'headers', {ids: ids});\n this.$unwrapHeaders(futureHeadersData);\n }\n }\n }\n return loaded;\n };\n\n /**\n * @function hasSelectedMessage\n * @memberof AddressBook.prototype\n * @desc Check if a card is selected.\n * @returns true if the a card is selected\n */\n AddressBook.prototype.hasSelectedCard = function() {\n return angular.isDefined(this.selectedCard);\n };\n\n /**\n * @function isSelectedCard\n * @memberof AddressBook.prototype\n * @desc Check if the specified card is selected.\n * @param {string} CardId\n * @returns true if the specified card is selected\n */\n AddressBook.prototype.isSelectedCard = function(cardId) {\n return this.hasSelectedCard() && this.selectedCard == cardId;\n };\n\n /**\n * @function $selectedCard\n * @memberof AddressBook.prototype\n * @desc Return the currently visible card.\n * @returns a Card instance or undefined if no card is displayed\n */\n AddressBook.prototype.$selectedCard = function() {\n var _this = this;\n\n return _.find(this.$cards, function(card) { return card.id == _this.selectedCard; });\n };\n\n /**\n * @function $selectedCardIndex\n * @memberof AddressBook.prototype\n * @desc Return the index of the currently visible card.\n * @returns a number or undefined if no card is selected\n */\n AddressBook.prototype.$selectedCardIndex = function() {\n return _.indexOf(_.map(this.$cards, 'id'), this.selectedCard);\n };\n\n /**\n * @function $selectedCards\n * @memberof AddressBook.prototype\n * @desc Return the cards selected by the user.\n * @returns Card instances\n */\n AddressBook.prototype.$selectedCards = function() {\n return _.filter(this.$cards, function(card) { return card.selected; });\n };\n\n /**\n * @function $selectedCount\n * @memberof AddressBook.prototype\n * @desc Return the number of cards selected by the user.\n * @returns the number of selected cards\n */\n AddressBook.prototype.$selectedCount = function() {\n var count;\n\n count = 0;\n if (this.$cards) {\n count = (_.filter(this.$cards, function(card) { return card.selected; })).length;\n }\n return count;\n };\n\n /**\n * @function $startRefreshTimeout\n * @memberof AddressBook.prototype\n * @desc Starts the refresh timeout for the current selected address book\n */\n AddressBook.prototype.$startRefreshTimeout = function() {\n var _this = this;\n\n if (AddressBook.$refreshTimeout)\n AddressBook.$timeout.cancel(AddressBook.$refreshTimeout);\n\n AddressBook.$Preferences.ready().then(function() {\n // Restart the refresh timer, if needed\n var refreshViewCheck = AddressBook.$Preferences.defaults.SOGoRefreshViewCheck;\n if (refreshViewCheck && refreshViewCheck != 'manually') {\n var f = angular.bind(_this, AddressBook.prototype.$reload);\n AddressBook.$refreshTimeout = AddressBook.$timeout(f, refreshViewCheck.timeInterval()*1000);\n }\n });\n };\n\n /**\n * @function $reload\n * @memberof AddressBook.prototype\n * @desc Reload list of cards\n * @returns a promise of the Cards instances\n */\n AddressBook.prototype.$reload = function() {\n var _this = this;\n\n this.$startRefreshTimeout();\n return this.$filter();\n };\n\n /**\n * @function $filter\n * @memberof AddressBook.prototype\n * @desc Search for cards matching some criterias\n * @param {string} search - the search string to match\n * @param {object} [options] - additional options to the query (dry, excludeList)\n * @returns a collection of Cards instances\n */\n AddressBook.prototype.$filter = function(search, options, excludedCards) {\n var _this = this, query,\n dry = options && options.dry;\n\n if (dry) {\n // Don't keep a copy of the query in dry mode\n query = angular.copy(AddressBook.$query);\n }\n else {\n this.$isLoading = true;\n query = AddressBook.$query;\n if (!this.isRemote) query.partial = 1;\n }\n\n return AddressBook.$Preferences.ready().then(function() {\n if (options) {\n angular.extend(query, options);\n if (dry) {\n if (!search) {\n // No query specified\n _this.$$cards = [];\n return AddressBook.$q.when(_this.$$cards);\n }\n }\n }\n\n if (angular.isDefined(search))\n query.value = search;\n\n return _this.$id().then(function(addressbookId) {\n var futureData = AddressBook.$$resource.fetch(addressbookId, 'view', query);\n\n if (dry) {\n return futureData.then(function(response) {\n var results, headers, card, index, fields, idFieldIndex,\n cards = _this.$$cards,\n compareIds = function(card) {\n return this == card.id;\n };\n\n if (response.headers) {\n // First entry of 'headers' are keys\n fields = _.invokeMap(response.headers[0], 'toLowerCase');\n idFieldIndex = fields.indexOf('id');\n response.headers.splice(0, 1);\n }\n\n if (excludedCards)\n // Remove excluded cards from results\n results = _.filter(response.ids, function(id) {\n return _.isUndefined(_.find(excludedCards, _.bind(compareIds, id)));\n });\n else\n results = response.ids;\n\n // Remove cards that no longer match the search query\n for (index = cards.length - 1; index >= 0; index--) {\n card = cards[index];\n if (_.isUndefined(_.find(results, _.bind(compareIds, card.id)))) {\n cards.splice(index, 1);\n }\n }\n\n // Add new cards matching the search query\n _.forEach(results, function(cardId, index) {\n if (_.isUndefined(_.find(cards, _.bind(compareIds, cardId)))) {\n var data = { pid: addressbookId, id: cardId };\n var card = new AddressBook.$Card(data, search);\n cards.splice(index, 0, card);\n }\n });\n\n // Respect the order of the results\n _.forEach(results, function(cardId, index) {\n var oldIndex, removedCards;\n if (cards[index].id != cardId) {\n oldIndex = _.findIndex(cards, _.bind(compareIds, cardId));\n removedCards = cards.splice(oldIndex, 1);\n cards.splice(index, 0, removedCards[0]);\n }\n });\n\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var card, index = _.findIndex(cards, _.bind(compareIds, data[idFieldIndex]));\n if (index > -1) {\n card = _.zipObject(fields, data);\n cards[index].init(card, search);\n }\n });\n\n return cards;\n });\n }\n else {\n // Unwrap promise and instantiate or extend Cards objets\n return _this.$unwrap(futureData);\n }\n });\n });\n };\n\n /**\n * @function $rename\n * @memberof AddressBook.prototype\n * @desc Rename the addressbook and keep the list sorted\n * @param {string} name - the new name\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$rename = function(name) {\n var i = _.indexOf(_.map(AddressBook.$addressbooks, 'id'), this.id);\n this.name = name;\n AddressBook.$addressbooks.splice(i, 1);\n AddressBook.$add(this);\n return this.$save();\n };\n\n /**\n * @function $delete\n * @memberof AddressBook.prototype\n * @desc Delete the addressbook from the server and the static list of addressbooks.\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$delete = function() {\n var _this = this,\n d = AddressBook.$q.defer(),\n list,\n promise;\n\n if (this.isSubscription) {\n promise = AddressBook.$$resource.fetch(this.id, 'unsubscribe');\n list = AddressBook.$subscriptions;\n }\n else {\n promise = AddressBook.$$resource.remove(this.id);\n list = AddressBook.$addressbooks;\n }\n\n promise.then(function() {\n var i = _.indexOf(_.map(list, 'id'), _this.id);\n list.splice(i, 1);\n d.resolve();\n }, d.reject);\n return d.promise;\n };\n\n /**\n * @function $_deleteCards\n * @memberof AddressBook.prototype\n * @desc Delete multiple cards from AddressBook object.\n * @param {string[]} ids - the cards ids\n */\n AddressBook.prototype.$_deleteCards = function(ids) {\n var _this = this;\n\n // Remove cards from $cards and idsMap\n _.forEachRight(this.$cards, function(card, index) {\n var selectedIndex = _.findIndex(ids, function(id) {\n return card.id == id;\n });\n if (selectedIndex > -1) {\n ids.splice(selectedIndex, 1);\n delete _this.idsMap[card.id];\n if (_this.isSelectedCard(card.id))\n delete _this.selectedCard;\n _this.$cards.splice(index, 1);\n }\n else {\n _this.idsMap[card.id] -= ids.length;\n }\n });\n };\n\n /**\n * @function $deleteCards\n * @memberof AddressBook.prototype\n * @desc Delete multiple cards from addressbook.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$deleteCards = function(cards) {\n var _this = this,\n ids = _.map(cards, 'id');\n \n return AddressBook.$$resource.post(this.id, 'batchDelete', {uids: ids}).then(function() {\n _this.$_deleteCards(ids);\n });\n };\n\n /**\n * @function $copyCards\n * @memberof AddressBook.prototype\n * @desc Copy multiple cards from addressbook to an other one.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$copyCards = function(cards, folder) {\n var uids = _.map(cards, 'id');\n return AddressBook.$$resource.post(this.id, 'copy', {uids: uids, folder: folder});\n };\n\n /**\n * @function $moveCards\n * @memberof AddressBook.prototype\n * @desc Move multiple cards from the current addressbook to a target one\n * @param {object[]} cards - instances of Card object\n * @param {string} folder - the destination folder id\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$moveCards = function(cards, folder) {\n var _this = this, uids;\n\n uids = _.map(cards, 'id');\n return AddressBook.$$resource.post(this.id, 'move', {uids: uids, folder: folder})\n .then(function() {\n return _this.$_deleteCards(uids);\n });\n };\n\n /**\n * @function $save\n * @memberof AddressBook.prototype\n * @desc Save the addressbook to the server. This currently can only affect the name of the addressbook.\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$save = function() {\n return AddressBook.$$resource.save(this.id, this.$omit()).then(function(data) {\n return data;\n });\n };\n\n /**\n * @function $exportCards\n * @memberof AddressBook.prototype\n * @desc Export the selected/all cards\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.exportCards = function(selectedOnly) {\n var selectedUIDs;\n\n if (selectedOnly) {\n var selectedCards = _.filter(this.$cards, function(card) { return card.selected; });\n selectedUIDs = _.map(selectedCards, 'id');\n }\n\n return AddressBook.$$resource.download(this.id, 'export', (angular.isDefined(selectedUIDs) ? {uids: selectedUIDs} : null), {type: 'application/octet-stream'});\n };\n\n /**\n * @function $unwrap\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and instanciate new Card objects using received data.\n * @param {promise} futureAddressBookData - a promise of the AddressBook's data\n */\n AddressBook.prototype.$unwrap = function(futureAddressBookData) {\n var _this = this;\n\n this.$isLoading = true;\n\n // Expose and resolve the promise\n this.$futureAddressBookData = futureAddressBookData.then(function(response) {\n return AddressBook.$timeout(function() {\n var headers;\n\n if (!response.ids || _this.$topIndex > response.ids.length - 1)\n _this.$topIndex = 0;\n\n // Extend AddressBook instance from data of addressbooks list.\n // Will inherit attributes such as isEditable and isRemote.\n angular.forEach(AddressBook.$findAll(), function(o, i) {\n if (o.id == response.id) {\n angular.extend(_this, o);\n }\n });\n\n // Extend AddressBook instance with received data\n _this.init(response);\n\n if (_this.ids) {\n AddressBook.$log.debug('unwrapping ' + _this.ids.length + ' cards');\n\n // Instanciate Card objects\n _.reduce(_this.ids, function(cards, card, i) {\n var data = { pid: _this.id, id: card };\n\n // Build map of ID <=> index\n _this.idsMap[data.id] = i;\n\n cards.push(new AddressBook.$Card(data));\n\n return cards;\n }, _this.$cards);\n }\n\n if (response.headers) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(response.headers[0], 'toLowerCase');\n response.headers.splice(0, 1);\n\n if (_this.ids) {\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data),\n i = _this.idsMap[o.id];\n _this.$cards[i].init(o);\n });\n }\n else {\n // Instanciate Card objects\n _this.$cards = [];\n angular.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data);\n angular.extend(o, { pid: _this.id });\n _this.$cards.push(new AddressBook.$Card(o));\n });\n }\n }\n\n // Instanciate Acl object\n _this.$acl = new AddressBook.$$Acl('Contacts/' + _this.id);\n\n _this.$startRefreshTimeout();\n\n _this.$isLoading = false;\n\n AddressBook.$log.debug('addressbook ' + _this.id + ' ready');\n\n return _this;\n });\n }, function(data) {\n _this.isError = true;\n if (angular.isObject(data)) {\n AddressBook.$timeout(function() {\n angular.extend(_this, data);\n });\n }\n });\n };\n\n /**\n * @function $unwrapHeaders\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and extend matching Card objects with received data.\n * @param {promise} futureHeadersData - a promise of the metadata of some cards\n */\n AddressBook.prototype.$unwrapHeaders = function(futureHeadersData) {\n var _this = this;\n\n futureHeadersData.then(function(data) {\n AddressBook.$timeout(function() {\n var headers, j;\n if (data.length > 0) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(data[0], 'toLowerCase');\n data.splice(0, 1);\n _.forEach(data, function(cardHeaders) {\n cardHeaders = _.zipObject(headers, cardHeaders);\n j = _this.idsMap[cardHeaders.id];\n if (angular.isDefined(j)) {\n _this.$cards[j].init(cardHeaders);\n }\n });\n }\n });\n });\n };\n\n /**\n * @function $omit\n * @memberof AddressBook.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the Addressbook instance\n */\n AddressBook.prototype.$omit = function() {\n var addressbook = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' &&\n key != 'ids' &&\n key[0] != '$') {\n addressbook[key] = value;\n }\n });\n return addressbook;\n };\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Card\n * @constructor\n * @param {object} futureCardData\n * @param {string} [partial]\n */\n function Card(futureCardData, partial) {\n\n // Data is immediately available\n if (typeof futureCardData.then !== 'function') {\n this.init(futureCardData, partial);\n if (this.pid && !this.id) {\n // Prepare for the creation of a new card;\n // Get UID from the server.\n var newCardData = Card.$$resource.newguid(this.pid);\n this.$unwrap(newCardData);\n this.isNew = true;\n }\n }\n else {\n // The promise will be unwrapped first\n this.$unwrap(futureCardData);\n }\n }\n\n Card.$TEL_TYPES = ['work', 'home', 'cell', 'fax', 'pager'];\n Card.$EMAIL_TYPES = ['work', 'home', 'pref'];\n Card.$URL_TYPES = ['work', 'home', 'pref'];\n Card.$ADDRESS_TYPES = ['work', 'home'];\n\n /**\n * @memberof Card\n * @desc The factory we'll use to register with Angular.\n * @returns the Card constructor\n */\n Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($timeout, Settings, Card_STATUS, Resource, Preferences) {\n angular.extend(Card, {\n STATUS: Card_STATUS,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $timeout: $timeout,\n $Preferences: Preferences\n });\n // Initialize categories from user's defaults\n Preferences.ready().then(function() {\n if (Preferences.defaults.SOGoContactsCategories) {\n Card.$categories = Preferences.defaults.SOGoContactsCategories;\n }\n if (Preferences.defaults.SOGoAlternateAvatar)\n Card.$alternateAvatar = Preferences.defaults.SOGoAlternateAvatar;\n });\n\n return Card; // return constructor\n }];\n\n /**\n * @module SOGo.ContactsUI\n * @desc Factory registration of Card in Angular module.\n */\n try {\n angular.module('SOGo.ContactsUI');\n }\n catch(e) {\n angular.module('SOGo.ContactsUI', ['SOGo.Common', 'SOGo.PreferencesUI']);\n }\n angular.module('SOGo.ContactsUI')\n .constant('sgCard_STATUS', {\n NOT_LOADED: 0,\n DELAYED_LOADING: 1,\n LOADING: 2,\n LOADED: 3,\n DELAYED_MS: 300\n })\n .factory('Card', Card.$factory);\n\n /**\n * @memberof Card\n * @desc Fetch a card from a specific addressbook.\n * @param {string} addressbookId - the addressbook ID\n * @param {string} cardId - the card ID\n * @see {@link AddressBook.$getCard}\n */\n Card.$find = function(addressbookId, cardId) {\n var futureCardData = this.$$resource.fetch([addressbookId, cardId].join('/'), 'view');\n\n if (cardId) return new Card(futureCardData); // a single card\n\n return Card.$unwrapCollection(futureCardData); // a collection of cards\n };\n\n /**\n * @function filterCategories\n * @memberof Card.prototype\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 Card.filterCategories = function(query) {\n var re = new RegExp(query, 'i');\n return _.map(_.filter(Card.$categories, function(category) {\n return category.search(re) != -1;\n }), function(category) {\n return { value: category };\n });\n };\n\n /**\n * @memberof Card\n * @desc Unwrap to a collection of Card instances.\n * @param {object} futureCardData\n */\n Card.$unwrapCollection = function(futureCardData) {\n var collection = {};\n\n collection.$futureCardData = futureCardData;\n\n futureCardData.then(function(cards) {\n Card.$timeout(function() {\n angular.forEach(cards, function(data, index) {\n collection[data.id] = new Card(data);\n });\n });\n });\n\n return collection;\n };\n\n /**\n * @function init\n * @memberof Card.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of card\n */\n Card.prototype.init = function(data, partial) {\n var _this = this;\n\n this.refs = [];\n this.categories = [];\n this.c_screenname = null;\n angular.extend(this, data);\n if (!this.$$fullname)\n this.$$fullname = this.$fullname();\n if (!this.$$email)\n this.$$email = this.$preferredEmail(partial);\n if (!this.$$image)\n this.$$image = this.image;\n if (!this.$$image)\n Card.$Preferences.avatar(this.$$email, 32, {no_404: true}).then(function(url) {\n _this.$$image = url;\n });\n if (this.isgroup)\n this.c_component = 'vlist';\n if (data.notes && data.notes.length)\n this.notes = _.map(data.notes, function(note) { return { 'value': note }; });\n else if (!this.notes)\n this.notes = [ { value: '' } ];\n // Instanciate Card objects for list members\n angular.forEach(this.refs, function(o, i) {\n if (o.email) o.emails = [{value: o.email}];\n o.id = o.reference;\n _this.refs[i] = new Card(o);\n });\n // Instanciate date object of birthday\n if (this.birthday) {\n Card.$Preferences.ready().then(function() {\n var dlp = Card.$Preferences.$mdDateLocaleProvider;\n _this.birthday = _this.birthday.parseDate(dlp, '%Y-%m-%d');\n _this.$birthday = dlp.formatDate(_this.birthday);\n });\n }\n\n this.$loaded = angular.isDefined(this.c_name)? Card.STATUS.LOADED : Card.STATUS.NOT_LOADED;\n\n // An empty attribute to trick md-autocomplete when adding attendees from the appointment editor\n this.empty = ' ';\n };\n\n /**\n * @function $id\n * @memberof Card.prototype\n * @desc Return the card ID.\n * @returns the card ID\n */\n Card.prototype.$id = function() {\n return this.$futureCardData.then(function(data) {\n return data.id;\n });\n };\n\n /**\n * @function $isLoading\n * @memberof Card.prototype\n * @returns true if the Card definition is still being retrieved from server after a specific delay\n * @see sgCard_STATUS\n */\n Card.prototype.$isLoading = function() {\n return this.$loaded == Card.STATUS.LOADING;\n };\n\n /**\n * @function $reload\n * @memberof Message.prototype\n * @desc Fetch the viewable message body along with other metadata such as the list of attachments.\n * @returns a promise of the HTTP operation\n */\n Card.prototype.$reload = function() {\n var futureCardData;\n\n if (this.$futureCardData)\n return this;\n\n futureCardData = Card.$$resource.fetch([this.pid, this.id].join('/'), 'view');\n\n return this.$unwrap(futureCardData);\n };\n\n /**\n * @function $save\n * @memberof Card.prototype\n * @desc Save the card to the server.\n */\n Card.prototype.$save = function() {\n var _this = this,\n action = 'saveAsContact';\n\n if (this.c_component == 'vlist') {\n action = 'saveAsList';\n _.forEach(this.refs, function(ref) {\n ref.reference = ref.id;\n });\n }\n\n return Card.$$resource.save([this.pid, this.id || '_new_'].join('/'),\n this.$omit(),\n { action: action })\n .then(function(data) {\n // Format birthdate\n if (_this.birthday)\n _this.$birthday = Card.$Preferences.$mdDateLocaleProvider.formatDate(_this.birthday);\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit(true);\n return data;\n });\n };\n\n Card.prototype.$delete = function(attribute, index) {\n if (attribute) {\n if (index > -1 && this[attribute].length > index) {\n this[attribute].splice(index, 1);\n }\n else\n delete this[attribute];\n }\n else {\n // No arguments -- delete card\n return Card.$$resource.remove([this.pid, this.id].join('/'));\n }\n };\n\n /**\n * @function export\n * @memberof Card.prototype\n * @desc Download the current card\n * @returns a promise of the HTTP operation\n */\n Card.prototype.export = function() {\n var selectedIDs;\n\n selectedIDs = [ this.id ];\n\n return Card.$$resource.download(this.pid, 'export', {uids: selectedIDs}, {type: 'application/octet-stream'});\n };\n\n Card.prototype.$fullname = function(options) {\n var fn = this.c_cn || '', html = options && options.html, email, names;\n if (fn.length === 0) {\n names = [];\n if (this.c_givenname && this.c_givenname.length > 0)\n names.push(this.c_givenname);\n if (this.nickname && this.nickname.length > 0)\n names.push((html?'<em>':'') + this.nickname + (html?'</em>':''));\n if (this.c_sn && this.c_sn.length > 0)\n names.push(this.c_sn);\n if (names.length > 0)\n fn = names.join(' ');\n else if (this.c_org && this.c_org.length > 0) {\n fn = this.c_org;\n }\n else if (this.emails && this.emails.length > 0) {\n email = _.find(this.emails, function(i) { return i.value !== ''; });\n if (email)\n fn = email.value;\n }\n }\n\n return fn;\n };\n\n Card.prototype.$description = function() {\n var description = [];\n if (this.title) description.push(this.title);\n if (this.role) description.push(this.role);\n if (this.orgUnits && this.orgUnits.length > 0)\n _.forEach(this.orgUnits, function(unit) {\n if (unit.value !== '')\n description.push(unit.value);\n });\n if (this.c_org) description.push(this.c_org);\n if (this.description) description.push(this.description);\n\n return description.join(', ');\n };\n\n /**\n * @function $preferredEmail\n * @memberof Card.prototype\n * @desc Get the preferred email address.\n * @param {string} [partial] - a partial string that the email must match\n * @returns the first email address of type \"pref\" or the first address if none found\n */\n Card.prototype.$preferredEmail = function(partial) {\n var email, re;\n if (partial) {\n re = new RegExp(partial, 'i');\n email = _.find(this.emails, function(o) {\n return re.test(o.value);\n });\n }\n if (email) {\n email = email.value;\n }\n else {\n email = _.find(this.emails, function(o) {\n return o.type == 'pref';\n });\n if (email) {\n email = email.value;\n }\n else if (this.emails && this.emails.length) {\n email = this.emails[0].value;\n }\n else if (this.c_mail && this.c_mail.length) {\n email = this.c_mail[0];\n }\n else {\n email = '';\n }\n }\n\n return email;\n };\n\n /**\n * @function $shortFormat\n * @memberof Card.prototype\n * @param {string} [partial] - a partial string that the email must match\n * @returns the fullname along with a matching email address in parentheses\n */\n Card.prototype.$shortFormat = function(partial) {\n var fullname = [this.$$fullname],\n email = this.$preferredEmail(partial);\n if (email && email != this.$$fullname)\n fullname.push(' <' + email + '>');\n return fullname.join(' ');\n };\n\n Card.prototype.$isCard = function() {\n return this.c_component == 'vcard';\n };\n\n Card.prototype.$isList = function(options) {\n // isGroup attribute means it's a group of a LDAP source (not expandable on the client-side)\n var condition = (!options || !options.expandable || options.expandable && !this.isgroup);\n return this.c_component == 'vlist' && condition;\n };\n\n Card.prototype.$addOrgUnit = function(orgUnit) {\n if (angular.isUndefined(this.orgUnits)) {\n this.orgUnits = [{value: orgUnit}];\n }\n else {\n for (var i = 0; i < this.orgUnits.length; i++) {\n if (this.orgUnits[i].value == orgUnit) {\n break;\n }\n }\n if (i == this.orgUnits.length)\n this.orgUnits.push({value: orgUnit});\n }\n return this.orgUnits.length - 1;\n };\n\n // Card.prototype.$addCategory = function(category) {\n // if (category) {\n // if (angular.isUndefined(this.categories)) {\n // this.categories = [{value: category}];\n // }\n // else {\n // for (var i = 0; i < this.categories.length; i++) {\n // if (this.categories[i].value == category) {\n // break;\n // }\n // }\n // if (i == this.categories.length)\n // this.categories.push({value: category});\n // }\n // }\n // };\n\n Card.prototype.$addEmail = function(type) {\n if (angular.isUndefined(this.emails)) {\n this.emails = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.emails, function(i) { return i.value === ''; }))) {\n this.emails.push({type: type, value: ''});\n }\n return this.emails.length - 1;\n };\n\n Card.prototype.$addScreenName = function(screenName) {\n this.c_screenname = screenName;\n };\n\n Card.prototype.$addPhone = function(type) {\n if (angular.isUndefined(this.phones)) {\n this.phones = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.phones, function(i) { return i.value === ''; }))) {\n this.phones.push({type: type, value: ''});\n }\n return this.phones.length - 1;\n };\n\n Card.prototype.$addUrl = function(type, url) {\n if (angular.isUndefined(this.urls)) {\n this.urls = [{type: type, value: url}];\n }\n else if (_.isUndefined(_.find(this.urls, function(i) { return i.value == url; }))) {\n this.urls.push({type: type, value: url});\n }\n return this.urls.length - 1;\n };\n\n Card.prototype.$addAddress = function(type, postoffice, street, street2, locality, region, country, postalcode) {\n if (angular.isUndefined(this.addresses)) {\n this.addresses = [{type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode}];\n }\n else if (!_.find(this.addresses, function(i) {\n return i.street == street &&\n i.street2 == street2 &&\n i.locality == locality &&\n i.country == country &&\n i.postalcode == postalcode;\n })) {\n this.addresses.push({type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode});\n }\n return this.addresses.length - 1;\n };\n\n Card.prototype.$addMember = function(email) {\n var card = new Card({email: email, emails: [{value: email}]}),\n i;\n if (angular.isUndefined(this.refs)) {\n this.refs = [card];\n }\n else if (email.length === 0) {\n this.refs.push(card);\n }\n else {\n for (i = 0; i < this.refs.length; i++) {\n if (this.refs[i].email == email) {\n break;\n }\n }\n if (i == this.refs.length)\n this.refs.push(card);\n }\n return this.refs.length - 1;\n };\n\n /**\n * @function explode\n * @memberof Card.prototype\n * @desc Create a new Card associated to each email address of this card.\n * @return an array of Card instances\n */\n Card.prototype.explode = function() {\n var _this = this, cards = [], data;\n\n if (this.emails.length > 1) {\n data = this.$omit();\n _.forEach(this.emails, function(email) {\n var card = new Card(angular.extend({}, data, {emails: [email]}));\n cards.push(card);\n });\n return cards;\n }\n else\n return [this];\n };\n\n /**\n * @function $reset\n * @memberof Card.prototype\n * @desc Reset the original state the card's data.\n */\n Card.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 $updateMember\n * @memberof Card.prototype\n * @desc Update an existing list member from a Card instance.\n * A list member has the following attribtues:\n * - email\n * - reference\n * - fn\n * @param {number} index\n * @param {string} email\n * @param {Card} card\n */\n // Card.prototype.$updateMember = function(index, email, card) {\n // var ref = {\n // email: email,\n // emails: [{value: email}],\n // reference: card.c_name,\n // c_cn: card.$fullname()\n // };\n // this.refs[index] = new Card(ref);\n // };\n\n /**\n * @function $unwrap\n * @memberof Card.prototype\n * @desc Unwrap a promise and make a copy of the resolved data.\n * @param {object} futureCardData - a promise of the Card's data\n */\n Card.prototype.$unwrap = function(futureCardData) {\n var _this = this;\n\n // Card is not loaded yet\n this.$loaded = Card.STATUS.DELAYED_LOADING;\n Card.$timeout(function() {\n if (_this.$loaded != Card.STATUS.LOADED)\n _this.$loaded = Card.STATUS.LOADING;\n }, Card.STATUS.DELAYED_MS);\n\n // Expose the promise\n this.$futureCardData = futureCardData.then(function(data) {\n _this.init(data);\n // Mark card as loaded\n _this.$loaded = Card.STATUS.LOADED;\n // Make a copy of the data for an eventual reset\n _this.$shadowData = _this.$omit(true);\n\n return _this;\n });\n\n return this.$futureCardData;\n };\n\n /**\n * @function $omit\n * @memberof Card.prototype\n * @desc Return a sanitized object used to send to the server.\n * @param {boolean} [deep] - make a deep copy if true\n * @return an object literal copy of the Card instance\n */\n Card.prototype.$omit = function(deep) {\n var card = {};\n angular.forEach(this, function(value, key) {\n if (key == 'refs') {\n card.refs = _.map(value, function(o) {\n return o.$omit(deep);\n });\n }\n else if (key != 'constructor' && key[0] != '$') {\n if (deep)\n card[key] = angular.copy(value);\n else\n card[key] = value;\n }\n });\n\n // We convert back our birthday object\n if (!deep) {\n if (card.birthday)\n card.birthday = card.birthday.format(Card.$Preferences.$mdDateLocaleProvider, '%Y-%m-%d');\n else\n card.birthday = '';\n }\n\n // We flatten the notes to an array of strings\n if (this.notes)\n card.notes = _.map(this.notes, 'value');\n\n return card;\n };\n\n Card.prototype.toString = function() {\n var desc = this.id + ' ' + this.$$fullname;\n\n if (this.$$email)\n desc += ' <' + this.$$email + '>';\n\n return '[' + desc + ']';\n };\n})();\n"]} |