From 17ebfce2c7212defe353e0076b6e75e902a107dd Mon Sep 17 00:00:00 2001 From: InverseBot Date: Wed, 6 Apr 2016 11:10:02 -0400 Subject: [PATCH] (js/css) Update generated files --- UI/WebServerResources/js/Contacts.services.js | 2 +- UI/WebServerResources/js/Contacts.services.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/WebServerResources/js/Contacts.services.js b/UI/WebServerResources/js/Contacts.services.js index a1c4b99ce..998722459 100644 --- a/UI/WebServerResources/js/Contacts.services.js +++ b/UI/WebServerResources/js/Contacts.services.js @@ -1,2 +1,2 @@ -!function(){"use strict";function a(b){if("function"!=typeof b.then)if(this.init(b),this.name&&!this.id){var c=a.$$resource.create("createFolder",this.name);this.$unwrap(c),this.acls={objectEditor:1,objectCreator:1,objectEraser:1}}else this.id&&(this.$acl=new a.$$Acl("Contacts/"+this.id));else this.$unwrap(b)}a.$factory=["$q","$timeout","$log","sgSettings","sgAddressBook_PRELOAD","Resource","Card","Acl","Preferences",function(b,c,d,e,f,g,h,i,j){return angular.extend(a,{$q:b,$timeout:c,$log:d,PRELOAD:f,$$resource:new g(e.activeUser("folderURL")+"Contacts",e.activeUser()),$Card:h,$$Acl:i,$Preferences:j,$query:{search:"name_or_address",value:"",sort:"c_cn",asc:1},activeUser:e.activeUser(),selectedFolder:null,$refreshTimeout:null}),j.ready().then(function(){j.settings.Contact.SortingState&&(a.$query.sort=j.settings.Contact.SortingState[0],a.$query.asc=parseInt(j.settings.Contact.SortingState[1]))}),a}];try{angular.module("SOGo.ContactsUI")}catch(b){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgAddressBook_PRELOAD",{LOOKAHEAD:50,SIZE:100}).factory("AddressBook",a.$factory),a.$filterAll=function(b,c,d){var e={search:b};return b?(angular.isUndefined(a.$cards)&&(a.$cards=[]),angular.extend(e,c),a.$$resource.fetch(null,"allContactSearch",e).then(function(c){var e,f,g,h=function(a){return this.id==a.id};for(e=d?_.filter(c.contacts,function(a){return _.isUndefined(_.find(d,_.bind(h,a)))}):c.contacts,g=a.$cards.length-1;g>=0;g--)f=a.$cards[g],_.isUndefined(_.find(e,_.bind(h,f)))&&a.$cards.splice(g,1);return _.forEach(e,function(c,d){if(_.isUndefined(_.find(a.$cards,_.bind(h,c)))){var e=new a.$Card(c,b);a.$cards.splice(d,0,e)}}),a.$log.debug(a.$cards),a.$cards})):(a.$cards=[],a.$q.when(a.$cards))},a.$add=function(a){var b,c,d;b=a.isSubscription?this.$subscriptions:this.$addressbooks,c=_.find(b,function(b){return"personal"==a.id||"personal"!=b.id&&1===b.name.localeCompare(a.name)}),d=c?_.indexOf(_.map(b,"id"),c.id):1,b.splice(d,0,a)},a.$findAll=function(b){var c=this;return b&&(this.$addressbooks=[],this.$subscriptions=[],this.$remotes=[],angular.forEach(b,function(b,d){var e=new a(b);e.isRemote?c.$remotes.push(e):e.isSubscription?c.$subscriptions.push(e):c.$addressbooks.push(e)})),_.union(this.$addressbooks,this.$subscriptions,this.$remotes)},a.$find=function(b){var c=a.$Preferences.ready().then(function(){return a.$$resource.fetch(b,"view",a.$query)});return new a(c)},a.$subscribe=function(b,c){var d=this;return a.$$resource.userResource(b).fetch(c,"subscribe").then(function(b){var c=new a(b);return _.isUndefined(_.find(d.$subscriptions,function(a){return a.id==b.id}))&&a.$add(c),c})},a.prototype.init=function(b,c){var d=this;this.$$cards||(this.$$cards=[]),this.idsMap={},this.$cards=[],angular.forEach(b,function(a,b){"headers"!=b&&"cards"!=b&&(d[b]=a)}),this.isOwned=a.activeUser.isSuperUser||this.owner==a.activeUser.login,this.isSubscription=!this.isRemote&&this.owner!=a.activeUser.login},a.prototype.$id=function(){return this.id?a.$q.when(this.id):this.$futureAddressBookData.then(function(a){return a.id})},a.prototype.getLength=function(){return this.$cards.length},a.prototype.getItemAtIndex=function(a){var b;return!this.$isLoading&&a>=0&&ah&&i>h;h++)this.$cards[h].$loaded!=a.$Card.STATUS.NOT_LOADED?c++:(e.push(this.$cards[h].id),this.$cards[h].$loaded=a.$Card.STATUS.LOADING);a.$log.debug("Loading Ids "+e.join(" ")+" ("+e.length+" cards)"),e.length>0&&(f=a.$$resource.post(this.id,"headers",{ids:e}),this.$unwrapHeaders(f))}return j},a.prototype.isSelectedCard=function(a){return this.selectedCard==a},a.prototype.$selectedCount=function(){var a;return a=0,this.$cards&&(a=_.filter(this.$cards,function(a){return a.selected}).length),a},a.prototype.$startRefreshTimeout=function(){var b=this;a.$refreshTimeout&&a.$timeout.cancel(a.$refreshTimeout),a.$Preferences.ready().then(function(){var c=a.$Preferences.defaults.SOGoRefreshViewCheck;if(c&&"manually"!=c){var d=angular.bind(b,a.prototype.$reload);a.$refreshTimeout=a.$timeout(d,1e3*c.timeInterval())}})},a.prototype.$reload=function(){return this.$startRefreshTimeout(),this.$filter()},a.prototype.$filter=function(b,c,d){var e,f=this,g=c&&c.dry;return g?e=angular.copy(a.$query):(this.$isLoading=!0,e=a.$query,this.isRemote||(e.partial=1)),a.$Preferences.ready().then(function(){return c&&(angular.extend(e,c),g&&!b)?(f.$$cards=[],a.$q.when(f.$$cards)):(angular.isDefined(b)&&(e.value=b),f.$id().then(function(c){var h=a.$$resource.fetch(c,"view",e);g?h.then(function(c){var e,g,h,i,j,k=f.$$cards,l=function(a){return this==a.id};for(i=_.invokeMap(c.headers[0],"toLowerCase"),j=i.indexOf("id"),c.headers.splice(0,1),e=d?_.filter(c.ids,function(a){return _.isUndefined(_.find(d,_.bind(l,a)))}):c.ids,h=k.length-1;h>=0;h--)g=k[h],_.isUndefined(_.find(e,_.bind(l,g.id)))&&k.splice(h,1);return _.forEach(e,function(c,d){if(_.isUndefined(_.find(k,_.bind(l,c)))){var e={id:c},f=new a.$Card(e,b);k.splice(d,0,f)}}),_.forEach(e,function(a,b){var c,d;k[b].id!=a&&(c=_.findIndex(k,_.bind(l,a)),d=k.splice(c,1),k.splice(b,0,d[0]))}),_.forEach(c.headers,function(a){var c,d=_.findIndex(k,_.bind(l,a[j]));d>-1&&(c=_.zipObject(i,a),k[d].init(c,b))}),f.$isLoading=!1,k}):f.$unwrap(h)}))})},a.prototype.$rename=function(b){var c=_.indexOf(_.map(a.$addressbooks,"id"),this.id);return this.name=b,a.$addressbooks.splice(c,1),a.$add(this),this.$save()},a.prototype.$delete=function(){var b,c,d=this,e=a.$q.defer();return this.isSubscription?(c=a.$$resource.fetch(this.id,"unsubscribe"),b=a.$subscriptions):(c=a.$$resource.remove(this.id),b=a.$addressbooks),c.then(function(){var a=_.indexOf(_.map(b,"id"),d.id);b.splice(a,1),e.resolve()},e.reject),e.promise},a.prototype.$deleteCards=function(b){var c=this,d=_.map(b,function(a){return a.id});return a.$$resource.post(this.id,"batchDelete",{uids:d}).then(function(){c.$cards=_.differenceBy(c.$cards,b,"id"),_.forEach(b,function(a){delete c.idsMap[a.id]})})},a.prototype.$copyCards=function(b,c){var d=_.map(b,function(a){return a.id});return a.$$resource.post(this.id,"copy",{uids:d,folder:c})},a.prototype.$save=function(){return a.$$resource.save(this.id,this.$omit()).then(function(a){return a})},a.prototype.$getCard=function(b){var c=this;return this.$id().then(function(d){var e,f=_.find(c.$cards,function(a){return b==a.id});return f&&f.$futureCardData?f:(e=a.$Card.$find(d,b),e.$id().then(function(a){f&&angular.extend(f,e)}),e)})},a.prototype.$unwrap=function(b){var c=this;this.$isLoading=!0,this.$futureAddressBookData=b.then(function(b){return a.$timeout(function(){var d;return(!b.ids||c.$topIndex>b.ids.length-1)&&(c.$topIndex=0),angular.forEach(a.$findAll(),function(a,d){a.id==b.id&&angular.extend(c,a)}),c.init(b),c.ids&&(a.$log.debug("unwrapping "+c.ids.length+" cards"),_.reduce(c.ids,function(b,d,e){var f={id:d};return c.idsMap[f.id]=e,b.push(new a.$Card(f)),b},c.$cards)),b.headers&&(d=_.invokeMap(b.headers[0],"toLowerCase"),b.headers.splice(0,1),c.ids?_.forEach(b.headers,function(a){var b=_.zipObject(d,a),e=c.idsMap[b.id];c.$cards[e].init(b)}):(c.$cards=[],angular.forEach(b.headers,function(b){var e=_.zipObject(d,b);c.$cards.push(new a.$Card(e))}))),c.$acl=new a.$$Acl("Contacts/"+c.id),c.$startRefreshTimeout(),c.$isLoading=!1,a.$log.debug("addressbook "+c.id+" ready"),c})},function(b){c.isError=!0,angular.isObject(b)&&a.$timeout(function(){angular.extend(c,b)})})},a.prototype.$unwrapHeaders=function(b){var c=this;b.then(function(b){a.$timeout(function(){var a,d;b.length>0&&(a=_.invokeMap(b[0],"toLowerCase"),b.splice(0,1),_.forEach(b,function(b){b=_.zipObject(a,b),d=c.idsMap[b.id],angular.isDefined(d)&&c.$cards[d].init(b)}))})})},a.prototype.$omit=function(){var a={};return angular.forEach(this,function(b,c){"constructor"!=c&&"ids"!=c&&"$"!=c[0]&&(a[c]=b)}),a}}(),function(){"use strict";function a(b,c){if("function"!=typeof b.then){if(this.init(b,c),this.pid&&!this.id){var d=a.$$resource.newguid(this.pid);this.$unwrap(d),this.isNew=!0}}else this.$unwrap(b)}a.$TEL_TYPES=["work","home","cell","fax","pager"],a.$EMAIL_TYPES=["work","home","pref"],a.$URL_TYPES=["work","home","pref"],a.$ADDRESS_TYPES=["work","home"],a.$factory=["$timeout","sgSettings","sgCard_STATUS","Resource","Preferences","Gravatar",function(b,c,d,e,f,g){return angular.extend(a,{STATUS:d,$$resource:new e(c.activeUser("folderURL")+"Contacts",c.activeUser()),$timeout:b,$gravatar:g,$Preferences:f}),f.ready().then(function(){f.defaults.SOGoContactsCategories&&(a.$categories=f.defaults.SOGoContactsCategories),f.defaults.SOGoAlternateAvatar&&(a.$alternateAvatar=f.defaults.SOGoAlternateAvatar)}),a}];try{angular.module("SOGo.ContactsUI")}catch(b){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgCard_STATUS",{NOT_LOADED:0,LOADING:1,LOADED:2}).factory("Card",a.$factory),a.$find=function(b,c){var d=this.$$resource.fetch([b,c].join("/"),"view");return c?new a(d):a.$unwrapCollection(d)},a.filterCategories=function(b){var c=new RegExp(b,"i");return _.map(_.filter(a.$categories,function(a){return-1!=a.search(c)}),function(a){return{value:a}})},a.$unwrapCollection=function(b){var c={};return c.$futureCardData=b,b.then(function(b){a.$timeout(function(){angular.forEach(b,function(b,d){c[b.id]=new a(b)})})}),c},a.prototype.init=function(b,c){this.refs=[],this.categories=[],angular.extend(this,b),this.$$fullname||(this.$$fullname=this.$fullname()),this.$$email||(this.$$email=this.$preferredEmail(c)),this.$$image||(this.$$image=this.image||a.$gravatar(this.$preferredEmail(c),32,a.$alternateAvatar,{no_404:!0})),this.isgroup&&(this.c_component="vlist"),this.$loaded=angular.isDefined(this.c_name)?a.STATUS.LOADED:a.STATUS.NOT_LOADED,this.empty=" "},a.prototype.$id=function(){return this.$futureCardData.then(function(a){return a.id})},a.prototype.$save=function(){var b=this,c="saveAsContact";return"vlist"==this.c_component&&(c="saveAsList"),a.$$resource.save([this.pid,this.id||"_new_"].join("/"),this.$omit(),{action:c}).then(function(c){return b.birthday&&(b.$birthday=a.$Preferences.$mdDateLocaleProvider.formatDate(b.birthday)),b.$shadowData=b.$omit(!0),c})},a.prototype.$delete=function(b,c){return b?void(c>-1&&this[b].length>c?this[b].splice(c,1):delete this[b]):a.$$resource.remove([this.pid,this.id].join("/"))},a.prototype.$fullname=function(){var a,b=this.c_cn||"";return 0===b.length&&(a=[],this.c_givenname&&this.c_givenname.length>0&&a.push(this.c_givenname),this.nickname&&this.nickname.length>0&&a.push(""+this.nickname+""),this.c_sn&&this.c_sn.length>0&&a.push(this.c_sn),a.length>0?b=a.join(" "):this.c_org&&this.c_org.length>0?b=this.c_org:this.emails&&this.emails.length>0?b=_.find(this.emails,function(a){return""!==a.value}).value:this.c_cn&&this.c_cn.length>0&&(b=this.c_cn)),b},a.prototype.$description=function(){var a=[];return this.title&&a.push(this.title),this.role&&a.push(this.role),this.orgUnits&&this.orgUnits.length>0&&_.forEach(this.orgUnits,function(b){""!==b.value&&a.push(b.value)}),this.c_org&&a.push(this.c_org),this.description&&a.push(this.description),a.join(", ")},a.prototype.$preferredEmail=function(a){var b,c;return a&&(c=new RegExp(a,"i"),b=_.find(this.emails,function(a){return c.test(a.value)})),b?b=b.value:(b=_.find(this.emails,function(a){return"pref"==a.type}),b=b?b.value:this.emails&&this.emails.length?this.emails[0].value:""),b},a.prototype.$shortFormat=function(a){var b=[this.$$fullname],c=this.$preferredEmail(a);return c&&c!=this.$$fullname&&b.push(" <"+c+">"),b.join(" ")},a.prototype.$isCard=function(){return"vcard"==this.c_component},a.prototype.$isList=function(){return"vlist"==this.c_component},a.prototype.$addOrgUnit=function(a){if(angular.isUndefined(this.orgUnits))this.orgUnits=[{value:a}];else{for(var b=0;b"),"["+a+"]"}}(); +!function(){"use strict";function a(b){if("function"!=typeof b.then)if(this.init(b),this.name&&!this.id){var c=a.$$resource.create("createFolder",this.name);this.$unwrap(c),this.acls={objectEditor:1,objectCreator:1,objectEraser:1}}else this.id&&(this.$acl=new a.$$Acl("Contacts/"+this.id));else this.$unwrap(b)}a.$factory=["$q","$timeout","$log","sgSettings","sgAddressBook_PRELOAD","Resource","Card","Acl","Preferences",function(b,c,d,e,f,g,h,i,j){return angular.extend(a,{$q:b,$timeout:c,$log:d,PRELOAD:f,$$resource:new g(e.activeUser("folderURL")+"Contacts",e.activeUser()),$Card:h,$$Acl:i,$Preferences:j,$query:{search:"name_or_address",value:"",sort:"c_cn",asc:1},activeUser:e.activeUser(),selectedFolder:null,$refreshTimeout:null}),j.ready().then(function(){j.settings.Contact.SortingState&&(a.$query.sort=j.settings.Contact.SortingState[0],a.$query.asc=parseInt(j.settings.Contact.SortingState[1]))}),a}];try{angular.module("SOGo.ContactsUI")}catch(b){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgAddressBook_PRELOAD",{LOOKAHEAD:50,SIZE:100}).factory("AddressBook",a.$factory),a.$filterAll=function(b,c,d){var e={search:b};return b?(angular.isUndefined(a.$cards)&&(a.$cards=[]),angular.extend(e,c),a.$$resource.fetch(null,"allContactSearch",e).then(function(c){var e,f,g,h=function(a){return this.id==a.id};for(e=d?_.filter(c.contacts,function(a){return _.isUndefined(_.find(d,_.bind(h,a)))}):c.contacts,g=a.$cards.length-1;g>=0;g--)f=a.$cards[g],_.isUndefined(_.find(e,_.bind(h,f)))&&a.$cards.splice(g,1);return _.forEach(e,function(c,d){if(_.isUndefined(_.find(a.$cards,_.bind(h,c)))){var e=new a.$Card(c,b);a.$cards.splice(d,0,e)}}),a.$log.debug(a.$cards),a.$cards})):(a.$cards=[],a.$q.when(a.$cards))},a.$add=function(a){var b,c,d;b=a.isSubscription?this.$subscriptions:this.$addressbooks,c=_.find(b,function(b){return"personal"==a.id||"personal"!=b.id&&1===b.name.localeCompare(a.name)}),d=c?_.indexOf(_.map(b,"id"),c.id):1,b.splice(d,0,a)},a.$findAll=function(b){var c=this;return b&&(this.$addressbooks=[],this.$subscriptions=[],this.$remotes=[],angular.forEach(b,function(b,d){var e=new a(b);e.isRemote?c.$remotes.push(e):e.isSubscription?c.$subscriptions.push(e):c.$addressbooks.push(e)})),_.union(this.$addressbooks,this.$subscriptions,this.$remotes)},a.$find=function(b){var c=a.$Preferences.ready().then(function(){return a.$$resource.fetch(b,"view",a.$query)});return new a(c)},a.$subscribe=function(b,c){var d=this;return a.$$resource.userResource(b).fetch(c,"subscribe").then(function(b){var c=new a(b);return _.isUndefined(_.find(d.$subscriptions,function(a){return a.id==b.id}))&&a.$add(c),c})},a.prototype.init=function(b,c){var d=this;this.$$cards||(this.$$cards=[]),this.idsMap={},this.$cards=[],angular.forEach(b,function(a,b){"headers"!=b&&"cards"!=b&&(d[b]=a)}),this.isOwned=a.activeUser.isSuperUser||this.owner==a.activeUser.login,this.isSubscription=!this.isRemote&&this.owner!=a.activeUser.login},a.prototype.$id=function(){return this.id?a.$q.when(this.id):this.$futureAddressBookData.then(function(a){return a.id})},a.prototype.getLength=function(){return this.$cards.length},a.prototype.getItemAtIndex=function(a){var b;return!this.$isLoading&&a>=0&&ah&&i>h;h++)this.$cards[h].$loaded!=a.$Card.STATUS.NOT_LOADED?c++:(e.push(this.$cards[h].id),this.$cards[h].$loaded=a.$Card.STATUS.LOADING);a.$log.debug("Loading Ids "+e.join(" ")+" ("+e.length+" cards)"),e.length>0&&(f=a.$$resource.post(this.id,"headers",{ids:e}),this.$unwrapHeaders(f))}return j},a.prototype.isSelectedCard=function(a){return this.selectedCard==a},a.prototype.$selectedCount=function(){var a;return a=0,this.$cards&&(a=_.filter(this.$cards,function(a){return a.selected}).length),a},a.prototype.$startRefreshTimeout=function(){var b=this;a.$refreshTimeout&&a.$timeout.cancel(a.$refreshTimeout),a.$Preferences.ready().then(function(){var c=a.$Preferences.defaults.SOGoRefreshViewCheck;if(c&&"manually"!=c){var d=angular.bind(b,a.prototype.$reload);a.$refreshTimeout=a.$timeout(d,1e3*c.timeInterval())}})},a.prototype.$reload=function(){return this.$startRefreshTimeout(),this.$filter()},a.prototype.$filter=function(b,c,d){var e,f=this,g=c&&c.dry;return g?e=angular.copy(a.$query):(this.$isLoading=!0,e=a.$query,this.isRemote||(e.partial=1)),a.$Preferences.ready().then(function(){return c&&(angular.extend(e,c),g&&!b)?(f.$$cards=[],a.$q.when(f.$$cards)):(angular.isDefined(b)&&(e.value=b),f.$id().then(function(c){var h=a.$$resource.fetch(c,"view",e);g?h.then(function(c){var e,g,h,i,j,k=f.$$cards,l=function(a){return this==a.id};for(i=_.invokeMap(c.headers[0],"toLowerCase"),j=i.indexOf("id"),c.headers.splice(0,1),e=d?_.filter(c.ids,function(a){return _.isUndefined(_.find(d,_.bind(l,a)))}):c.ids,h=k.length-1;h>=0;h--)g=k[h],_.isUndefined(_.find(e,_.bind(l,g.id)))&&k.splice(h,1);return _.forEach(e,function(c,d){if(_.isUndefined(_.find(k,_.bind(l,c)))){var e={id:c},f=new a.$Card(e,b);k.splice(d,0,f)}}),_.forEach(e,function(a,b){var c,d;k[b].id!=a&&(c=_.findIndex(k,_.bind(l,a)),d=k.splice(c,1),k.splice(b,0,d[0]))}),_.forEach(c.headers,function(a){var c,d=_.findIndex(k,_.bind(l,a[j]));d>-1&&(c=_.zipObject(i,a),k[d].init(c,b))}),f.$isLoading=!1,k}):f.$unwrap(h)}))})},a.prototype.$rename=function(b){var c=_.indexOf(_.map(a.$addressbooks,"id"),this.id);return this.name=b,a.$addressbooks.splice(c,1),a.$add(this),this.$save()},a.prototype.$delete=function(){var b,c,d=this,e=a.$q.defer();return this.isSubscription?(c=a.$$resource.fetch(this.id,"unsubscribe"),b=a.$subscriptions):(c=a.$$resource.remove(this.id),b=a.$addressbooks),c.then(function(){var a=_.indexOf(_.map(b,"id"),d.id);b.splice(a,1),e.resolve()},e.reject),e.promise},a.prototype.$deleteCards=function(b){var c=this,d=_.map(b,function(a){return a.id});return a.$$resource.post(this.id,"batchDelete",{uids:d}).then(function(){c.$cards=_.differenceBy(c.$cards,b,"id"),_.forEach(b,function(a){delete c.idsMap[a.id]})})},a.prototype.$copyCards=function(b,c){var d=_.map(b,function(a){return a.id});return a.$$resource.post(this.id,"copy",{uids:d,folder:c})},a.prototype.$save=function(){return a.$$resource.save(this.id,this.$omit()).then(function(a){return a})},a.prototype.$getCard=function(b){var c=this;return this.$id().then(function(d){var e,f=_.find(c.$cards,function(a){return b==a.id});return f&&f.$futureCardData?f:(e=a.$Card.$find(d,b),e.$id().then(function(a){f&&angular.extend(f,e)}),e)})},a.prototype.$unwrap=function(b){var c=this;this.$isLoading=!0,this.$futureAddressBookData=b.then(function(b){return a.$timeout(function(){var d;return(!b.ids||c.$topIndex>b.ids.length-1)&&(c.$topIndex=0),angular.forEach(a.$findAll(),function(a,d){a.id==b.id&&angular.extend(c,a)}),c.init(b),c.ids&&(a.$log.debug("unwrapping "+c.ids.length+" cards"),_.reduce(c.ids,function(b,d,e){var f={id:d};return c.idsMap[f.id]=e,b.push(new a.$Card(f)),b},c.$cards)),b.headers&&(d=_.invokeMap(b.headers[0],"toLowerCase"),b.headers.splice(0,1),c.ids?_.forEach(b.headers,function(a){var b=_.zipObject(d,a),e=c.idsMap[b.id];c.$cards[e].init(b)}):(c.$cards=[],angular.forEach(b.headers,function(b){var e=_.zipObject(d,b);c.$cards.push(new a.$Card(e))}))),c.$acl=new a.$$Acl("Contacts/"+c.id),c.$startRefreshTimeout(),c.$isLoading=!1,a.$log.debug("addressbook "+c.id+" ready"),c})},function(b){c.isError=!0,angular.isObject(b)&&a.$timeout(function(){angular.extend(c,b)})})},a.prototype.$unwrapHeaders=function(b){var c=this;b.then(function(b){a.$timeout(function(){var a,d;b.length>0&&(a=_.invokeMap(b[0],"toLowerCase"),b.splice(0,1),_.forEach(b,function(b){b=_.zipObject(a,b),d=c.idsMap[b.id],angular.isDefined(d)&&c.$cards[d].init(b)}))})})},a.prototype.$omit=function(){var a={};return angular.forEach(this,function(b,c){"constructor"!=c&&"ids"!=c&&"$"!=c[0]&&(a[c]=b)}),a}}(),function(){"use strict";function a(b,c){if("function"!=typeof b.then){if(this.init(b,c),this.pid&&!this.id){var d=a.$$resource.newguid(this.pid);this.$unwrap(d),this.isNew=!0}}else this.$unwrap(b)}a.$TEL_TYPES=["work","home","cell","fax","pager"],a.$EMAIL_TYPES=["work","home","pref"],a.$URL_TYPES=["work","home","pref"],a.$ADDRESS_TYPES=["work","home"],a.$factory=["$timeout","sgSettings","sgCard_STATUS","Resource","Preferences","Gravatar",function(b,c,d,e,f,g){return angular.extend(a,{STATUS:d,$$resource:new e(c.activeUser("folderURL")+"Contacts",c.activeUser()),$timeout:b,$gravatar:g,$Preferences:f}),f.ready().then(function(){f.defaults.SOGoContactsCategories&&(a.$categories=f.defaults.SOGoContactsCategories),f.defaults.SOGoAlternateAvatar&&(a.$alternateAvatar=f.defaults.SOGoAlternateAvatar)}),a}];try{angular.module("SOGo.ContactsUI")}catch(b){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgCard_STATUS",{NOT_LOADED:0,LOADING:1,LOADED:2}).factory("Card",a.$factory),a.$find=function(b,c){var d=this.$$resource.fetch([b,c].join("/"),"view");return c?new a(d):a.$unwrapCollection(d)},a.filterCategories=function(b){var c=new RegExp(b,"i");return _.map(_.filter(a.$categories,function(a){return-1!=a.search(c)}),function(a){return{value:a}})},a.$unwrapCollection=function(b){var c={};return c.$futureCardData=b,b.then(function(b){a.$timeout(function(){angular.forEach(b,function(b,d){c[b.id]=new a(b)})})}),c},a.prototype.init=function(b,c){this.refs=[],this.categories=[],angular.extend(this,b),this.$$fullname||(this.$$fullname=this.$fullname()),this.$$email||(this.$$email=this.$preferredEmail(c)),this.$$image||(this.$$image=this.image||a.$gravatar(this.$preferredEmail(c),32,a.$alternateAvatar,{no_404:!0})),this.isgroup&&(this.c_component="vlist"),this.$loaded=angular.isDefined(this.c_name)?a.STATUS.LOADED:a.STATUS.NOT_LOADED,this.empty=" "},a.prototype.$id=function(){return this.$futureCardData.then(function(a){return a.id})},a.prototype.$save=function(){var b=this,c="saveAsContact";return"vlist"==this.c_component&&(c="saveAsList"),a.$$resource.save([this.pid,this.id||"_new_"].join("/"),this.$omit(),{action:c}).then(function(c){return b.birthday&&(b.$birthday=a.$Preferences.$mdDateLocaleProvider.formatDate(b.birthday)),b.$shadowData=b.$omit(!0),c})},a.prototype.$delete=function(b,c){return b?void(c>-1&&this[b].length>c?this[b].splice(c,1):delete this[b]):a.$$resource.remove([this.pid,this.id].join("/"))},a.prototype.$fullname=function(){var a,b=this.c_cn||"";return 0===b.length&&(a=[],this.c_givenname&&this.c_givenname.length>0&&a.push(this.c_givenname),this.nickname&&this.nickname.length>0&&a.push(""+this.nickname+""),this.c_sn&&this.c_sn.length>0&&a.push(this.c_sn),a.length>0?b=a.join(" "):this.c_org&&this.c_org.length>0?b=this.c_org:this.emails&&this.emails.length>0?b=_.find(this.emails,function(a){return""!==a.value}).value:this.c_cn&&this.c_cn.length>0&&(b=this.c_cn)),b},a.prototype.$description=function(){var a=[];return this.title&&a.push(this.title),this.role&&a.push(this.role),this.orgUnits&&this.orgUnits.length>0&&_.forEach(this.orgUnits,function(b){""!==b.value&&a.push(b.value)}),this.c_org&&a.push(this.c_org),this.description&&a.push(this.description),a.join(", ")},a.prototype.$preferredEmail=function(a){var b,c;return a&&(c=new RegExp(a,"i"),b=_.find(this.emails,function(a){return c.test(a.value)})),b?b=b.value:(b=_.find(this.emails,function(a){return"pref"==a.type}),b=b?b.value:this.emails&&this.emails.length?this.emails[0].value:""),b},a.prototype.$shortFormat=function(a){var b=[this.$$fullname],c=this.$preferredEmail(a);return c&&c!=this.$$fullname&&b.push(" <"+c+">"),b.join(" ")},a.prototype.$isCard=function(){return"vcard"==this.c_component},a.prototype.$isList=function(){return"vlist"==this.c_component},a.prototype.$addOrgUnit=function(a){if(angular.isUndefined(this.orgUnits))this.orgUnits=[{value:a}];else{for(var b=0;b"),"["+a+"]"}}(); //# sourceMappingURL=Contacts.services.js.map \ No newline at end of file diff --git a/UI/WebServerResources/js/Contacts.services.js.map b/UI/WebServerResources/js/Contacts.services.js.map index ee908868c..53acac3bf 100644 --- a/UI/WebServerResources/js/Contacts.services.js.map +++ b/UI/WebServerResources/js/Contacts.services.js.map @@ -1 +1 @@ -{"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","debug","when","$add","addressbook","list","sibling","i","isSubscription","$subscriptions","$addressbooks","o","localeCompare","indexOf","map","$findAll","_this","$remotes","isRemote","push","union","$find","addressbookId","$subscribe","uid","path","userResource","addressbookData","prototype","$$cards","idsMap","key","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","isSelectedCard","selectedCard","$selectedCount","count","selected","$startRefreshTimeout","cancel","refreshViewCheck","defaults","SOGoRefreshViewCheck","f","$reload","timeInterval","$filter","query","dry","copy","partial","futureData","fields","idFieldIndex","cards","invokeMap","headers","oldIndex","removedCards","findIndex","zipObject","$rename","$save","$delete","promise","d","defer","remove","resolve","reject","$deleteCards","uids","differenceBy","$copyCards","folder","save","$omit","$getCard","fullCard","cachedCard","$futureCardData","$topIndex","reduce","isError","isObject","j","cardHeaders","futureCardData","pid","newCardData","newguid","isNew","$TEL_TYPES","$EMAIL_TYPES","$URL_TYPES","$ADDRESS_TYPES","Card_STATUS","Gravatar","$gravatar","SOGoContactsCategories","$categories","SOGoAlternateAvatar","$alternateAvatar","$unwrapCollection","filterCategories","re","RegExp","category","collection","refs","categories","$$fullname","$fullname","$$email","$preferredEmail","$$image","image","no_404","isgroup","c_component","c_name","empty","action","birthday","$birthday","$mdDateLocaleProvider","formatDate","$shadowData","attribute","names","fn","c_cn","c_givenname","nickname","c_sn","c_org","emails","$description","description","title","role","orgUnits","unit","email","test","type","$shortFormat","fullname","$isCard","$isList","$addOrgUnit","orgUnit","$addEmail","$addScreenName","screenName","c_screenname","$addPhone","phones","$addUrl","url","urls","$addAddress","postoffice","street","street2","locality","region","country","postalcode","addresses","$addMember","$reset","reference","Date","deep","getTime","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(data, 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 Fetch list of cards and return an AddressBook instance.\n * @param {string} addressbookId - the addressbook identifier\n * @returns an AddressBook object instance\n */\n AddressBook.$find = function(addressbookId) {\n var futureAddressBookData = AddressBook.$Preferences.ready().then(function() {\n return AddressBook.$$resource.fetch(addressbookId, 'view', AddressBook.$query);\n });\n return new AddressBook(futureAddressBookData);\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 = []; // TODO Keep the \"selected\" state of 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 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.selectedCard == cardId;\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 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 // 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 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 = { 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 _this.$isLoading = false;\n return cards;\n });\n }\n else {\n // Unwrap promise and instantiate or extend Cards objets\n _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.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$deleteCards = function(cards) {\n var _this = this,\n ids = _.map(cards, function(card) { return card.id; });\n \n return AddressBook.$$resource.post(this.id, 'batchDelete', {uids: ids}).then(function() {\n _this.$cards = _.differenceBy(_this.$cards, cards, 'id');\n _.forEach(cards, function(card) {\n delete _this.idsMap[card.id];\n });\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, function(card) { return card.id; });\n return AddressBook.$$resource.post(this.id, 'copy', {uids: uids, folder: folder});\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 $getCard\n * @memberof AddressBook.prototype\n * @desc Fetch the card attributes from the server.\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$getCard = function(cardId) {\n var _this = this;\n\n return this.$id().then(function(addressbookId) {\n var fullCard,\n cachedCard = _.find(_this.$cards, function(data) {\n return cardId == data.id;\n });\n\n if (cachedCard && cachedCard.$futureCardData)\n // Full card is available\n return cachedCard;\n\n fullCard = AddressBook.$Card.$find(addressbookId, cardId);\n fullCard.$id().then(function(cardId) {\n // Extend the Card object of the addressbook list with the full card description\n if (cachedCard)\n angular.extend(cachedCard, fullCard);\n });\n return fullCard;\n });\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 = { 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 _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', 'Gravatar', function($timeout, Settings, Card_STATUS, Resource, Preferences, Gravatar) {\n angular.extend(Card, {\n STATUS: Card_STATUS,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $timeout: $timeout,\n $gravatar: Gravatar,\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 LOADING: 1,\n LOADED: 2\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 this.refs = [];\n this.categories = [];\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 || Card.$gravatar(this.$preferredEmail(partial), 32, Card.$alternateAvatar, {no_404: true});\n if (this.isgroup)\n this.c_component = 'vlist';\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 $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') action = 'saveAsList';\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 Card.prototype.$fullname = function() {\n var fn = this.c_cn || '', 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('' + this.nickname + '');\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 fn = _.find(this.emails, function(i) { return i.value !== ''; }).value;\n }\n else if (this.c_cn && this.c_cn.length > 0) {\n fn = this.c_cn;\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 {\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() {\n return this.c_component == 'vlist';\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 $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 angular.extend(this, this.$shadowData);\n // Reinstanciate Card objects for list members\n angular.forEach(this.refs, function(o, i) {\n if (o.email) o.emails = [{value: o.email}];\n _this.refs[i] = new Card(o);\n });\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.LOADING;\n\n // Expose the promise\n this.$futureCardData = futureCardData.then(function(data) {\n _this.init(data);\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 if (_this.birthday) {\n _this.birthday = new Date(_this.birthday * 1000);\n Card.$Preferences.ready().then(function() {\n _this.$birthday = Card.$Preferences.$mdDateLocaleProvider.formatDate(_this.birthday);\n });\n }\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\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.getTime()/1000;\n else\n card.birthday = 0;\n }\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"]} \ No newline at end of file +{"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","debug","when","$add","addressbook","list","sibling","i","isSubscription","$subscriptions","$addressbooks","o","localeCompare","indexOf","map","$findAll","_this","$remotes","isRemote","push","union","$find","addressbookId","$subscribe","uid","path","userResource","addressbookData","prototype","$$cards","idsMap","key","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","isSelectedCard","selectedCard","$selectedCount","count","selected","$startRefreshTimeout","cancel","refreshViewCheck","defaults","SOGoRefreshViewCheck","f","$reload","timeInterval","$filter","query","dry","copy","partial","futureData","fields","idFieldIndex","cards","invokeMap","headers","oldIndex","removedCards","findIndex","zipObject","$rename","$save","$delete","promise","d","defer","remove","resolve","reject","$deleteCards","uids","differenceBy","$copyCards","folder","save","$omit","$getCard","fullCard","cachedCard","$futureCardData","$topIndex","reduce","isError","isObject","j","cardHeaders","futureCardData","pid","newCardData","newguid","isNew","$TEL_TYPES","$EMAIL_TYPES","$URL_TYPES","$ADDRESS_TYPES","Card_STATUS","Gravatar","$gravatar","SOGoContactsCategories","$categories","SOGoAlternateAvatar","$alternateAvatar","$unwrapCollection","filterCategories","re","RegExp","category","collection","refs","categories","$$fullname","$fullname","$$email","$preferredEmail","$$image","image","no_404","isgroup","c_component","c_name","empty","action","birthday","$birthday","$mdDateLocaleProvider","formatDate","$shadowData","attribute","names","fn","c_cn","c_givenname","nickname","c_sn","c_org","emails","$description","description","title","role","orgUnits","unit","email","test","type","$shortFormat","fullname","$isCard","$isList","$addOrgUnit","orgUnit","$addEmail","$addScreenName","screenName","c_screenname","$addPhone","phones","$addUrl","url","urls","$addAddress","postoffice","street","street2","locality","region","country","postalcode","addresses","$addMember","$reset","reference","dlp","parseDate","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(data, 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 Fetch list of cards and return an AddressBook instance.\n * @param {string} addressbookId - the addressbook identifier\n * @returns an AddressBook object instance\n */\n AddressBook.$find = function(addressbookId) {\n var futureAddressBookData = AddressBook.$Preferences.ready().then(function() {\n return AddressBook.$$resource.fetch(addressbookId, 'view', AddressBook.$query);\n });\n return new AddressBook(futureAddressBookData);\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 = []; // TODO Keep the \"selected\" state of 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 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.selectedCard == cardId;\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 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 // 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 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 = { 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 _this.$isLoading = false;\n return cards;\n });\n }\n else {\n // Unwrap promise and instantiate or extend Cards objets\n _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.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$deleteCards = function(cards) {\n var _this = this,\n ids = _.map(cards, function(card) { return card.id; });\n \n return AddressBook.$$resource.post(this.id, 'batchDelete', {uids: ids}).then(function() {\n _this.$cards = _.differenceBy(_this.$cards, cards, 'id');\n _.forEach(cards, function(card) {\n delete _this.idsMap[card.id];\n });\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, function(card) { return card.id; });\n return AddressBook.$$resource.post(this.id, 'copy', {uids: uids, folder: folder});\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 $getCard\n * @memberof AddressBook.prototype\n * @desc Fetch the card attributes from the server.\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$getCard = function(cardId) {\n var _this = this;\n\n return this.$id().then(function(addressbookId) {\n var fullCard,\n cachedCard = _.find(_this.$cards, function(data) {\n return cardId == data.id;\n });\n\n if (cachedCard && cachedCard.$futureCardData)\n // Full card is available\n return cachedCard;\n\n fullCard = AddressBook.$Card.$find(addressbookId, cardId);\n fullCard.$id().then(function(cardId) {\n // Extend the Card object of the addressbook list with the full card description\n if (cachedCard)\n angular.extend(cachedCard, fullCard);\n });\n return fullCard;\n });\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 = { 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 _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', 'Gravatar', function($timeout, Settings, Card_STATUS, Resource, Preferences, Gravatar) {\n angular.extend(Card, {\n STATUS: Card_STATUS,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $timeout: $timeout,\n $gravatar: Gravatar,\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 LOADING: 1,\n LOADED: 2\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 this.refs = [];\n this.categories = [];\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 || Card.$gravatar(this.$preferredEmail(partial), 32, Card.$alternateAvatar, {no_404: true});\n if (this.isgroup)\n this.c_component = 'vlist';\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 $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') action = 'saveAsList';\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 Card.prototype.$fullname = function() {\n var fn = this.c_cn || '', 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('' + this.nickname + '');\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 fn = _.find(this.emails, function(i) { return i.value !== ''; }).value;\n }\n else if (this.c_cn && this.c_cn.length > 0) {\n fn = this.c_cn;\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 {\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() {\n return this.c_component == 'vlist';\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 $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 angular.extend(this, this.$shadowData);\n // Reinstanciate Card objects for list members\n angular.forEach(this.refs, function(o, i) {\n if (o.email) o.emails = [{value: o.email}];\n _this.refs[i] = new Card(o);\n });\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.LOADING;\n\n // Expose the promise\n this.$futureCardData = futureCardData.then(function(data) {\n _this.init(data);\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 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 // 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\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 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"]} \ No newline at end of file