diff --git a/UI/WebServerResources/js/Contacts.js b/UI/WebServerResources/js/Contacts.js index ab800aa22..68b8cebe5 100644 --- a/UI/WebServerResources/js/Contacts.js +++ b/UI/WebServerResources/js/Contacts.js @@ -1,2 +1,2 @@ -!function(){"use strict";function a(a,h){a.state("app",{url:"/addressbooks",abstract:!0,views:{addressbooks:{templateUrl:"UIxContactFoldersView",controller:"AddressBooksController",controllerAs:"app"}},resolve:{stateAddressbooks:b}}).state("app.addressbook",{url:"/:addressbookId",views:{addressbook:{templateUrl:"addressbook",controller:"AddressBookController",controllerAs:"addressbook"}},resolve:{stateAddressbook:c}}).state("app.addressbook.new",{url:"/{contactType:(?:card|list)}/new",views:{card:{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}},resolve:{stateCard:d}}).state("app.addressbook.card",{url:"/:cardId",abstract:!0,views:{card:{template:""}},resolve:{stateCard:e},onEnter:f,onExit:g}).state("app.addressbook.card.view",{url:"/view",views:{"card@app.addressbook":{templateUrl:"UIxContactViewTemplate",controller:"CardController",controllerAs:"editor"}}}).state("app.addressbook.card.editor",{url:"/edit",views:{"card@app.addressbook":{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}}}),h.otherwise("/addressbooks/personal")}function b(a){return a.$findAll(window.contactFolders)}function c(a,b,c,d){var e=_.find(d.$findAll(),function(a){return a.id==c.addressbookId});return e?(e.selectedCard=!1,e.$reload(),e):a.reject("Addressbook "+c.addressbookId+" not found")}function d(a,b,c){var d="v"+a.contactType,e=new c({pid:a.addressbookId,c_component:d});return b.selectedCard=!0,e}function e(a,b,c){var d;return(d=_.find(c.$cards,function(a){return a.id==b.cardId}))?d.$reload():void a.go("app.addressbook")}function f(a,b){b.selectedCard=a.cardId}function g(a){delete c.selectedCard}function h(a,b,c){a.$on("$stateChangeError",function(a,d,e,f,g,h){b.error(h),c.go("app.addressbook",{addressbookId:"personal"})}),a.$on("$routeChangeError",function(a,c,d,e){b.error(a,c,d,e)})}angular.module("SOGo.ContactsUI",["ngCookies","ui.router","angularFileUpload","ck","SOGo.Common","SOGo.PreferencesUI","SOGo.MailerUI"]).config(a).run(h),a.$inject=["$stateProvider","$urlRouterProvider"],b.$inject=["AddressBook"],c.$inject=["$q","$state","$stateParams","AddressBook"],d.$inject=["$stateParams","stateAddressbook","Card"],e.$inject=["$state","$stateParams","stateAddressbook"],f.$inject=["$stateParams","stateAddressbook"],g.$inject=["stateAddressbook"],h.$inject=["$rootScope","$log","$state"]}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k,m,n){function o(a){d.go("app.addressbook.card.view",{cardId:a.id})}function p(a,b){b.selected=!b.selected,B.mode.multiple+=b.selected?1:-1,a.preventDefault(),a.stopPropagation()}function q(a){d.go("app.addressbook.new",{contactType:a})}function r(){_.forEach(B.selectedFolder.$cards,function(a){a.selected=!1}),B.mode.multiple=0}function s(){j.confirm(l("Warning"),l("Are you sure you want to delete the selected contacts?"),{ok:l("Delete")}).then(function(){var a=_.filter(B.selectedFolder.$cards,function(a){return a.selected});B.selectedFolder.$deleteCards(a).then(function(){B.mode.multiple=0,B.selectedFolder.selectedCard||d.go("app.addressbook")})})}function t(a){var b=_.filter(B.selectedFolder.$cards,function(a){return a.selected});B.selectedFolder.$copyCards(b,a).then(function(){})}function u(){_.forEach(B.selectedFolder.$cards,function(a){a.selected=!0}),B.mode.multiple=B.selectedFolder.$cards.length}function v(a){B.selectedFolder.$filter("",{sort:a})}function w(a){return i.$query.sort==a}function x(){B.mode.search=!1,B.selectedFolder.$filter("")}function y(a,b){g.$findAll().then(function(c){var d=_.find(c,function(a){if(0===a.id)return a});d.$getMailboxes().then(function(c){d.$newMessage().then(function(c){angular.extend(c.editable,{to:b}),f.show({parent:angular.element(document.body),targetEvent:a,clickOutsideToClose:!1,escapeToClose:!1,templateUrl:"../Mail/UIxMailEditor",controller:"MessageEditorController",controllerAs:"editor",locals:{stateAccount:d,stateMessage:c}})})})})}function z(a,b,c){var d=[c+" <"+b+">"];B.newMessage(a,d),a.stopPropagation(),a.preventDefault()}function A(a){var c=_.filter(B.selectedFolder.$cards,function(a){return a.selected}),d=[],e=[];_.forEach(c,function(a){a.$isList({expandable:!0})?angular.isDefined(a.refs)&&a.refs.length?_.forEach(a.refs,function(a){a.email.length&&e.push(a.$shortFormat())}):d.push(a.$reload().then(function(a){_.forEach(a.refs,function(a){a.email.length&&e.push(a.$shortFormat())})})):a.c_mail.length&&e.push(a.$shortFormat())}),b.all(d).then(function(){e=_.uniq(e),e.length&&B.newMessage(a,e)})}var B=this;i.selectedFolder=n,B.service=i,B.selectedFolder=n,B.selectCard=o,B.toggleCardSelection=p,B.newComponent=q,B.unselectCards=r,B.confirmDeleteSelectedCards=s,B.copySelectedCards=t,B.selectAll=u,B.sort=v,B.sortedBy=w,B.cancelSearch=x,B.newMessage=y,B.newMessageWithSelectedCards=A,B.newMessageWithRecipient=z,B.mode={search:!1,multiple:0}}a.$inject=["$scope","$q","$window","$state","$timeout","$mdDialog","Account","Card","AddressBook","Dialog","sgSettings","stateAddressbooks","stateAddressbook"],angular.module("SOGo.ContactsUI").controller("AddressBookController",a)}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k,m,n,o,p,q,r,s,t){function u(b,c){a.params.addressbookId!=c.id&&F.editMode!=c.id?(F.editMode=!1,p.$query.value="",i(m["gt-md"])||j("left").close(),a.go("app.addressbook",{addressbookId:c.id})):(b.preventDefault(),b.stopPropagation())}function v(){q.prompt(l("New addressbook"),l("Name of new addressbook")).then(function(a){var b=new p({name:a,isEditable:!0,isRemote:!1,owner:UserLogin});p.$add(b)})}function w(a){a.isRemote||(F.editMode=a.id,F.originalAddressbook=angular.extend({},a.$omit()),n("addressBookName_"+a.id))}function x(a){a.name=F.originalAddressbook.name,F.editMode=!1}function y(a){var b=a.name;b&&b.length>0&&b!=F.originalAddressbook.name&&a.$rename(b).then(function(a){F.editMode=!1},function(a,b){q.alert(l("Warning"),a)})}function z(){F.service.selectedFolder.isSubscription?F.service.selectedFolder.$delete().then(function(){F.service.selectedFolder=null,a.go("app.addressbook",{addressbookId:"personal"})},function(a,b){q.alert(l('An error occured while deleting the addressbook "%{0}".',F.service.selectedFolder.name),l(a.error))}):q.confirm(l("Warning"),l('Are you sure you want to delete the addressbook "%{0}"?',F.service.selectedFolder.name),{ok:l("Delete")}).then(function(){return F.service.selectedFolder.$delete()}).then(function(){return F.service.selectedFolder=null,a.go("app.addressbook",{addressbookId:"personal"}),!0}).catch(function(a){var b=a.data.message||a.statusText;q.alert(l('An error occured while deleting the addressbook "%{0}".',F.service.selectedFolder.name),b)})}function A(a,b){function c(a,b,c){function d(a){var b=0===a.type.indexOf("text")||/\.(ldif|vcf|vcard)$/.test(a.name);return b||h.show({template:["",'
',' error_outline'," "+l("Select a vCard or LDIF file.")+"","
","
"].join(""),position:"top right",hideDelay:3e3}),b}var e=this;e.uploader=new k({url:ApplicationBaseURL+[c.id,"import"].join("/"),autoUpload:!0,queueLimit:1,filters:[{name:d,fn:d}],onSuccessItem:function(a,c,d,e){var f;b.hide(),0===c.imported?f=l("No card was imported."):(f=l("A total of %{0} cards were imported in the addressbook.",c.imported),p.selectedFolder.$reload()),h.show(h.simple().content(f).position("top right").hideDelay(3e3))},onErrorItem:function(a,b,c,d){h.show({template:["",'
',' error_outline'," "+l("An error occured while importing contacts.")+"","
","
"].join(""),position:"top right",hideDelay:3e3})}}),e.close=function(){b.hide()}}g.show({parent:angular.element(document.body),targetEvent:a,clickOutsideToClose:!0,escapeToClose:!0,templateUrl:"UIxContactsImportDialog",controller:c,controllerAs:"$CardsImportDialogController",locals:{folder:b}}),c.$inject=["scope","$mdDialog","folder"]}function B(a){function b(a,b){function c(){a.hide()}this.addressbook=b,this.close=c}g.show({parent:angular.element(document.body),clickOutsideToClose:!0,escapeToClose:!0,templateUrl:a.id+"/links",controller:b,controllerAs:"links",locals:{addressbook:a}}),b.$inject=["$mdDialog","addressbook"]}function C(a){function b(a,b,c){function d(){f.addressbook.$save().then(function(){c.init(f.addressbook.$omit()),b.hide()})}function e(){b.cancel()}var f=this;f.addressbook=new p(c.$omit()),f.saveProperties=d,f.close=e}g.show({templateUrl:a.id+"/properties",controller:b,controllerAs:"properties",clickOutsideToClose:!0,escapeToClose:!0,locals:{srcAddressBook:a}}).catch(function(){}),b.$inject=["$scope","$mdDialog","srcAddressBook"]}function D(a){a.$acl.$users().then(function(){g.show({templateUrl:a.id+"/UIxAclEditor",controller:"AclController",controllerAs:"acl",clickOutsideToClose:!0,escapeToClose:!0,locals:{usersWithACL:a.$acl.users,User:s,folder:a}})})}function E(a){console.debug("subscribeToFolder "+a.owner+a.name),p.$subscribe(a.owner,a.name).then(function(a){h.show(h.simple().content(l("Successfully subscribed to address book")).position("top right").hideDelay(3e3))})}var F=this;F.activeUser=r.activeUser,F.service=p,F.select=u,F.newAddressbook=v,F.edit=w,F.revertEditing=x,F.save=y,F.confirmDelete=z,F.importCards=A,F.showLinks=B,F.showProperties=C,F.share=D,F.subscribeToFolder=E}a.$inject=["$state","$scope","$rootScope","$stateParams","$timeout","$window","$mdDialog","$mdToast","$mdMedia","$mdSidenav","FileUploader","sgConstant","sgFocus","Card","AddressBook","Dialog","sgSettings","User","stateAddressbooks"],angular.module("SOGo.ContactsUI").controller("AddressBooksController",a)}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k){function m(a){return angular.isString(a)?{value:a}:a}function n(){var a=B.card.$addOrgUnit("");h("orgUnit_"+a)}function o(){B.card.birthday=new Date}function p(){B.card.$addScreenName("")}function q(){var a=B.card.$addEmail("");h("email_"+a)}function r(){var a=B.card.$addPhone("");h("phone_"+a)}function s(){var a=B.card.$addUrl("","");h("url_"+a)}function t(){var a=B.card.$addAddress("","","","","","","","");h("address_"+a)}function u(a,b){return e.selectedFolder.$filter(a,{dry:!0,excludeLists:!0},b),e.selectedFolder.$$cards}function v(a){a.$valid&&B.card.$save().then(function(a){var b=_.indexOf(_.map(e.selectedFolder.$cards,"id"),B.card.id);b<0?e.selectedFolder.$reload():e.selectedFolder.$cards[b]=angular.copy(B.card),i.go("app.addressbook.card.view",{cardId:B.card.id})})}function w(){i.go("app.addressbook").then(function(){B.card=null,delete e.selectedFolder.selectedCard})}function x(){B.card.$reset()}function y(){B.card.$reset(),B.card.isNew?(B.card=null,delete e.selectedFolder.selectedCard,i.go("app.addressbook",{addressbookId:e.selectedFolder.id})):i.go("app.addressbook.card.view",{cardId:B.card.id})}function z(a){g.confirm(l("Warning"),l("Are you sure you want to delete the card of %{0}?",""+a.$fullname()+""),{ok:l("Delete")}).then(function(){e.selectedFolder.$deleteCards([a]).then(function(){w()},function(b,c){g.alert(l("Warning"),l('An error occured while deleting the card "%{0}".',a.$fullname()))})})}function A(a){B.showRawSource||B.rawSource?B.showRawSource=!B.showRawSource:f.$$resource.post(B.currentFolder.id+"/"+B.card.id,"raw").then(function(a){B.rawSource=a,B.showRawSource=!0})}var B=this;B.card=k,B.currentFolder=e.selectedFolder,B.allEmailTypes=f.$EMAIL_TYPES,B.allTelTypes=f.$TEL_TYPES,B.allUrlTypes=f.$URL_TYPES,B.allAddressTypes=f.$ADDRESS_TYPES,B.categories={},B.userFilterResults=[],B.transformCategory=m,B.addOrgUnit=n,B.addBirthday=o,B.addScreenName=p,B.addEmail=q,B.addPhone=r,B.addUrl=s,B.addAddress=t,B.userFilter=u,B.save=v,B.close=w,B.reset=x,B.cancel=y,B.confirmDelete=z,B.toggleRawSource=A,B.showRawSource=!1}a.$inject=["$scope","$timeout","$window","$mdDialog","AddressBook","Card","Dialog","sgFocus","$state","$stateParams","stateCard"],angular.module("SOGo.ContactsUI").controller("CardController",a)}(),function(){"use strict";function a(){return{restrict:"A",scope:{data:"=sgAddress"},controller:["$scope",function(a){a.addressLines=function(a){var b=[],c=[];return a.street&&b.push(a.street),a.street2&&b.push(a.street2),a.locality&&c.push(a.locality),a.region&&c.push(a.region),c.length>0&&b.push(c.join(", ")),a.country&&b.push(a.country),a.postalcode&&b.push(a.postalcode),b.join("
")}}],template:'
'}}angular.module("SOGo.Common").directive("sgAddress",a)}(); +!function(){"use strict";function a(a,h){a.state("app",{url:"/addressbooks",abstract:!0,views:{addressbooks:{templateUrl:"UIxContactFoldersView",controller:"AddressBooksController",controllerAs:"app"}},resolve:{stateAddressbooks:b}}).state("app.addressbook",{url:"/:addressbookId",views:{addressbook:{templateUrl:"addressbook",controller:"AddressBookController",controllerAs:"addressbook"}},resolve:{stateAddressbook:c}}).state("app.addressbook.new",{url:"/{contactType:(?:card|list)}/new",views:{card:{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}},resolve:{stateCard:d}}).state("app.addressbook.card",{url:"/:cardId",abstract:!0,views:{card:{template:""}},resolve:{stateCard:e},onEnter:f,onExit:g}).state("app.addressbook.card.view",{url:"/view",views:{"card@app.addressbook":{templateUrl:"UIxContactViewTemplate",controller:"CardController",controllerAs:"editor"}}}).state("app.addressbook.card.editor",{url:"/edit",views:{"card@app.addressbook":{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}}}),h.otherwise("/addressbooks/personal")}function b(a){return a.$findAll(window.contactFolders)}function c(a,b,c,d){var e=_.find(d.$findAll(),function(a){return a.id==c.addressbookId});return e?(delete e.selectedCard,e.$reload(),e):a.reject("Addressbook "+c.addressbookId+" not found")}function d(a,b,c){var d="v"+a.contactType,e=new c({pid:a.addressbookId,c_component:d});return b.selectedCard=!0,e}function e(a,b,c){var d;return(d=_.find(c.$cards,function(a){return a.id==b.cardId}))?d.$reload():void a.go("app.addressbook")}function f(a,b){b.selectedCard=a.cardId}function g(a){delete c.selectedCard}function h(a,b,c){a.$on("$stateChangeError",function(a,d,e,f,g,h){b.error(h),c.go("app.addressbook",{addressbookId:"personal"})}),a.$on("$routeChangeError",function(a,c,d,e){b.error(a,c,d,e)})}angular.module("SOGo.ContactsUI",["ngCookies","ui.router","angularFileUpload","ck","SOGo.Common","SOGo.PreferencesUI","SOGo.MailerUI"]).config(a).run(h),a.$inject=["$stateProvider","$urlRouterProvider"],b.$inject=["AddressBook"],c.$inject=["$q","$state","$stateParams","AddressBook"],d.$inject=["$stateParams","stateAddressbook","Card"],e.$inject=["$state","$stateParams","stateAddressbook"],f.$inject=["$stateParams","stateAddressbook"],g.$inject=["stateAddressbook"],h.$inject=["$rootScope","$log","$state"]}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k,m,n,o){function p(a){d.go("app.addressbook.card.view",{cardId:a.id})}function q(a,b){b.selected=!b.selected,E.mode.multiple+=b.selected?1:-1,a.preventDefault(),a.stopPropagation()}function r(a){d.go("app.addressbook.new",{contactType:a})}function s(){_.forEach(E.selectedFolder.$cards,function(a){a.selected=!1}),E.mode.multiple=0}function t(){k.confirm(l("Warning"),l("Are you sure you want to delete the selected contacts?"),{ok:l("Delete")}).then(function(){var a=_.filter(E.selectedFolder.$cards,function(a){return a.selected});E.selectedFolder.$deleteCards(a).then(function(){E.mode.multiple=0,E.selectedFolder.selectedCard||d.go("app.addressbook")})})}function u(a,b){var c,e,f,h,i,j,k;c=E.selectedFolder,i=!1,e=c.$selectedCards(),f=_.filter(e,function(a){return a.$isCard()}),f.length!=e.length&&g.show(g.simple().content(l("Lists can't be moved or copied.")).position("top right").hideDelay(2e3)),f.length&&("copy"==a?(j=c.$copyCards(f,b),k=l("%{0} card(s) copied",f.length)):(j=c.$moveCards(f,b),k=l("%{0} card(s) moved",f.length),h=_.map(f,"id"),i=c.selectedCard&&h.indexOf(c.selectedCard)>=0),j.then(function(){i&&d.go("app.addressbook"),g.show(g.simple().content(k).position("top right").hideDelay(2e3))}))}function v(a){u("copy",a)}function w(a){u("move",a)}function x(){_.forEach(E.selectedFolder.$cards,function(a){a.selected=!0}),E.mode.multiple=E.selectedFolder.$cards.length}function y(a){E.selectedFolder.$filter("",{sort:a})}function z(a){return j.$query.sort==a}function A(){E.mode.search=!1,E.selectedFolder.$filter("")}function B(a,b){h.$findAll().then(function(c){var d=_.find(c,function(a){if(0===a.id)return a});d.$getMailboxes().then(function(c){d.$newMessage().then(function(c){angular.extend(c.editable,{to:b}),f.show({parent:angular.element(document.body),targetEvent:a,clickOutsideToClose:!1,escapeToClose:!1,templateUrl:"../Mail/UIxMailEditor",controller:"MessageEditorController",controllerAs:"editor",locals:{stateAccount:d,stateMessage:c}})})})})}function C(a,b,c){var d=[c+" <"+b+">"];E.newMessage(a,d),a.stopPropagation(),a.preventDefault()}function D(a){var c=_.filter(E.selectedFolder.$cards,function(a){return a.selected}),d=[],e=[];_.forEach(c,function(a){a.$isList({expandable:!0})?angular.isDefined(a.refs)&&a.refs.length?_.forEach(a.refs,function(a){a.email.length&&e.push(a.$shortFormat())}):d.push(a.$reload().then(function(a){_.forEach(a.refs,function(a){a.email.length&&e.push(a.$shortFormat())})})):a.c_mail.length&&e.push(a.$shortFormat())}),b.all(d).then(function(){e=_.uniq(e),e.length&&E.newMessage(a,e)})}var E=this;j.selectedFolder=o,E.service=j,E.selectedFolder=o,E.selectCard=p,E.toggleCardSelection=q,E.newComponent=r,E.unselectCards=s,E.confirmDeleteSelectedCards=t,E.copySelectedCards=v,E.moveSelectedCards=w,E.selectAll=x,E.sort=y,E.sortedBy=z,E.cancelSearch=A,E.newMessage=B,E.newMessageWithSelectedCards=D,E.newMessageWithRecipient=C,E.mode={search:!1,multiple:0}}a.$inject=["$scope","$q","$window","$state","$timeout","$mdDialog","$mdToast","Account","Card","AddressBook","Dialog","sgSettings","stateAddressbooks","stateAddressbook"],angular.module("SOGo.ContactsUI").controller("AddressBookController",a)}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k,m,n,o,p,q,r,s,t){function u(b,c){a.params.addressbookId!=c.id&&H.editMode!=c.id?(H.editMode=!1,p.$query.value="",i(m["gt-md"])||j("left").close(),a.go("app.addressbook",{addressbookId:c.id})):(b.preventDefault(),b.stopPropagation())}function v(){q.prompt(l("New addressbook"),l("Name of new addressbook")).then(function(a){var b=new p({name:a,isEditable:!0,isRemote:!1,owner:UserLogin});p.$add(b)})}function w(a){a.isRemote||(H.editMode=a.id,H.originalAddressbook=angular.extend({},a.$omit()),n("addressBookName_"+a.id))}function x(a){a.name=H.originalAddressbook.name,H.editMode=!1}function y(a){var b=a.name;b&&b.length>0&&b!=H.originalAddressbook.name&&a.$rename(b).then(function(a){H.editMode=!1},function(a,b){q.alert(l("Warning"),a)})}function z(){H.service.selectedFolder.isSubscription?H.service.selectedFolder.$delete().then(function(){H.service.selectedFolder=null,a.go("app.addressbook",{addressbookId:"personal"})},function(a,b){q.alert(l('An error occured while deleting the addressbook "%{0}".',H.service.selectedFolder.name),l(a.error))}):q.confirm(l("Warning"),l('Are you sure you want to delete the addressbook "%{0}"?',H.service.selectedFolder.name),{ok:l("Delete")}).then(function(){return H.service.selectedFolder.$delete()}).then(function(){return H.service.selectedFolder=null,a.go("app.addressbook",{addressbookId:"personal"}),!0}).catch(function(a){var b=a.data.message||a.statusText;q.alert(l('An error occured while deleting the addressbook "%{0}".',H.service.selectedFolder.name),b)})}function A(a,b){function c(a,b,c){function d(a){var b=0===a.type.indexOf("text")||/\.(ldif|vcf|vcard)$/.test(a.name);return b||h.show({template:["",'
',' error_outline'," "+l("Select a vCard or LDIF file.")+"","
","
"].join(""),position:"top right",hideDelay:3e3}),b}var e=this;e.uploader=new k({url:ApplicationBaseURL+[c.id,"import"].join("/"),autoUpload:!0,queueLimit:1,filters:[{name:d,fn:d}],onSuccessItem:function(a,c,d,e){var f;b.hide(),0===c.imported?f=l("No card was imported."):(f=l("A total of %{0} cards were imported in the addressbook.",c.imported),p.selectedFolder.$reload()),h.show(h.simple().content(f).position("top right").hideDelay(3e3))},onErrorItem:function(a,b,c,d){h.show({template:["",'
',' error_outline'," "+l("An error occured while importing contacts.")+"","
","
"].join(""),position:"top right",hideDelay:3e3})}}),e.close=function(){b.hide()}}g.show({parent:angular.element(document.body),targetEvent:a,clickOutsideToClose:!0,escapeToClose:!0,templateUrl:"UIxContactsImportDialog",controller:c,controllerAs:"$CardsImportDialogController",locals:{folder:b}}),c.$inject=["scope","$mdDialog","folder"]}function B(a){function b(a,b){function c(){a.hide()}this.addressbook=b,this.close=c}g.show({parent:angular.element(document.body),clickOutsideToClose:!0,escapeToClose:!0,templateUrl:a.id+"/links",controller:b,controllerAs:"links",locals:{addressbook:a}}),b.$inject=["$mdDialog","addressbook"]}function C(a){function b(a,b,c){function d(){f.addressbook.$save().then(function(){c.init(f.addressbook.$omit()),b.hide()})}function e(){b.cancel()}var f=this;f.addressbook=new p(c.$omit()),f.saveProperties=d,f.close=e}g.show({templateUrl:a.id+"/properties",controller:b,controllerAs:"properties",clickOutsideToClose:!0,escapeToClose:!0,locals:{srcAddressBook:a}}).catch(function(){}),b.$inject=["$scope","$mdDialog","srcAddressBook"]}function D(a){a.$acl.$users().then(function(){g.show({templateUrl:a.id+"/UIxAclEditor",controller:"AclController",controllerAs:"acl",clickOutsideToClose:!0,escapeToClose:!0,locals:{usersWithACL:a.$acl.users,User:s,folder:a}})})}function E(a){console.debug("subscribeToFolder "+a.owner+a.name),p.$subscribe(a.owner,a.name).then(function(a){h.show(h.simple().content(l("Successfully subscribed to address book")).position("top right").hideDelay(3e3))})}function F(a,b){return b.id!=a.id&&(b.isOwned||b.acls.objectCreator)}function G(b,c,d){var e,f,g,i,j,k,m;e=c.id,j=!1,f=b.$selectedCards(),0===f.length&&(f=[b.$selectedCard()]),g=_.filter(f,function(a){return a.$isCard()}),g.length!=f.length&&h.show(h.simple().content(l("Lists can't be moved or copied.")).position("top right").hideDelay(2e3)),g.length&&("copy"==d?(k=b.$copyCards(g,e),m=l("%{0} card(s) copied",g.length)):(k=b.$moveCards(g,e),m=l("%{0} card(s) moved",g.length),i=_.map(g,"id"),j=b.selectedCard&&i.indexOf(b.selectedCard)>=0),k.then(function(){j&&a.go("app.addressbook"),h.show(h.simple().content(m).position("top right").hideDelay(2e3))}))}var H=this;H.activeUser=r.activeUser,H.service=p,H.select=u,H.newAddressbook=v,H.edit=w,H.revertEditing=x,H.save=y,H.confirmDelete=z,H.importCards=A,H.showLinks=B,H.showProperties=C,H.share=D,H.subscribeToFolder=E,H.isDroppableFolder=F,H.dragSelectedCards=G}a.$inject=["$state","$scope","$rootScope","$stateParams","$timeout","$window","$mdDialog","$mdToast","$mdMedia","$mdSidenav","FileUploader","sgConstant","sgFocus","Card","AddressBook","Dialog","sgSettings","User","stateAddressbooks"],angular.module("SOGo.ContactsUI").controller("AddressBooksController",a)}(),function(){"use strict";function a(a,b,c,d,e,f,g,h,i,j,k){function m(a){return angular.isString(a)?{value:a}:a}function n(){var a=B.card.$addOrgUnit("");h("orgUnit_"+a)}function o(){B.card.birthday=new Date}function p(){B.card.$addScreenName("")}function q(){var a=B.card.$addEmail("");h("email_"+a)}function r(){var a=B.card.$addPhone("");h("phone_"+a)}function s(){var a=B.card.$addUrl("","");h("url_"+a)}function t(){var a=B.card.$addAddress("","","","","","","","");h("address_"+a)}function u(a,b){return e.selectedFolder.$filter(a,{dry:!0,excludeLists:!0},b),e.selectedFolder.$$cards}function v(a){a.$valid&&B.card.$save().then(function(a){var b=_.indexOf(_.map(e.selectedFolder.$cards,"id"),B.card.id);b<0?e.selectedFolder.$reload():e.selectedFolder.$cards[b]=angular.copy(B.card),i.go("app.addressbook.card.view",{cardId:B.card.id})})}function w(){i.go("app.addressbook").then(function(){B.card=null,delete e.selectedFolder.selectedCard})}function x(){B.card.$reset()}function y(){B.card.$reset(),B.card.isNew?(B.card=null,delete e.selectedFolder.selectedCard,i.go("app.addressbook",{addressbookId:e.selectedFolder.id})):i.go("app.addressbook.card.view",{cardId:B.card.id})}function z(a){g.confirm(l("Warning"),l("Are you sure you want to delete the card of %{0}?",""+a.$fullname()+""),{ok:l("Delete")}).then(function(){e.selectedFolder.$deleteCards([a]).then(function(){w()},function(b,c){g.alert(l("Warning"),l('An error occured while deleting the card "%{0}".',a.$fullname()))})})}function A(a){B.showRawSource||B.rawSource?B.showRawSource=!B.showRawSource:f.$$resource.post(B.currentFolder.id+"/"+B.card.id,"raw").then(function(a){B.rawSource=a,B.showRawSource=!0})}var B=this;B.card=k,B.currentFolder=e.selectedFolder,B.allEmailTypes=f.$EMAIL_TYPES,B.allTelTypes=f.$TEL_TYPES,B.allUrlTypes=f.$URL_TYPES,B.allAddressTypes=f.$ADDRESS_TYPES,B.categories={},B.userFilterResults=[],B.transformCategory=m,B.addOrgUnit=n,B.addBirthday=o,B.addScreenName=p,B.addEmail=q,B.addPhone=r,B.addUrl=s,B.addAddress=t,B.userFilter=u,B.save=v,B.close=w,B.reset=x,B.cancel=y,B.confirmDelete=z,B.toggleRawSource=A,B.showRawSource=!1}a.$inject=["$scope","$timeout","$window","$mdDialog","AddressBook","Card","Dialog","sgFocus","$state","$stateParams","stateCard"],angular.module("SOGo.ContactsUI").controller("CardController",a)}(),function(){"use strict";function a(){return{restrict:"A",scope:{data:"=sgAddress"},controller:["$scope",function(a){a.addressLines=function(a){var b=[],c=[];return a.street&&b.push(a.street),a.street2&&b.push(a.street2),a.locality&&c.push(a.locality),a.region&&c.push(a.region),c.length>0&&b.push(c.join(", ")),a.country&&b.push(a.country),a.postalcode&&b.push(a.postalcode),b.join("
")}}],template:'
'}}angular.module("SOGo.Common").directive("sgAddress",a)}(); //# sourceMappingURL=Contacts.js.map \ No newline at end of file diff --git a/UI/WebServerResources/js/Contacts.js.map b/UI/WebServerResources/js/Contacts.js.map index bcd09ef35..ecf2159bc 100644 --- a/UI/WebServerResources/js/Contacts.js.map +++ b/UI/WebServerResources/js/Contacts.js.map @@ -1 +1 @@ -{"version":3,"sources":["Contacts/Contacts.app.js","Contacts/AddressBookController.js","Contacts/AddressBooksController.js","Contacts/CardController.js","Contacts/sgAddress.directive.js"],"names":["configure","$stateProvider","$urlRouterProvider","state","url","abstract","views","addressbooks","templateUrl","controller","controllerAs","resolve","stateAddressbooks","addressbook","stateAddressbook","card","stateCard","stateNewCard","template","onEnter","onEnterCard","onExit","onExitCard","card@app.addressbook","otherwise","AddressBook","$findAll","window","contactFolders","$q","$state","$stateParams","_","find","id","addressbookId","selectedCard","$reload","reject","Card","tag","contactType","pid","c_component","$cards","cardObject","cardId","go","stateMailbox","runBlock","$rootScope","$log","$on","event","toState","toParams","fromState","fromParams","error","current","previous","rejection","angular","module","config","run","$inject","AddressBookController","$scope","$window","$timeout","$mdDialog","Account","Dialog","Settings","selectCard","toggleCardSelection","$event","selected","vm","mode","multiple","preventDefault","stopPropagation","newComponent","type","unselectCards","forEach","selectedFolder","confirmDeleteSelectedCards","confirm","l","ok","then","selectedCards","filter","$deleteCards","copySelectedCards","folder","$copyCards","selectAll","length","sort","field","$filter","sortedBy","$query","cancelSearch","search","newMessage","recipients","accounts","account","o","$getMailboxes","mailboxes","$newMessage","message","extend","editable","to","show","parent","element","document","body","targetEvent","clickOutsideToClose","escapeToClose","locals","stateAccount","stateMessage","newMessageWithRecipient","recipient","fn","newMessageWithSelectedCards","promises","$isList","expandable","isDefined","refs","ref","email","push","$shortFormat","c_mail","all","uniq","this","service","AddressBooksController","$mdToast","$mdMedia","$mdSidenav","FileUploader","sgConstant","focus","User","select","params","editMode","value","close","newAddressbook","prompt","name","isEditable","isRemote","owner","UserLogin","$add","edit","originalAddressbook","$omit","revertEditing","save","$rename","data","status","alert","confirmDelete","isSubscription","$delete","catch","response","statusText","importCards","CardsImportDialogController","scope","filterByExtension","item","isTextFile","indexOf","test","join","position","hideDelay","uploader","ApplicationBaseURL","autoUpload","queueLimit","filters","onSuccessItem","headers","msg","hide","imported","simple","content","onErrorItem","showLinks","LinksDialogController","showProperties","PropertiesDialogController","srcAddressBook","saveProperties","$save","init","cancel","share","$acl","$users","usersWithACL","users","subscribeToFolder","addressbookData","console","debug","$subscribe","activeUser","CardController","transformCategory","input","isString","addOrgUnit","i","$addOrgUnit","addBirthday","birthday","Date","addScreenName","$addScreenName","addEmail","$addEmail","addPhone","$addPhone","addUrl","$addUrl","addAddress","$addAddress","userFilter","excludedCards","dry","excludeLists","$$cards","form","$valid","map","copy","reset","$reset","isNew","$fullname","toggleRawSource","showRawSource","rawSource","$$resource","post","currentFolder","allEmailTypes","$EMAIL_TYPES","allTelTypes","$TEL_TYPES","allUrlTypes","$URL_TYPES","allAddressTypes","$ADDRESS_TYPES","categories","userFilterResults","sgAddress","restrict","addressLines","lines","locality_region","street","street2","locality","region","country","postalcode","directive"],"mappings":"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","file":"Contacts.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n/* JavaScript for SOGoContacts */\n\n(function() {\n 'use strict';\n\n angular.module('SOGo.ContactsUI', ['ngCookies', 'ui.router', 'angularFileUpload', 'ck', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.MailerUI'])\n .config(configure)\n .run(runBlock);\n\n /**\n * @ngInject\n */\n configure.$inject = ['$stateProvider', '$urlRouterProvider'];\n function configure($stateProvider, $urlRouterProvider) {\n $stateProvider\n .state('app', {\n url: '/addressbooks',\n abstract: true,\n views: {\n addressbooks: {\n templateUrl: 'UIxContactFoldersView', // UI/Templates/Contacts/UIxContactFoldersView.wox\n controller: 'AddressBooksController',\n controllerAs: 'app'\n }\n },\n resolve: {\n stateAddressbooks: stateAddressbooks\n }\n })\n .state('app.addressbook', {\n url: '/:addressbookId',\n views: {\n addressbook: {\n templateUrl: 'addressbook',\n controller: 'AddressBookController',\n controllerAs: 'addressbook'\n }\n },\n resolve: {\n stateAddressbook: stateAddressbook\n }\n })\n .state('app.addressbook.new', {\n url: '/{contactType:(?:card|list)}/new',\n views: {\n card: {\n templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n },\n resolve: {\n stateCard: stateNewCard\n }\n })\n .state('app.addressbook.card', {\n url: '/:cardId',\n abstract: true,\n views: {\n card: {\n template: ''\n }\n },\n resolve: {\n stateCard: stateCard\n },\n onEnter: onEnterCard,\n onExit: onExitCard\n })\n .state('app.addressbook.card.view', {\n url: '/view',\n views: {\n 'card@app.addressbook': {\n templateUrl: 'UIxContactViewTemplate', // UI/Templates/Contacts/UIxContactViewTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n }\n })\n .state('app.addressbook.card.editor', {\n url: '/edit',\n views: {\n 'card@app.addressbook': {\n templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n }\n });\n\n // if none of the above states are matched, use this as the fallback\n $urlRouterProvider.otherwise('/addressbooks/personal');\n }\n\n /**\n * @ngInject\n */\n stateAddressbooks.$inject = ['AddressBook'];\n function stateAddressbooks(AddressBook) {\n return AddressBook.$findAll(window.contactFolders);\n }\n\n /**\n * @ngInject\n */\n stateAddressbook.$inject = ['$q', '$state', '$stateParams', 'AddressBook'];\n function stateAddressbook($q, $state, $stateParams, AddressBook) {\n var addressbook = _.find(AddressBook.$findAll(), function(addressbook) {\n return addressbook.id == $stateParams.addressbookId;\n });\n if (addressbook) {\n addressbook.selectedCard = false;\n addressbook.$reload();\n return addressbook;\n }\n return $q.reject('Addressbook ' + $stateParams.addressbookId + ' not found');\n }\n\n /**\n * @ngInject\n */\n stateNewCard.$inject = ['$stateParams', 'stateAddressbook', 'Card'];\n function stateNewCard($stateParams, stateAddressbook, Card) {\n var tag = 'v' + $stateParams.contactType,\n card = new Card({ pid: $stateParams.addressbookId, c_component: tag });\n stateAddressbook.selectedCard = true;\n return card;\n }\n\n /**\n * @ngInject\n */\n stateCard.$inject = ['$state', '$stateParams', 'stateAddressbook'];\n function stateCard($state, $stateParams, stateAddressbook) {\n var card;\n\n card = _.find(stateAddressbook.$cards, function(cardObject) {\n return (cardObject.id == $stateParams.cardId);\n });\n\n if (card) {\n return card.$reload();\n }\n else {\n // Card not found\n $state.go('app.addressbook');\n }\n }\n\n /**\n * @ngInject\n */\n onEnterCard.$inject = ['$stateParams', 'stateAddressbook'];\n function onEnterCard($stateParams, stateAddressbook) {\n stateAddressbook.selectedCard = $stateParams.cardId;\n }\n\n /**\n * @ngInject\n */\n onExitCard.$inject = ['stateAddressbook'];\n function onExitCard(stateMailbox) {\n delete stateAddressbook.selectedCard;\n }\n\n /**\n * @ngInject\n */\n runBlock.$inject = ['$rootScope', '$log', '$state'];\n function runBlock($rootScope, $log, $state) {\n $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {\n $log.error(error);\n $state.go('app.addressbook', { addressbookId: 'personal' });\n });\n $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {\n $log.error(event, current, previous, rejection);\n });\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n AddressBookController.$inject = ['$scope', '$q', '$window', '$state', '$timeout', '$mdDialog', 'Account', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'stateAddressbooks', 'stateAddressbook'];\n function AddressBookController($scope, $q, $window, $state, $timeout, $mdDialog, Account, Card, AddressBook, Dialog, Settings, stateAddressbooks, stateAddressbook) {\n var vm = this;\n\n AddressBook.selectedFolder = stateAddressbook;\n\n vm.service = AddressBook;\n vm.selectedFolder = stateAddressbook;\n vm.selectCard = selectCard;\n vm.toggleCardSelection = toggleCardSelection;\n vm.newComponent = newComponent;\n vm.unselectCards = unselectCards;\n vm.confirmDeleteSelectedCards = confirmDeleteSelectedCards;\n vm.copySelectedCards = copySelectedCards;\n vm.selectAll = selectAll;\n vm.sort = sort;\n vm.sortedBy = sortedBy;\n vm.cancelSearch = cancelSearch;\n vm.newMessage = newMessage;\n vm.newMessageWithSelectedCards = newMessageWithSelectedCards;\n vm.newMessageWithRecipient = newMessageWithRecipient;\n vm.mode = { search: false, multiple: 0 };\n \n function selectCard(card) {\n $state.go('app.addressbook.card.view', {cardId: card.id});\n }\n \n function toggleCardSelection($event, card) {\n card.selected = !card.selected;\n vm.mode.multiple += card.selected? 1 : -1;\n $event.preventDefault();\n $event.stopPropagation();\n }\n\n function newComponent(type) {\n $state.go('app.addressbook.new', { contactType: type });\n }\n\n function unselectCards() {\n _.forEach(vm.selectedFolder.$cards, function(card) {\n card.selected = false;\n });\n vm.mode.multiple = 0;\n }\n \n function confirmDeleteSelectedCards() {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the selected contacts?'),\n { ok: l('Delete') })\n .then(function() {\n // User confirmed the deletion\n var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });\n vm.selectedFolder.$deleteCards(selectedCards).then(function() {\n vm.mode.multiple = 0;\n if (!vm.selectedFolder.selectedCard)\n $state.go('app.addressbook');\n });\n });\n }\n\n function copySelectedCards(folder) {\n var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });\n vm.selectedFolder.$copyCards(selectedCards, folder).then(function() {\n // TODO: refresh target addressbook?\n });\n }\n\n function selectAll() {\n _.forEach(vm.selectedFolder.$cards, function(card) {\n card.selected = true;\n });\n vm.mode.multiple = vm.selectedFolder.$cards.length;\n }\n\n function sort(field) {\n vm.selectedFolder.$filter('', { sort: field });\n }\n\n function sortedBy(field) {\n return AddressBook.$query.sort == field;\n }\n\n function cancelSearch() {\n vm.mode.search = false;\n vm.selectedFolder.$filter('');\n }\n\n function newMessage($event, recipients) {\n Account.$findAll().then(function(accounts) {\n var account = _.find(accounts, function(o) {\n if (o.id === 0)\n return o;\n });\n\n // We must initialize the Account with its mailbox\n // list before proceeding with message's creation\n account.$getMailboxes().then(function(mailboxes) {\n account.$newMessage().then(function(message) {\n angular.extend(message.editable, { to: recipients });\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: false,\n escapeToClose: false,\n templateUrl: '../Mail/UIxMailEditor',\n controller: 'MessageEditorController',\n controllerAs: 'editor',\n locals: {\n stateAccount: account,\n stateMessage: message\n }\n });\n });\n });\n });\n }\n\n function newMessageWithRecipient($event, recipient, fn) {\n var recipients = [fn + ' <' + recipient + '>'];\n vm.newMessage($event, recipients);\n $event.stopPropagation();\n $event.preventDefault();\n }\n\n function newMessageWithSelectedCards($event) {\n var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });\n var promises = [], recipients = [];\n\n _.forEach(selectedCards, function(card) {\n if (card.$isList({expandable: true})) {\n // If the list's members were already fetch, use them\n if (angular.isDefined(card.refs) && card.refs.length) {\n _.forEach(card.refs, function(ref) {\n if (ref.email.length)\n recipients.push(ref.$shortFormat());\n });\n }\n else {\n promises.push(card.$reload().then(function(card) {\n _.forEach(card.refs, function(ref) {\n if (ref.email.length)\n recipients.push(ref.$shortFormat());\n });\n }));\n }\n }\n else if (card.c_mail.length) {\n recipients.push(card.$shortFormat());\n }\n });\n\n $q.all(promises).then(function() {\n recipients = _.uniq(recipients);\n if (recipients.length)\n vm.newMessage($event, recipients);\n });\n }\n }\n\n angular\n .module('SOGo.ContactsUI') \n .controller('AddressBookController', AddressBookController); \n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n AddressBooksController.$inject = ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$window', '$mdDialog', '$mdToast', '$mdMedia', '$mdSidenav', 'FileUploader', 'sgConstant', 'sgFocus', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'User', 'stateAddressbooks'];\n function AddressBooksController($state, $scope, $rootScope, $stateParams, $timeout, $window, $mdDialog, $mdToast, $mdMedia, $mdSidenav, FileUploader, sgConstant, focus, Card, AddressBook, Dialog, Settings, User, stateAddressbooks) {\n var vm = this;\n\n vm.activeUser = Settings.activeUser;\n vm.service = AddressBook;\n vm.select = select;\n vm.newAddressbook = newAddressbook;\n vm.edit = edit;\n vm.revertEditing = revertEditing;\n vm.save = save;\n vm.confirmDelete = confirmDelete;\n vm.importCards = importCards;\n vm.showLinks = showLinks;\n vm.showProperties = showProperties;\n vm.share = share;\n vm.subscribeToFolder = subscribeToFolder;\n\n function select($event, folder) {\n if ($state.params.addressbookId != folder.id &&\n vm.editMode != folder.id) {\n vm.editMode = false;\n AddressBook.$query.value = '';\n // Close sidenav on small devices\n if (!$mdMedia(sgConstant['gt-md']))\n $mdSidenav('left').close();\n $state.go('app.addressbook', {addressbookId: folder.id});\n }\n else {\n $event.preventDefault();\n $event.stopPropagation();\n }\n }\n\n function newAddressbook() {\n Dialog.prompt(l('New addressbook'),\n l('Name of new addressbook'))\n .then(function(name) {\n var addressbook = new AddressBook(\n {\n name: name,\n isEditable: true,\n isRemote: false,\n owner: UserLogin\n }\n );\n AddressBook.$add(addressbook);\n });\n }\n\n function edit(folder) {\n if (!folder.isRemote) {\n vm.editMode = folder.id;\n vm.originalAddressbook = angular.extend({}, folder.$omit());\n focus('addressBookName_' + folder.id);\n }\n }\n\n function revertEditing(folder) {\n folder.name = vm.originalAddressbook.name;\n vm.editMode = false;\n }\n\n function save(folder) {\n var name = folder.name;\n if (name && name.length > 0 && name != vm.originalAddressbook.name) {\n folder.$rename(name)\n .then(function(data) {\n vm.editMode = false;\n }, function(data, status) {\n Dialog.alert(l('Warning'), data);\n });\n }\n }\n\n function confirmDelete() {\n if (vm.service.selectedFolder.isSubscription) {\n // Unsubscribe without confirmation\n vm.service.selectedFolder.$delete()\n .then(function() {\n vm.service.selectedFolder = null;\n $state.go('app.addressbook', { addressbookId: 'personal' });\n }, function(data, status) {\n Dialog.alert(l('An error occured while deleting the addressbook \"%{0}\".',\n vm.service.selectedFolder.name),\n l(data.error));\n });\n }\n else {\n Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook \"%{0}\"?',\n vm.service.selectedFolder.name),\n { ok: l('Delete') })\n .then(function() {\n return vm.service.selectedFolder.$delete();\n })\n .then(function() {\n vm.service.selectedFolder = null;\n $state.go('app.addressbook', { addressbookId: 'personal' });\n return true;\n })\n .catch(function(response) {\n var message = response.data.message || response.statusText;\n Dialog.alert(l('An error occured while deleting the addressbook \"%{0}\".',\n vm.service.selectedFolder.name),\n message);\n });\n }\n }\n\n function importCards($event, folder) {\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: 'UIxContactsImportDialog',\n controller: CardsImportDialogController,\n controllerAs: '$CardsImportDialogController',\n locals: {\n folder: folder\n }\n });\n\n /**\n * @ngInject\n */\n CardsImportDialogController.$inject = ['scope', '$mdDialog', 'folder'];\n function CardsImportDialogController(scope, $mdDialog, folder) {\n var vm = this;\n\n vm.uploader = new FileUploader({\n url: ApplicationBaseURL + [folder.id, 'import'].join('/'),\n autoUpload: true,\n queueLimit: 1,\n filters: [{ name: filterByExtension, fn: filterByExtension }],\n onSuccessItem: function(item, response, status, headers) {\n var msg;\n\n $mdDialog.hide();\n\n if (response.imported === 0)\n msg = l('No card was imported.');\n else {\n msg = l('A total of %{0} cards were imported in the addressbook.', response.imported);\n AddressBook.selectedFolder.$reload();\n }\n\n $mdToast.show(\n $mdToast.simple()\n .content(msg)\n .position('top right')\n .hideDelay(3000));\n },\n onErrorItem: function(item, response, status, headers) {\n $mdToast.show({\n template: [\n '',\n '
',\n ' error_outline',\n ' ' + l('An error occured while importing contacts.') + '',\n '
',\n '
'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n }\n });\n\n vm.close = function() {\n $mdDialog.hide();\n };\n\n function filterByExtension(item) {\n var isTextFile = item.type.indexOf('text') === 0 ||\n /\\.(ldif|vcf|vcard)$/.test(item.name);\n\n if (!isTextFile)\n $mdToast.show({\n template: [\n '',\n '
',\n ' error_outline',\n ' ' + l('Select a vCard or LDIF file.') + '',\n '
',\n '
'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n\n return isTextFile;\n }\n }\n }\n\n function showLinks(addressbook) {\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: addressbook.id + '/links',\n controller: LinksDialogController,\n controllerAs: 'links',\n locals: {\n addressbook: addressbook\n }\n });\n \n /**\n * @ngInject\n */\n LinksDialogController.$inject = ['$mdDialog', 'addressbook'];\n function LinksDialogController($mdDialog, addressbook) {\n var vm = this;\n this.addressbook = addressbook;\n this.close = close;\n\n function close() {\n $mdDialog.hide();\n }\n }\n }\n\n function showProperties(addressbook) {\n $mdDialog.show({\n templateUrl: addressbook.id + '/properties',\n controller: PropertiesDialogController,\n controllerAs: 'properties',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n srcAddressBook: addressbook\n }\n }).catch(function() {\n // Do nothing\n });\n\n /**\n * @ngInject\n */\n PropertiesDialogController.$inject = ['$scope', '$mdDialog', 'srcAddressBook'];\n function PropertiesDialogController($scope, $mdDialog, srcAddressBook) {\n var vm = this;\n\n vm.addressbook = new AddressBook(srcAddressBook.$omit());\n vm.saveProperties = saveProperties;\n vm.close = close;\n\n function saveProperties() {\n vm.addressbook.$save().then(function() {\n // Refresh list instance\n srcAddressBook.init(vm.addressbook.$omit());\n $mdDialog.hide();\n });\n }\n\n function close() {\n $mdDialog.cancel();\n }\n }\n }\n\n function share(addressbook) {\n // Fetch list of ACL users\n addressbook.$acl.$users().then(function() {\n // Show ACL editor\n $mdDialog.show({\n templateUrl: addressbook.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox\n controller: 'AclController', // from the ng module SOGo.Common\n controllerAs: 'acl',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n usersWithACL: addressbook.$acl.users,\n User: User,\n folder: addressbook\n }\n });\n });\n }\n\n /**\n * subscribeToFolder - Callback of sgSubscribe directive\n */\n function subscribeToFolder(addressbookData) {\n console.debug('subscribeToFolder ' + addressbookData.owner + addressbookData.name);\n AddressBook.$subscribe(addressbookData.owner, addressbookData.name).then(function(data) {\n $mdToast.show(\n $mdToast.simple()\n .content(l('Successfully subscribed to address book'))\n .position('top right')\n .hideDelay(3000));\n });\n }\n }\n\n angular\n .module('SOGo.ContactsUI')\n .controller('AddressBooksController', AddressBooksController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * Controller to view and edit a card\n * @ngInject\n */\n CardController.$inject = ['$scope', '$timeout', '$window', '$mdDialog', 'AddressBook', 'Card', 'Dialog', 'sgFocus', '$state', '$stateParams', 'stateCard'];\n function CardController($scope, $timeout, $window, $mdDialog, AddressBook, Card, Dialog, focus, $state, $stateParams, stateCard) {\n var vm = this;\n\n vm.card = stateCard;\n\n vm.currentFolder = AddressBook.selectedFolder;\n vm.allEmailTypes = Card.$EMAIL_TYPES;\n vm.allTelTypes = Card.$TEL_TYPES;\n vm.allUrlTypes = Card.$URL_TYPES;\n vm.allAddressTypes = Card.$ADDRESS_TYPES;\n vm.categories = {};\n vm.userFilterResults = [];\n vm.transformCategory = transformCategory;\n vm.addOrgUnit = addOrgUnit;\n vm.addBirthday = addBirthday;\n vm.addScreenName = addScreenName;\n vm.addEmail = addEmail;\n vm.addPhone = addPhone;\n vm.addUrl = addUrl;\n vm.addAddress = addAddress;\n vm.userFilter = userFilter;\n vm.save = save;\n vm.close = close;\n vm.reset = reset;\n vm.cancel = cancel;\n vm.confirmDelete = confirmDelete;\n vm.toggleRawSource = toggleRawSource;\n vm.showRawSource = false;\n\n function transformCategory(input) {\n if (angular.isString(input))\n return { value: input };\n else\n return input;\n }\n function addOrgUnit() {\n var i = vm.card.$addOrgUnit('');\n focus('orgUnit_' + i);\n }\n function addBirthday() {\n vm.card.birthday = new Date();\n }\n function addScreenName() {\n vm.card.$addScreenName('');\n }\n function addEmail() {\n var i = vm.card.$addEmail('');\n focus('email_' + i);\n }\n function addPhone() {\n var i = vm.card.$addPhone('');\n focus('phone_' + i);\n }\n function addUrl() {\n var i = vm.card.$addUrl('', '');\n focus('url_' + i);\n }\n function addAddress() {\n var i = vm.card.$addAddress('', '', '', '', '', '', '', '');\n focus('address_' + i);\n }\n function userFilter($query, excludedCards) {\n AddressBook.selectedFolder.$filter($query, {dry: true, excludeLists: true}, excludedCards);\n return AddressBook.selectedFolder.$$cards;\n }\n function save(form) {\n if (form.$valid) {\n vm.card.$save()\n .then(function(data) {\n var i = _.indexOf(_.map(AddressBook.selectedFolder.$cards, 'id'), vm.card.id);\n if (i < 0) {\n // New card; reload contacts list and show addressbook in which the card has been created\n AddressBook.selectedFolder.$reload();\n }\n else {\n // Update contacts list with new version of the Card object\n AddressBook.selectedFolder.$cards[i] = angular.copy(vm.card);\n }\n $state.go('app.addressbook.card.view', { cardId: vm.card.id });\n });\n }\n }\n function close() {\n $state.go('app.addressbook').then(function() {\n vm.card = null;\n delete AddressBook.selectedFolder.selectedCard;\n });\n }\n function reset() {\n vm.card.$reset();\n }\n function cancel() {\n vm.card.$reset();\n if (vm.card.isNew) {\n // Cancelling the creation of a card\n vm.card = null;\n delete AddressBook.selectedFolder.selectedCard;\n $state.go('app.addressbook', { addressbookId: AddressBook.selectedFolder.id });\n }\n else {\n // Cancelling the edition of an existing card\n $state.go('app.addressbook.card.view', { cardId: vm.card.id });\n }\n }\n function confirmDelete(card) {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the card of %{0}?', '' + card.$fullname() + ''),\n { ok: l('Delete') })\n .then(function() {\n // User confirmed the deletion\n AddressBook.selectedFolder.$deleteCards([card])\n .then(function() {\n close();\n }, function(data, status) {\n Dialog.alert(l('Warning'), l('An error occured while deleting the card \"%{0}\".',\n card.$fullname()));\n });\n });\n }\n\n function toggleRawSource($event) {\n if (!vm.showRawSource && !vm.rawSource) {\n Card.$$resource.post(vm.currentFolder.id + '/' + vm.card.id, \"raw\").then(function(data) {\n vm.rawSource = data;\n vm.showRawSource = true;\n });\n }\n else {\n vm.showRawSource = !vm.showRawSource;\n }\n }\n }\n\n angular\n .module('SOGo.ContactsUI')\n .controller('CardController', CardController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name sgAddress\n * @memberof ContactsUI\n * @desc Directive to format a postal address.\n * @ngInject\n */\n function sgAddress() {\n return {\n restrict: 'A',\n scope: { data: '=sgAddress' },\n controller: ['$scope', function($scope) {\n $scope.addressLines = function(data) {\n var lines = [],\n locality_region = [];\n if (data.street) lines.push(data.street);\n if (data.street2) lines.push(data.street2);\n if (data.locality) locality_region.push(data.locality);\n if (data.region) locality_region.push(data.region);\n if (locality_region.length > 0) lines.push(locality_region.join(', '));\n if (data.country) lines.push(data.country);\n if (data.postalcode) lines.push(data.postalcode);\n return lines.join('
');\n };\n }],\n template: '
'\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgAddress', sgAddress);\n})();\n"]} \ No newline at end of file +{"version":3,"sources":["Contacts/Contacts.app.js","Contacts/AddressBookController.js","Contacts/AddressBooksController.js","Contacts/CardController.js","Contacts/sgAddress.directive.js"],"names":["configure","$stateProvider","$urlRouterProvider","state","url","abstract","views","addressbooks","templateUrl","controller","controllerAs","resolve","stateAddressbooks","addressbook","stateAddressbook","card","stateCard","stateNewCard","template","onEnter","onEnterCard","onExit","onExitCard","card@app.addressbook","otherwise","AddressBook","$findAll","window","contactFolders","$q","$state","$stateParams","_","find","id","addressbookId","selectedCard","$reload","reject","Card","tag","contactType","pid","c_component","$cards","cardObject","cardId","go","stateMailbox","runBlock","$rootScope","$log","$on","event","toState","toParams","fromState","fromParams","error","current","previous","rejection","angular","module","config","run","$inject","AddressBookController","$scope","$window","$timeout","$mdDialog","$mdToast","Account","Dialog","Settings","selectCard","toggleCardSelection","$event","selected","vm","mode","multiple","preventDefault","stopPropagation","newComponent","type","unselectCards","forEach","selectedFolder","confirmDeleteSelectedCards","confirm","l","ok","then","selectedCards","filter","$deleteCards","_selectedCardsOperation","operation","dstId","srcFolder","allCards","cards","ids","clearCardView","promise","success","$selectedCards","$isCard","length","show","simple","content","position","hideDelay","$copyCards","$moveCards","map","indexOf","copySelectedCards","folder","moveSelectedCards","selectAll","sort","field","$filter","sortedBy","$query","cancelSearch","search","newMessage","recipients","accounts","account","o","$getMailboxes","mailboxes","$newMessage","message","extend","editable","to","parent","element","document","body","targetEvent","clickOutsideToClose","escapeToClose","locals","stateAccount","stateMessage","newMessageWithRecipient","recipient","fn","newMessageWithSelectedCards","promises","$isList","expandable","isDefined","refs","ref","email","push","$shortFormat","c_mail","all","uniq","this","service","AddressBooksController","$mdMedia","$mdSidenav","FileUploader","sgConstant","focus","User","select","params","editMode","value","close","newAddressbook","prompt","name","isEditable","isRemote","owner","UserLogin","$add","edit","originalAddressbook","$omit","revertEditing","save","$rename","data","status","alert","confirmDelete","isSubscription","$delete","catch","response","statusText","importCards","CardsImportDialogController","scope","filterByExtension","item","isTextFile","test","join","uploader","ApplicationBaseURL","autoUpload","queueLimit","filters","onSuccessItem","headers","msg","hide","imported","onErrorItem","showLinks","LinksDialogController","showProperties","PropertiesDialogController","srcAddressBook","saveProperties","$save","init","cancel","share","$acl","$users","usersWithACL","users","subscribeToFolder","addressbookData","console","debug","$subscribe","isDroppableFolder","dstFolder","isOwned","acls","objectCreator","dragSelectedCards","$selectedCard","activeUser","CardController","transformCategory","input","isString","addOrgUnit","i","$addOrgUnit","addBirthday","birthday","Date","addScreenName","$addScreenName","addEmail","$addEmail","addPhone","$addPhone","addUrl","$addUrl","addAddress","$addAddress","userFilter","excludedCards","dry","excludeLists","$$cards","form","$valid","copy","reset","$reset","isNew","$fullname","toggleRawSource","showRawSource","rawSource","$$resource","post","currentFolder","allEmailTypes","$EMAIL_TYPES","allTelTypes","$TEL_TYPES","allUrlTypes","$URL_TYPES","allAddressTypes","$ADDRESS_TYPES","categories","userFilterResults","sgAddress","restrict","addressLines","lines","locality_region","street","street2","locality","region","country","postalcode","directive"],"mappings":"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","file":"Contacts.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n/* JavaScript for SOGoContacts */\n\n(function() {\n 'use strict';\n\n angular.module('SOGo.ContactsUI', ['ngCookies', 'ui.router', 'angularFileUpload', 'ck', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.MailerUI'])\n .config(configure)\n .run(runBlock);\n\n /**\n * @ngInject\n */\n configure.$inject = ['$stateProvider', '$urlRouterProvider'];\n function configure($stateProvider, $urlRouterProvider) {\n $stateProvider\n .state('app', {\n url: '/addressbooks',\n abstract: true,\n views: {\n addressbooks: {\n templateUrl: 'UIxContactFoldersView', // UI/Templates/Contacts/UIxContactFoldersView.wox\n controller: 'AddressBooksController',\n controllerAs: 'app'\n }\n },\n resolve: {\n stateAddressbooks: stateAddressbooks\n }\n })\n .state('app.addressbook', {\n url: '/:addressbookId',\n views: {\n addressbook: {\n templateUrl: 'addressbook',\n controller: 'AddressBookController',\n controllerAs: 'addressbook'\n }\n },\n resolve: {\n stateAddressbook: stateAddressbook\n }\n })\n .state('app.addressbook.new', {\n url: '/{contactType:(?:card|list)}/new',\n views: {\n card: {\n templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n },\n resolve: {\n stateCard: stateNewCard\n }\n })\n .state('app.addressbook.card', {\n url: '/:cardId',\n abstract: true,\n views: {\n card: {\n template: ''\n }\n },\n resolve: {\n stateCard: stateCard\n },\n onEnter: onEnterCard,\n onExit: onExitCard\n })\n .state('app.addressbook.card.view', {\n url: '/view',\n views: {\n 'card@app.addressbook': {\n templateUrl: 'UIxContactViewTemplate', // UI/Templates/Contacts/UIxContactViewTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n }\n })\n .state('app.addressbook.card.editor', {\n url: '/edit',\n views: {\n 'card@app.addressbook': {\n templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox\n controller: 'CardController',\n controllerAs: 'editor'\n }\n }\n });\n\n // if none of the above states are matched, use this as the fallback\n $urlRouterProvider.otherwise('/addressbooks/personal');\n }\n\n /**\n * @ngInject\n */\n stateAddressbooks.$inject = ['AddressBook'];\n function stateAddressbooks(AddressBook) {\n return AddressBook.$findAll(window.contactFolders);\n }\n\n /**\n * @ngInject\n */\n stateAddressbook.$inject = ['$q', '$state', '$stateParams', 'AddressBook'];\n function stateAddressbook($q, $state, $stateParams, AddressBook) {\n var addressbook = _.find(AddressBook.$findAll(), function(addressbook) {\n return addressbook.id == $stateParams.addressbookId;\n });\n if (addressbook) {\n delete addressbook.selectedCard;\n addressbook.$reload();\n return addressbook;\n }\n return $q.reject('Addressbook ' + $stateParams.addressbookId + ' not found');\n }\n\n /**\n * @ngInject\n */\n stateNewCard.$inject = ['$stateParams', 'stateAddressbook', 'Card'];\n function stateNewCard($stateParams, stateAddressbook, Card) {\n var tag = 'v' + $stateParams.contactType,\n card = new Card({ pid: $stateParams.addressbookId, c_component: tag });\n stateAddressbook.selectedCard = true;\n return card;\n }\n\n /**\n * @ngInject\n */\n stateCard.$inject = ['$state', '$stateParams', 'stateAddressbook'];\n function stateCard($state, $stateParams, stateAddressbook) {\n var card;\n\n card = _.find(stateAddressbook.$cards, function(cardObject) {\n return (cardObject.id == $stateParams.cardId);\n });\n\n if (card) {\n return card.$reload();\n }\n else {\n // Card not found\n $state.go('app.addressbook');\n }\n }\n\n /**\n * @ngInject\n */\n onEnterCard.$inject = ['$stateParams', 'stateAddressbook'];\n function onEnterCard($stateParams, stateAddressbook) {\n stateAddressbook.selectedCard = $stateParams.cardId;\n }\n\n /**\n * @ngInject\n */\n onExitCard.$inject = ['stateAddressbook'];\n function onExitCard(stateMailbox) {\n delete stateAddressbook.selectedCard;\n }\n\n /**\n * @ngInject\n */\n runBlock.$inject = ['$rootScope', '$log', '$state'];\n function runBlock($rootScope, $log, $state) {\n $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {\n $log.error(error);\n $state.go('app.addressbook', { addressbookId: 'personal' });\n });\n $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {\n $log.error(event, current, previous, rejection);\n });\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n AddressBookController.$inject = ['$scope', '$q', '$window', '$state', '$timeout', '$mdDialog', '$mdToast', 'Account', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'stateAddressbooks', 'stateAddressbook'];\n function AddressBookController($scope, $q, $window, $state, $timeout, $mdDialog, $mdToast, Account, Card, AddressBook, Dialog, Settings, stateAddressbooks, stateAddressbook) {\n var vm = this;\n\n AddressBook.selectedFolder = stateAddressbook;\n\n vm.service = AddressBook;\n vm.selectedFolder = stateAddressbook;\n vm.selectCard = selectCard;\n vm.toggleCardSelection = toggleCardSelection;\n vm.newComponent = newComponent;\n vm.unselectCards = unselectCards;\n vm.confirmDeleteSelectedCards = confirmDeleteSelectedCards;\n vm.copySelectedCards = copySelectedCards;\n vm.moveSelectedCards = moveSelectedCards;\n vm.selectAll = selectAll;\n vm.sort = sort;\n vm.sortedBy = sortedBy;\n vm.cancelSearch = cancelSearch;\n vm.newMessage = newMessage;\n vm.newMessageWithSelectedCards = newMessageWithSelectedCards;\n vm.newMessageWithRecipient = newMessageWithRecipient;\n vm.mode = { search: false, multiple: 0 };\n \n function selectCard(card) {\n $state.go('app.addressbook.card.view', {cardId: card.id});\n }\n \n function toggleCardSelection($event, card) {\n card.selected = !card.selected;\n vm.mode.multiple += card.selected? 1 : -1;\n $event.preventDefault();\n $event.stopPropagation();\n }\n\n function newComponent(type) {\n $state.go('app.addressbook.new', { contactType: type });\n }\n\n function unselectCards() {\n _.forEach(vm.selectedFolder.$cards, function(card) {\n card.selected = false;\n });\n vm.mode.multiple = 0;\n }\n \n function confirmDeleteSelectedCards() {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the selected contacts?'),\n { ok: l('Delete') })\n .then(function() {\n // User confirmed the deletion\n var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });\n vm.selectedFolder.$deleteCards(selectedCards).then(function() {\n vm.mode.multiple = 0;\n if (!vm.selectedFolder.selectedCard)\n $state.go('app.addressbook');\n });\n });\n }\n\n /**\n * @see AddressBooksController.dragSelectedCards\n */\n function _selectedCardsOperation(operation, dstId) {\n var srcFolder, allCards, cards, ids, clearCardView, promise, success;\n\n srcFolder = vm.selectedFolder;\n clearCardView = false;\n allCards = srcFolder.$selectedCards();\n cards = _.filter(allCards, function(card) {\n return card.$isCard();\n });\n\n if (cards.length != allCards.length)\n $mdToast.show(\n $mdToast.simple()\n .content(l(\"Lists can't be moved or copied.\"))\n .position('top right')\n .hideDelay(2000));\n\n if (cards.length) {\n if (operation == 'copy') {\n promise = srcFolder.$copyCards(cards, dstId);\n success = l('%{0} card(s) copied', cards.length);\n }\n else {\n promise = srcFolder.$moveCards(cards, dstId);\n success = l('%{0} card(s) moved', cards.length);\n // Check if currently displayed card will be moved\n ids = _.map(cards, 'id');\n clearCardView = (srcFolder.selectedCard && ids.indexOf(srcFolder.selectedCard) >= 0);\n }\n\n // Show success toast when action succeeds\n promise.then(function() {\n if (clearCardView)\n $state.go('app.addressbook');\n $mdToast.show(\n $mdToast.simple()\n .content(success)\n .position('top right')\n .hideDelay(2000));\n });\n }\n }\n\n function copySelectedCards(folder) {\n _selectedCardsOperation('copy', folder);\n }\n\n function moveSelectedCards(folder) {\n _selectedCardsOperation('move', folder);\n }\n\n function selectAll() {\n _.forEach(vm.selectedFolder.$cards, function(card) {\n card.selected = true;\n });\n vm.mode.multiple = vm.selectedFolder.$cards.length;\n }\n\n function sort(field) {\n vm.selectedFolder.$filter('', { sort: field });\n }\n\n function sortedBy(field) {\n return AddressBook.$query.sort == field;\n }\n\n function cancelSearch() {\n vm.mode.search = false;\n vm.selectedFolder.$filter('');\n }\n\n function newMessage($event, recipients) {\n Account.$findAll().then(function(accounts) {\n var account = _.find(accounts, function(o) {\n if (o.id === 0)\n return o;\n });\n\n // We must initialize the Account with its mailbox\n // list before proceeding with message's creation\n account.$getMailboxes().then(function(mailboxes) {\n account.$newMessage().then(function(message) {\n angular.extend(message.editable, { to: recipients });\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: false,\n escapeToClose: false,\n templateUrl: '../Mail/UIxMailEditor',\n controller: 'MessageEditorController',\n controllerAs: 'editor',\n locals: {\n stateAccount: account,\n stateMessage: message\n }\n });\n });\n });\n });\n }\n\n function newMessageWithRecipient($event, recipient, fn) {\n var recipients = [fn + ' <' + recipient + '>'];\n vm.newMessage($event, recipients);\n $event.stopPropagation();\n $event.preventDefault();\n }\n\n function newMessageWithSelectedCards($event) {\n var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });\n var promises = [], recipients = [];\n\n _.forEach(selectedCards, function(card) {\n if (card.$isList({expandable: true})) {\n // If the list's members were already fetch, use them\n if (angular.isDefined(card.refs) && card.refs.length) {\n _.forEach(card.refs, function(ref) {\n if (ref.email.length)\n recipients.push(ref.$shortFormat());\n });\n }\n else {\n promises.push(card.$reload().then(function(card) {\n _.forEach(card.refs, function(ref) {\n if (ref.email.length)\n recipients.push(ref.$shortFormat());\n });\n }));\n }\n }\n else if (card.c_mail.length) {\n recipients.push(card.$shortFormat());\n }\n });\n\n $q.all(promises).then(function() {\n recipients = _.uniq(recipients);\n if (recipients.length)\n vm.newMessage($event, recipients);\n });\n }\n }\n\n angular\n .module('SOGo.ContactsUI') \n .controller('AddressBookController', AddressBookController); \n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n AddressBooksController.$inject = ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$window', '$mdDialog', '$mdToast', '$mdMedia', '$mdSidenav', 'FileUploader', 'sgConstant', 'sgFocus', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'User', 'stateAddressbooks'];\n function AddressBooksController($state, $scope, $rootScope, $stateParams, $timeout, $window, $mdDialog, $mdToast, $mdMedia, $mdSidenav, FileUploader, sgConstant, focus, Card, AddressBook, Dialog, Settings, User, stateAddressbooks) {\n var vm = this;\n\n vm.activeUser = Settings.activeUser;\n vm.service = AddressBook;\n vm.select = select;\n vm.newAddressbook = newAddressbook;\n vm.edit = edit;\n vm.revertEditing = revertEditing;\n vm.save = save;\n vm.confirmDelete = confirmDelete;\n vm.importCards = importCards;\n vm.showLinks = showLinks;\n vm.showProperties = showProperties;\n vm.share = share;\n vm.subscribeToFolder = subscribeToFolder;\n vm.isDroppableFolder = isDroppableFolder;\n vm.dragSelectedCards = dragSelectedCards;\n\n function select($event, folder) {\n if ($state.params.addressbookId != folder.id &&\n vm.editMode != folder.id) {\n vm.editMode = false;\n AddressBook.$query.value = '';\n // Close sidenav on small devices\n if (!$mdMedia(sgConstant['gt-md']))\n $mdSidenav('left').close();\n $state.go('app.addressbook', {addressbookId: folder.id});\n }\n else {\n $event.preventDefault();\n $event.stopPropagation();\n }\n }\n\n function newAddressbook() {\n Dialog.prompt(l('New addressbook'),\n l('Name of new addressbook'))\n .then(function(name) {\n var addressbook = new AddressBook(\n {\n name: name,\n isEditable: true,\n isRemote: false,\n owner: UserLogin\n }\n );\n AddressBook.$add(addressbook);\n });\n }\n\n function edit(folder) {\n if (!folder.isRemote) {\n vm.editMode = folder.id;\n vm.originalAddressbook = angular.extend({}, folder.$omit());\n focus('addressBookName_' + folder.id);\n }\n }\n\n function revertEditing(folder) {\n folder.name = vm.originalAddressbook.name;\n vm.editMode = false;\n }\n\n function save(folder) {\n var name = folder.name;\n if (name && name.length > 0 && name != vm.originalAddressbook.name) {\n folder.$rename(name)\n .then(function(data) {\n vm.editMode = false;\n }, function(data, status) {\n Dialog.alert(l('Warning'), data);\n });\n }\n }\n\n function confirmDelete() {\n if (vm.service.selectedFolder.isSubscription) {\n // Unsubscribe without confirmation\n vm.service.selectedFolder.$delete()\n .then(function() {\n vm.service.selectedFolder = null;\n $state.go('app.addressbook', { addressbookId: 'personal' });\n }, function(data, status) {\n Dialog.alert(l('An error occured while deleting the addressbook \"%{0}\".',\n vm.service.selectedFolder.name),\n l(data.error));\n });\n }\n else {\n Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook \"%{0}\"?',\n vm.service.selectedFolder.name),\n { ok: l('Delete') })\n .then(function() {\n return vm.service.selectedFolder.$delete();\n })\n .then(function() {\n vm.service.selectedFolder = null;\n $state.go('app.addressbook', { addressbookId: 'personal' });\n return true;\n })\n .catch(function(response) {\n var message = response.data.message || response.statusText;\n Dialog.alert(l('An error occured while deleting the addressbook \"%{0}\".',\n vm.service.selectedFolder.name),\n message);\n });\n }\n }\n\n function importCards($event, folder) {\n $mdDialog.show({\n parent: angular.element(document.body),\n targetEvent: $event,\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: 'UIxContactsImportDialog',\n controller: CardsImportDialogController,\n controllerAs: '$CardsImportDialogController',\n locals: {\n folder: folder\n }\n });\n\n /**\n * @ngInject\n */\n CardsImportDialogController.$inject = ['scope', '$mdDialog', 'folder'];\n function CardsImportDialogController(scope, $mdDialog, folder) {\n var vm = this;\n\n vm.uploader = new FileUploader({\n url: ApplicationBaseURL + [folder.id, 'import'].join('/'),\n autoUpload: true,\n queueLimit: 1,\n filters: [{ name: filterByExtension, fn: filterByExtension }],\n onSuccessItem: function(item, response, status, headers) {\n var msg;\n\n $mdDialog.hide();\n\n if (response.imported === 0)\n msg = l('No card was imported.');\n else {\n msg = l('A total of %{0} cards were imported in the addressbook.', response.imported);\n AddressBook.selectedFolder.$reload();\n }\n\n $mdToast.show(\n $mdToast.simple()\n .content(msg)\n .position('top right')\n .hideDelay(3000));\n },\n onErrorItem: function(item, response, status, headers) {\n $mdToast.show({\n template: [\n '',\n '
',\n ' error_outline',\n ' ' + l('An error occured while importing contacts.') + '',\n '
',\n '
'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n }\n });\n\n vm.close = function() {\n $mdDialog.hide();\n };\n\n function filterByExtension(item) {\n var isTextFile = item.type.indexOf('text') === 0 ||\n /\\.(ldif|vcf|vcard)$/.test(item.name);\n\n if (!isTextFile)\n $mdToast.show({\n template: [\n '',\n '
',\n ' error_outline',\n ' ' + l('Select a vCard or LDIF file.') + '',\n '
',\n '
'\n ].join(''),\n position: 'top right',\n hideDelay: 3000\n });\n\n return isTextFile;\n }\n }\n }\n\n function showLinks(addressbook) {\n $mdDialog.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n templateUrl: addressbook.id + '/links',\n controller: LinksDialogController,\n controllerAs: 'links',\n locals: {\n addressbook: addressbook\n }\n });\n\n /**\n * @ngInject\n */\n LinksDialogController.$inject = ['$mdDialog', 'addressbook'];\n function LinksDialogController($mdDialog, addressbook) {\n var vm = this;\n this.addressbook = addressbook;\n this.close = close;\n\n function close() {\n $mdDialog.hide();\n }\n }\n }\n\n function showProperties(addressbook) {\n $mdDialog.show({\n templateUrl: addressbook.id + '/properties',\n controller: PropertiesDialogController,\n controllerAs: 'properties',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n srcAddressBook: addressbook\n }\n }).catch(function() {\n // Do nothing\n });\n\n /**\n * @ngInject\n */\n PropertiesDialogController.$inject = ['$scope', '$mdDialog', 'srcAddressBook'];\n function PropertiesDialogController($scope, $mdDialog, srcAddressBook) {\n var vm = this;\n\n vm.addressbook = new AddressBook(srcAddressBook.$omit());\n vm.saveProperties = saveProperties;\n vm.close = close;\n\n function saveProperties() {\n vm.addressbook.$save().then(function() {\n // Refresh list instance\n srcAddressBook.init(vm.addressbook.$omit());\n $mdDialog.hide();\n });\n }\n\n function close() {\n $mdDialog.cancel();\n }\n }\n }\n\n function share(addressbook) {\n // Fetch list of ACL users\n addressbook.$acl.$users().then(function() {\n // Show ACL editor\n $mdDialog.show({\n templateUrl: addressbook.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox\n controller: 'AclController', // from the ng module SOGo.Common\n controllerAs: 'acl',\n clickOutsideToClose: true,\n escapeToClose: true,\n locals: {\n usersWithACL: addressbook.$acl.users,\n User: User,\n folder: addressbook\n }\n });\n });\n }\n\n /**\n * subscribeToFolder - Callback of sgSubscribe directive\n */\n function subscribeToFolder(addressbookData) {\n console.debug('subscribeToFolder ' + addressbookData.owner + addressbookData.name);\n AddressBook.$subscribe(addressbookData.owner, addressbookData.name).then(function(data) {\n $mdToast.show(\n $mdToast.simple()\n .content(l('Successfully subscribed to address book'))\n .position('top right')\n .hideDelay(3000));\n });\n }\n\n function isDroppableFolder(srcFolder, dstFolder) {\n return (dstFolder.id != srcFolder.id) && (dstFolder.isOwned || dstFolder.acls.objectCreator);\n }\n\n /**\n * @see AddressBookController._selectedCardsOperation\n */\n function dragSelectedCards(srcFolder, dstFolder, mode) {\n var dstId, allCards, cards, ids, clearCardView, promise, success;\n\n dstId = dstFolder.id;\n clearCardView = false;\n allCards = srcFolder.$selectedCards();\n if (allCards.length === 0)\n allCards = [srcFolder.$selectedCard()];\n cards = _.filter(allCards, function(card) {\n return card.$isCard();\n });\n\n if (cards.length != allCards.length)\n $mdToast.show(\n $mdToast.simple()\n .content(l(\"Lists can't be moved or copied.\"))\n .position('top right')\n .hideDelay(2000));\n\n if (cards.length) {\n if (mode == 'copy') {\n promise = srcFolder.$copyCards(cards, dstId);\n success = l('%{0} card(s) copied', cards.length);\n }\n else {\n promise = srcFolder.$moveCards(cards, dstId);\n success = l('%{0} card(s) moved', cards.length);\n // Check if currently displayed card will be moved\n ids = _.map(cards, 'id');\n clearCardView = (srcFolder.selectedCard && ids.indexOf(srcFolder.selectedCard) >= 0);\n }\n\n // Show success toast when action succeeds\n promise.then(function() {\n if (clearCardView)\n $state.go('app.addressbook');\n $mdToast.show(\n $mdToast.simple()\n .content(success)\n .position('top right')\n .hideDelay(2000));\n });\n }\n }\n\n }\n\n angular\n .module('SOGo.ContactsUI')\n .controller('AddressBooksController', AddressBooksController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * Controller to view and edit a card\n * @ngInject\n */\n CardController.$inject = ['$scope', '$timeout', '$window', '$mdDialog', 'AddressBook', 'Card', 'Dialog', 'sgFocus', '$state', '$stateParams', 'stateCard'];\n function CardController($scope, $timeout, $window, $mdDialog, AddressBook, Card, Dialog, focus, $state, $stateParams, stateCard) {\n var vm = this;\n\n vm.card = stateCard;\n\n vm.currentFolder = AddressBook.selectedFolder;\n vm.allEmailTypes = Card.$EMAIL_TYPES;\n vm.allTelTypes = Card.$TEL_TYPES;\n vm.allUrlTypes = Card.$URL_TYPES;\n vm.allAddressTypes = Card.$ADDRESS_TYPES;\n vm.categories = {};\n vm.userFilterResults = [];\n vm.transformCategory = transformCategory;\n vm.addOrgUnit = addOrgUnit;\n vm.addBirthday = addBirthday;\n vm.addScreenName = addScreenName;\n vm.addEmail = addEmail;\n vm.addPhone = addPhone;\n vm.addUrl = addUrl;\n vm.addAddress = addAddress;\n vm.userFilter = userFilter;\n vm.save = save;\n vm.close = close;\n vm.reset = reset;\n vm.cancel = cancel;\n vm.confirmDelete = confirmDelete;\n vm.toggleRawSource = toggleRawSource;\n vm.showRawSource = false;\n\n function transformCategory(input) {\n if (angular.isString(input))\n return { value: input };\n else\n return input;\n }\n function addOrgUnit() {\n var i = vm.card.$addOrgUnit('');\n focus('orgUnit_' + i);\n }\n function addBirthday() {\n vm.card.birthday = new Date();\n }\n function addScreenName() {\n vm.card.$addScreenName('');\n }\n function addEmail() {\n var i = vm.card.$addEmail('');\n focus('email_' + i);\n }\n function addPhone() {\n var i = vm.card.$addPhone('');\n focus('phone_' + i);\n }\n function addUrl() {\n var i = vm.card.$addUrl('', '');\n focus('url_' + i);\n }\n function addAddress() {\n var i = vm.card.$addAddress('', '', '', '', '', '', '', '');\n focus('address_' + i);\n }\n function userFilter($query, excludedCards) {\n AddressBook.selectedFolder.$filter($query, {dry: true, excludeLists: true}, excludedCards);\n return AddressBook.selectedFolder.$$cards;\n }\n function save(form) {\n if (form.$valid) {\n vm.card.$save()\n .then(function(data) {\n var i = _.indexOf(_.map(AddressBook.selectedFolder.$cards, 'id'), vm.card.id);\n if (i < 0) {\n // New card; reload contacts list and show addressbook in which the card has been created\n AddressBook.selectedFolder.$reload();\n }\n else {\n // Update contacts list with new version of the Card object\n AddressBook.selectedFolder.$cards[i] = angular.copy(vm.card);\n }\n $state.go('app.addressbook.card.view', { cardId: vm.card.id });\n });\n }\n }\n function close() {\n $state.go('app.addressbook').then(function() {\n vm.card = null;\n delete AddressBook.selectedFolder.selectedCard;\n });\n }\n function reset() {\n vm.card.$reset();\n }\n function cancel() {\n vm.card.$reset();\n if (vm.card.isNew) {\n // Cancelling the creation of a card\n vm.card = null;\n delete AddressBook.selectedFolder.selectedCard;\n $state.go('app.addressbook', { addressbookId: AddressBook.selectedFolder.id });\n }\n else {\n // Cancelling the edition of an existing card\n $state.go('app.addressbook.card.view', { cardId: vm.card.id });\n }\n }\n function confirmDelete(card) {\n Dialog.confirm(l('Warning'),\n l('Are you sure you want to delete the card of %{0}?', '' + card.$fullname() + ''),\n { ok: l('Delete') })\n .then(function() {\n // User confirmed the deletion\n AddressBook.selectedFolder.$deleteCards([card])\n .then(function() {\n close();\n }, function(data, status) {\n Dialog.alert(l('Warning'), l('An error occured while deleting the card \"%{0}\".',\n card.$fullname()));\n });\n });\n }\n\n function toggleRawSource($event) {\n if (!vm.showRawSource && !vm.rawSource) {\n Card.$$resource.post(vm.currentFolder.id + '/' + vm.card.id, \"raw\").then(function(data) {\n vm.rawSource = data;\n vm.showRawSource = true;\n });\n }\n else {\n vm.showRawSource = !vm.showRawSource;\n }\n }\n }\n\n angular\n .module('SOGo.ContactsUI')\n .controller('CardController', CardController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name sgAddress\n * @memberof ContactsUI\n * @desc Directive to format a postal address.\n * @ngInject\n */\n function sgAddress() {\n return {\n restrict: 'A',\n scope: { data: '=sgAddress' },\n controller: ['$scope', function($scope) {\n $scope.addressLines = function(data) {\n var lines = [],\n locality_region = [];\n if (data.street) lines.push(data.street);\n if (data.street2) lines.push(data.street2);\n if (data.locality) locality_region.push(data.locality);\n if (data.region) locality_region.push(data.region);\n if (locality_region.length > 0) lines.push(locality_region.join(', '));\n if (data.country) lines.push(data.country);\n if (data.postalcode) lines.push(data.postalcode);\n return lines.join('
');\n };\n }],\n template: '
'\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgAddress', sgAddress);\n})();\n"]} \ No newline at end of file diff --git a/UI/WebServerResources/js/Contacts.services.js b/UI/WebServerResources/js/Contacts.services.js index 2ad995461..43810c8a4 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(a){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(_.mapKeys(c,function(a,b){return b.toLowerCase()}),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.$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&&a0&&(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(e){var g,h,i,j,k,l=f.$$cards,m=function(a){return this==a.id};for(e.headers&&(j=_.invokeMap(e.headers[0],"toLowerCase"),k=j.indexOf("id"),e.headers.splice(0,1)),g=d?_.filter(e.ids,function(a){return _.isUndefined(_.find(d,_.bind(m,a)))}):e.ids,i=l.length-1;i>=0;i--)h=l[i],_.isUndefined(_.find(g,_.bind(m,h.id)))&&l.splice(i,1);return _.forEach(g,function(d,e){if(_.isUndefined(_.find(l,_.bind(m,d)))){var f={pid:c,id:d},g=new a.$Card(f,b);l.splice(e,0,g)}}),_.forEach(g,function(a,b){var c,d;l[b].id!=a&&(c=_.findIndex(l,_.bind(m,a)),d=l.splice(c,1),l.splice(b,0,d[0]))}),_.forEach(e.headers,function(a){var c,d=_.findIndex(l,_.bind(m,a[k]));d>-1&&(c=_.zipObject(j,a),l[d].init(c,b))}),f.$isLoading=!1,l}):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(){_.forEachRight(c.$cards,function(a,b){var e=_.findIndex(d,function(b){return a.id==b});e>-1?(d.splice(e,1),delete c.idsMap[a.id],c.isSelectedCard(a.id)&&delete c.selectedCard,c.$cards.splice(b,1)):c.idsMap[a.id]-=d.length})})},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.exportCards=function(b){var c;if(b){var d=_.filter(this.$cards,function(a){return a.selected});c=_.map(d,"id")}return a.$$resource.download(this.id,"export",angular.isDefined(c)?{uids:c}:null,{type:"application/octet-stream"})},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={pid:c.id,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);angular.extend(e,{pid:c.id}),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",function(b,c,d,e,f){return angular.extend(a,{STATUS:d,$$resource:new e(c.activeUser("folderURL")+"Contacts",c.activeUser()),$timeout:b,$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(a){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgCard_STATUS",{NOT_LOADED:0,DELAYED_LOADING:1,LOADING:2,LOADED:3,DELAYED_MS:300}).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 a.search(c)!=-1}),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){var d=this;this.refs=[],this.categories=[],this.notes=[this.note],this.c_screenname=null,angular.extend(this,b),this.$$fullname||(this.$$fullname=this.$fullname()),this.$$email||(this.$$email=this.$preferredEmail(c)),this.$$image||(this.$$image=this.image),this.$$image||a.$Preferences.avatar(this.$$email,32,{no_404:!0}).then(function(a){d.$$image=a}),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.$isLoading=function(){return this.$loaded==a.STATUS.LOADING},a.prototype.$reload=function(){var b;return this.$futureCardData?this:(b=a.$$resource.fetch([this.pid,this.id].join("/"),"view"),this.$unwrap(b))},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.export=function(){var b;return b=[this.id],a.$$resource.download(this.pid,"export",{uids:b},{type:"application/octet-stream"})},a.prototype.$fullname=function(a){var b,c,d=this.c_cn||"",e=a&&a.html;return 0===d.length&&(c=[],this.c_givenname&&this.c_givenname.length>0&&c.push(this.c_givenname),this.nickname&&this.nickname.length>0&&c.push((e?"":"")+this.nickname+(e?"":"")),this.c_sn&&this.c_sn.length>0&&c.push(this.c_sn),c.length>0?d=c.join(" "):this.c_org&&this.c_org.length>0?d=this.c_org:this.emails&&this.emails.length>0&&(b=_.find(this.emails,function(a){return""!==a.value}),b&&(d=b.value))),d},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:this.c_mail&&this.c_mail.length?this.c_mail[0]:""),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(a){var b=!a||!a.expandable||a.expandable&&!this.isgroup;return"vlist"==this.c_component&&b},a.prototype.$addOrgUnit=function(a){if(angular.isUndefined(this.orgUnits))this.orgUnits=[{value:a}];else{for(var b=0;b1?(b=this.$omit(),_.forEach(this.emails,function(d){var e=new a(angular.extend({},b,{emails:[d]}));c.push(e)}),c):[this]},a.prototype.$reset=function(){var b=this;angular.forEach(this,function(a,c){"constructor"!=c&&"$"!=c[0]&&delete b[c]}),angular.extend(this,this.$shadowData),angular.forEach(this.refs,function(c,d){c.email&&(c.emails=[{value:c.email}]),b.refs[d]=new a(c)}),this.$shadowData=this.$omit(!0)},a.prototype.$unwrap=function(b){var c=this;return this.$loaded=a.STATUS.DELAYED_LOADING,a.$timeout(function(){c.$loaded!=a.STATUS.LOADED&&(c.$loaded=a.STATUS.LOADING)},a.STATUS.DELAYED_MS),this.$futureCardData=b.then(function(b){return c.init(b),angular.forEach(c.refs,function(b,d){b.email&&(b.emails=[{value:b.email}]),b.id=b.reference,c.refs[d]=new a(b)}),c.birthday&&a.$Preferences.ready().then(function(){var b=a.$Preferences.$mdDateLocaleProvider;c.birthday=c.birthday.parseDate(b,"%Y-%m-%d"),c.$birthday=b.formatDate(c.birthday)}),c.$loaded=a.STATUS.LOADED,c.$shadowData=c.$omit(!0),c}),this.$futureCardData},a.prototype.$omit=function(b){var c={};return angular.forEach(this,function(a,d){"refs"==d?c.refs=_.map(a,function(a){return a.$omit(b)}):"constructor"!=d&&"$"!=d[0]&&(b?c[d]=angular.copy(a):c[d]=a)}),b||(c.birthday?c.birthday=c.birthday.format(a.$Preferences.$mdDateLocaleProvider,"%Y-%m-%d"):c.birthday=""),c},a.prototype.toString=function(){var a=this.id+" "+this.$$fullname;return this.$$email&&(a+=" <"+this.$$email+">"),"["+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(a){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(_.mapKeys(c,function(a,b){return b.toLowerCase()}),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.$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&&a0&&(f=a.$$resource.post(this.id,"headers",{ids:e}),this.$unwrapHeaders(f))}return j},a.prototype.hasSelectedCard=function(){return angular.isDefined(this.selectedCard)},a.prototype.isSelectedCard=function(a){return this.hasSelectedCard()&&this.selectedCard==a},a.prototype.$selectedCard=function(){var a=this;return _.find(this.$cards,function(b){return b.id==a.selectedCard})},a.prototype.$selectedCards=function(){return _.filter(this.$cards,function(a){return a.selected})},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(e){var g,h,i,j,k,l=f.$$cards,m=function(a){return this==a.id};for(e.headers&&(j=_.invokeMap(e.headers[0],"toLowerCase"),k=j.indexOf("id"),e.headers.splice(0,1)),g=d?_.filter(e.ids,function(a){return _.isUndefined(_.find(d,_.bind(m,a)))}):e.ids,i=l.length-1;i>=0;i--)h=l[i],_.isUndefined(_.find(g,_.bind(m,h.id)))&&l.splice(i,1);return _.forEach(g,function(d,e){if(_.isUndefined(_.find(l,_.bind(m,d)))){var f={pid:c,id:d},g=new a.$Card(f,b);l.splice(e,0,g)}}),_.forEach(g,function(a,b){var c,d;l[b].id!=a&&(c=_.findIndex(l,_.bind(m,a)),d=l.splice(c,1),l.splice(b,0,d[0]))}),_.forEach(e.headers,function(a){var c,d=_.findIndex(l,_.bind(m,a[k]));d>-1&&(c=_.zipObject(j,a),l[d].init(c,b))}),f.$isLoading=!1,l}):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(a){var b=this;_.forEachRight(this.$cards,function(c,d){var e=_.findIndex(a,function(a){return c.id==a});e>-1?(a.splice(e,1),delete b.idsMap[c.id],b.isSelectedCard(c.id)&&delete b.selectedCard,b.$cards.splice(d,1)):b.idsMap[c.id]-=a.length})},a.prototype.$deleteCards=function(b){var c=this,d=_.map(b,"id");return a.$$resource.post(this.id,"batchDelete",{uids:d}).then(function(){c.$_deleteCards(d)})},a.prototype.$copyCards=function(b,c){var d=_.map(b,"id");return a.$$resource.post(this.id,"copy",{uids:d,folder:c})},a.prototype.$moveCards=function(b,c){var d,e=this;return d=_.map(b,"id"),a.$$resource.post(this.id,"move",{uids:d,folder:c}).then(function(){return e.$_deleteCards(d)})},a.prototype.$save=function(){return a.$$resource.save(this.id,this.$omit()).then(function(a){return a})},a.prototype.exportCards=function(b){var c;if(b){var d=_.filter(this.$cards,function(a){return a.selected});c=_.map(d,"id")}return a.$$resource.download(this.id,"export",angular.isDefined(c)?{uids:c}:null,{type:"application/octet-stream"})},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={pid:c.id,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);angular.extend(e,{pid:c.id}),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",function(b,c,d,e,f){return angular.extend(a,{STATUS:d,$$resource:new e(c.activeUser("folderURL")+"Contacts",c.activeUser()),$timeout:b,$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(a){angular.module("SOGo.ContactsUI",["SOGo.Common","SOGo.PreferencesUI"])}angular.module("SOGo.ContactsUI").constant("sgCard_STATUS",{NOT_LOADED:0,DELAYED_LOADING:1,LOADING:2,LOADED:3,DELAYED_MS:300}).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 a.search(c)!=-1}),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){var d=this;this.refs=[],this.categories=[],this.notes=[this.note],this.c_screenname=null,angular.extend(this,b),this.$$fullname||(this.$$fullname=this.$fullname()),this.$$email||(this.$$email=this.$preferredEmail(c)),this.$$image||(this.$$image=this.image),this.$$image||a.$Preferences.avatar(this.$$email,32,{no_404:!0}).then(function(a){d.$$image=a}),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.$isLoading=function(){return this.$loaded==a.STATUS.LOADING},a.prototype.$reload=function(){var b;return this.$futureCardData?this:(b=a.$$resource.fetch([this.pid,this.id].join("/"),"view"),this.$unwrap(b))},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.export=function(){var b;return b=[this.id],a.$$resource.download(this.pid,"export",{uids:b},{type:"application/octet-stream"})},a.prototype.$fullname=function(a){var b,c,d=this.c_cn||"",e=a&&a.html;return 0===d.length&&(c=[],this.c_givenname&&this.c_givenname.length>0&&c.push(this.c_givenname),this.nickname&&this.nickname.length>0&&c.push((e?"":"")+this.nickname+(e?"":"")),this.c_sn&&this.c_sn.length>0&&c.push(this.c_sn),c.length>0?d=c.join(" "):this.c_org&&this.c_org.length>0?d=this.c_org:this.emails&&this.emails.length>0&&(b=_.find(this.emails,function(a){return""!==a.value}),b&&(d=b.value))),d},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:this.c_mail&&this.c_mail.length?this.c_mail[0]:""),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(a){var b=!a||!a.expandable||a.expandable&&!this.isgroup;return"vlist"==this.c_component&&b},a.prototype.$addOrgUnit=function(a){if(angular.isUndefined(this.orgUnits))this.orgUnits=[{value:a}];else{for(var b=0;b1?(b=this.$omit(),_.forEach(this.emails,function(d){var e=new a(angular.extend({},b,{emails:[d]}));c.push(e)}),c):[this]},a.prototype.$reset=function(){var b=this;angular.forEach(this,function(a,c){"constructor"!=c&&"$"!=c[0]&&delete b[c]}),angular.extend(this,this.$shadowData),angular.forEach(this.refs,function(c,d){c.email&&(c.emails=[{value:c.email}]),b.refs[d]=new a(c)}),this.$shadowData=this.$omit(!0)},a.prototype.$unwrap=function(b){var c=this;return this.$loaded=a.STATUS.DELAYED_LOADING,a.$timeout(function(){c.$loaded!=a.STATUS.LOADED&&(c.$loaded=a.STATUS.LOADING)},a.STATUS.DELAYED_MS),this.$futureCardData=b.then(function(b){return c.init(b),angular.forEach(c.refs,function(b,d){b.email&&(b.emails=[{value:b.email}]),b.id=b.reference,c.refs[d]=new a(b)}),c.birthday&&a.$Preferences.ready().then(function(){var b=a.$Preferences.$mdDateLocaleProvider;c.birthday=c.birthday.parseDate(b,"%Y-%m-%d"),c.$birthday=b.formatDate(c.birthday)}),c.$loaded=a.STATUS.LOADED,c.$shadowData=c.$omit(!0),c}),this.$futureCardData},a.prototype.$omit=function(b){var c={};return angular.forEach(this,function(a,d){"refs"==d?c.refs=_.map(a,function(a){return a.$omit(b)}):"constructor"!=d&&"$"!=d[0]&&(b?c[d]=angular.copy(a):c[d]=a)}),b||(c.birthday?c.birthday=c.birthday.format(a.$Preferences.$mdDateLocaleProvider,"%Y-%m-%d"):c.birthday=""),c},a.prototype.toString=function(){var a=this.id+" "+this.$$fullname;return this.$$email&&(a+=" <"+this.$$email+">"),"["+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 f89ed36cf..f2e2c0779 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","mapKeys","key","toLowerCase","debug","when","$add","addressbook","list","sibling","i","isSubscription","$subscriptions","$addressbooks","o","localeCompare","indexOf","map","$findAll","_this","$remotes","isRemote","push","union","$subscribe","uid","path","userResource","addressbookData","prototype","$$cards","idsMap","isOwned","isSuperUser","owner","login","$id","$futureAddressBookData","getLength","getItemAtIndex","$isLoading","$lastVisibleIndex","Math","max","$loadCard","endIndex","ids","futureHeadersData","cardId","startIndex","loaded","isDefined","$loaded","STATUS","NOT_LOADED","min","LOADED","LOADING","join","post","$unwrapHeaders","isSelectedCard","selectedCard","$selectedCount","count","selected","$startRefreshTimeout","cancel","refreshViewCheck","defaults","SOGoRefreshViewCheck","f","$reload","timeInterval","$filter","query","dry","copy","partial","addressbookId","futureData","fields","idFieldIndex","cards","headers","invokeMap","pid","oldIndex","removedCards","findIndex","zipObject","$rename","$save","$delete","promise","d","defer","remove","resolve","reject","$deleteCards","uids","forEachRight","selectedIndex","$copyCards","folder","save","$omit","exportCards","selectedOnly","selectedUIDs","selectedCards","download","type","$topIndex","reduce","isError","isObject","j","cardHeaders","futureCardData","newCardData","newguid","isNew","$TEL_TYPES","$EMAIL_TYPES","$URL_TYPES","$ADDRESS_TYPES","Card_STATUS","SOGoContactsCategories","$categories","SOGoAlternateAvatar","$alternateAvatar","DELAYED_LOADING","DELAYED_MS","$find","$unwrapCollection","filterCategories","re","RegExp","category","collection","$futureCardData","refs","categories","notes","note","c_screenname","$$fullname","$fullname","$$email","$preferredEmail","$$image","image","avatar","no_404","url","isgroup","c_component","c_name","empty","action","birthday","$birthday","$mdDateLocaleProvider","formatDate","$shadowData","attribute","export","selectedIDs","email","names","fn","c_cn","html","c_givenname","nickname","c_sn","c_org","emails","$description","description","title","role","orgUnits","unit","test","c_mail","$shortFormat","fullname","$isCard","$isList","condition","expandable","$addOrgUnit","orgUnit","$addEmail","$addScreenName","screenName","$addPhone","phones","$addUrl","urls","$addAddress","postoffice","street","street2","locality","region","country","postalcode","addresses","$addMember","explode","$reset","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(_.mapKeys(data, function(value, key) {\n return key.toLowerCase();\n }), search);\n AddressBook.$cards.splice(index, 0, card);\n }\n });\n AddressBook.$log.debug(AddressBook.$cards);\n return AddressBook.$cards;\n });\n };\n\n /**\n * @memberof AddressBook\n * @desc Add a new addressbook to the static list of addressbooks\n * @param {AddressBook} addressbook - an Addressbook object instance\n */\n AddressBook.$add = function(addressbook) {\n // Insert new addressbook at proper index\n var list, sibling, i;\n\n list = addressbook.isSubscription? this.$subscriptions : this.$addressbooks;\n sibling = _.find(list, function(o) {\n return (addressbook.id == 'personal' ||\n (o.id != 'personal' &&\n o.name.localeCompare(addressbook.name) === 1));\n });\n i = sibling ? _.indexOf(_.map(list, 'id'), sibling.id) : 1;\n list.splice(i, 0, addressbook);\n };\n\n /**\n * @memberof AddressBook\n * @desc Set or get the list of addressbooks. Will instantiate a new AddressBook object for each item.\n * @param {array} [data] - the metadata of the addressbooks\n * @returns the list of addressbooks\n */\n AddressBook.$findAll = function(data) {\n var _this = this;\n if (data) {\n this.$addressbooks = [];\n this.$subscriptions = [];\n this.$remotes = [];\n // Instanciate AddressBook objects\n angular.forEach(data, function(o, i) {\n var addressbook = new AddressBook(o);\n if (addressbook.isRemote)\n _this.$remotes.push(addressbook);\n else if (addressbook.isSubscription)\n _this.$subscriptions.push(addressbook);\n else\n _this.$addressbooks.push(addressbook);\n });\n }\n return _.union(this.$addressbooks, this.$subscriptions, this.$remotes);\n };\n\n /**\n * @memberOf AddressBook\n * @desc Subscribe to another user's addressbook and add it to the list of addressbooks.\n * @param {string} uid - user id\n * @param {string} path - path of folder for specified user\n * @returns a promise of the HTTP query result\n */\n AddressBook.$subscribe = function(uid, path) {\n var _this = this;\n return AddressBook.$$resource.userResource(uid).fetch(path, 'subscribe').then(function(addressbookData) {\n var addressbook = new AddressBook(addressbookData);\n if (_.isUndefined(_.find(_this.$subscriptions, function(o) {\n return o.id == addressbookData.id;\n }))) {\n // Not already subscribed\n AddressBook.$add(addressbook);\n }\n return addressbook;\n });\n };\n\n /**\n * @function init\n * @memberof AddressBook.prototype\n * @desc Extend instance with new data and compute additional attributes.\n * @param {object} data - attributes of addressbook\n */\n AddressBook.prototype.init = function(data, options) {\n var _this = this;\n if (!this.$$cards) {\n // Array of cards for \"dry\" searches (see $filter)\n this.$$cards = [];\n }\n this.idsMap = {};\n this.$cards = []; // 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 if (response.headers) {\n // First entry of 'headers' are keys\n fields = _.invokeMap(response.headers[0], 'toLowerCase');\n idFieldIndex = fields.indexOf('id');\n response.headers.splice(0, 1);\n }\n\n if (excludedCards)\n // Remove excluded cards from results\n results = _.filter(response.ids, function(id) {\n return _.isUndefined(_.find(excludedCards, _.bind(compareIds, id)));\n });\n else\n results = response.ids;\n\n // Remove cards that no longer match the search query\n for (index = cards.length - 1; index >= 0; index--) {\n card = cards[index];\n if (_.isUndefined(_.find(results, _.bind(compareIds, card.id)))) {\n cards.splice(index, 1);\n }\n }\n\n // Add new cards matching the search query\n _.forEach(results, function(cardId, index) {\n if (_.isUndefined(_.find(cards, _.bind(compareIds, cardId)))) {\n var data = { pid: addressbookId, id: cardId };\n var card = new AddressBook.$Card(data, search);\n cards.splice(index, 0, card);\n }\n });\n\n // Respect the order of the results\n _.forEach(results, function(cardId, index) {\n var oldIndex, removedCards;\n if (cards[index].id != cardId) {\n oldIndex = _.findIndex(cards, _.bind(compareIds, cardId));\n removedCards = cards.splice(oldIndex, 1);\n cards.splice(index, 0, removedCards[0]);\n }\n });\n\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var card, index = _.findIndex(cards, _.bind(compareIds, data[idFieldIndex]));\n if (index > -1) {\n card = _.zipObject(fields, data);\n cards[index].init(card, search);\n }\n });\n\n _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 // Remove cards from $cards and idsMap\n _.forEachRight(_this.$cards, function(card, index) {\n var selectedIndex = _.findIndex(ids, function(id) {\n return card.id == id;\n });\n if (selectedIndex > -1) {\n ids.splice(selectedIndex, 1);\n delete _this.idsMap[card.id];\n if (_this.isSelectedCard(card.id))\n delete _this.selectedCard;\n _this.$cards.splice(index, 1);\n }\n else {\n _this.idsMap[card.id] -= ids.length;\n }\n });\n });\n };\n\n /**\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 $exportCards\n * @memberof AddressBook.prototype\n * @desc Export the selected/all cards\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.exportCards = function(selectedOnly) {\n var selectedUIDs;\n\n if (selectedOnly) {\n var selectedCards = _.filter(this.$cards, function(card) { return card.selected; });\n selectedUIDs = _.map(selectedCards, 'id');\n }\n\n return AddressBook.$$resource.download(this.id, 'export', (angular.isDefined(selectedUIDs) ? {uids: selectedUIDs} : null), {type: 'application/octet-stream'});\n };\n\n /**\n * @function $unwrap\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and instanciate new Card objects using received data.\n * @param {promise} futureAddressBookData - a promise of the AddressBook's data\n */\n AddressBook.prototype.$unwrap = function(futureAddressBookData) {\n var _this = this;\n\n this.$isLoading = true;\n\n // Expose and resolve the promise\n this.$futureAddressBookData = futureAddressBookData.then(function(response) {\n return AddressBook.$timeout(function() {\n var headers;\n\n if (!response.ids || _this.$topIndex > response.ids.length - 1)\n _this.$topIndex = 0;\n\n // Extend AddressBook instance from data of addressbooks list.\n // Will inherit attributes such as isEditable and isRemote.\n angular.forEach(AddressBook.$findAll(), function(o, i) {\n if (o.id == response.id) {\n angular.extend(_this, o);\n }\n });\n\n // Extend AddressBook instance with received data\n _this.init(response);\n\n if (_this.ids) {\n AddressBook.$log.debug('unwrapping ' + _this.ids.length + ' cards');\n\n // Instanciate Card objects\n _.reduce(_this.ids, function(cards, card, i) {\n var data = { pid: _this.id, id: card };\n\n // Build map of ID <=> index\n _this.idsMap[data.id] = i;\n\n cards.push(new AddressBook.$Card(data));\n\n return cards;\n }, _this.$cards);\n }\n\n if (response.headers) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(response.headers[0], 'toLowerCase');\n response.headers.splice(0, 1);\n\n if (_this.ids) {\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data),\n i = _this.idsMap[o.id];\n _this.$cards[i].init(o);\n });\n }\n else {\n // Instanciate Card objects\n _this.$cards = [];\n angular.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data);\n angular.extend(o, { pid: _this.id });\n _this.$cards.push(new AddressBook.$Card(o));\n });\n }\n }\n\n // Instanciate Acl object\n _this.$acl = new AddressBook.$$Acl('Contacts/' + _this.id);\n\n _this.$startRefreshTimeout();\n\n _this.$isLoading = false;\n\n AddressBook.$log.debug('addressbook ' + _this.id + ' ready');\n\n return _this;\n });\n }, function(data) {\n _this.isError = true;\n if (angular.isObject(data)) {\n AddressBook.$timeout(function() {\n angular.extend(_this, data);\n });\n }\n });\n };\n\n /**\n * @function $unwrapHeaders\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and extend matching Card objects with received data.\n * @param {promise} futureHeadersData - a promise of the metadata of some cards\n */\n AddressBook.prototype.$unwrapHeaders = function(futureHeadersData) {\n var _this = this;\n\n futureHeadersData.then(function(data) {\n AddressBook.$timeout(function() {\n var headers, j;\n if (data.length > 0) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(data[0], 'toLowerCase');\n data.splice(0, 1);\n _.forEach(data, function(cardHeaders) {\n cardHeaders = _.zipObject(headers, cardHeaders);\n j = _this.idsMap[cardHeaders.id];\n if (angular.isDefined(j)) {\n _this.$cards[j].init(cardHeaders);\n }\n });\n }\n });\n });\n };\n\n /**\n * @function $omit\n * @memberof AddressBook.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the Addressbook instance\n */\n AddressBook.prototype.$omit = function() {\n var addressbook = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' &&\n key != 'ids' &&\n key[0] != '$') {\n addressbook[key] = value;\n }\n });\n return addressbook;\n };\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Card\n * @constructor\n * @param {object} futureCardData\n * @param {string} [partial]\n */\n function Card(futureCardData, partial) {\n\n // Data is immediately available\n if (typeof futureCardData.then !== 'function') {\n this.init(futureCardData, partial);\n if (this.pid && !this.id) {\n // Prepare for the creation of a new card;\n // Get UID from the server.\n var newCardData = Card.$$resource.newguid(this.pid);\n this.$unwrap(newCardData);\n this.isNew = true;\n }\n }\n else {\n // The promise will be unwrapped first\n this.$unwrap(futureCardData);\n }\n }\n\n Card.$TEL_TYPES = ['work', 'home', 'cell', 'fax', 'pager'];\n Card.$EMAIL_TYPES = ['work', 'home', 'pref'];\n Card.$URL_TYPES = ['work', 'home', 'pref'];\n Card.$ADDRESS_TYPES = ['work', 'home'];\n\n /**\n * @memberof Card\n * @desc The factory we'll use to register with Angular.\n * @returns the Card constructor\n */\n Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($timeout, Settings, Card_STATUS, Resource, Preferences) {\n angular.extend(Card, {\n STATUS: Card_STATUS,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $timeout: $timeout,\n $Preferences: Preferences\n });\n // Initialize categories from user's defaults\n Preferences.ready().then(function() {\n if (Preferences.defaults.SOGoContactsCategories) {\n Card.$categories = Preferences.defaults.SOGoContactsCategories;\n }\n if (Preferences.defaults.SOGoAlternateAvatar)\n Card.$alternateAvatar = Preferences.defaults.SOGoAlternateAvatar;\n });\n\n return Card; // return constructor\n }];\n\n /**\n * @module SOGo.ContactsUI\n * @desc Factory registration of Card in Angular module.\n */\n try {\n angular.module('SOGo.ContactsUI');\n }\n catch(e) {\n angular.module('SOGo.ContactsUI', ['SOGo.Common', 'SOGo.PreferencesUI']);\n }\n angular.module('SOGo.ContactsUI')\n .constant('sgCard_STATUS', {\n NOT_LOADED: 0,\n DELAYED_LOADING: 1,\n LOADING: 2,\n LOADED: 3,\n DELAYED_MS: 300\n })\n .factory('Card', Card.$factory);\n\n /**\n * @memberof Card\n * @desc Fetch a card from a specific addressbook.\n * @param {string} addressbookId - the addressbook ID\n * @param {string} cardId - the card ID\n * @see {@link AddressBook.$getCard}\n */\n Card.$find = function(addressbookId, cardId) {\n var futureCardData = this.$$resource.fetch([addressbookId, cardId].join('/'), 'view');\n\n if (cardId) return new Card(futureCardData); // a single card\n\n return Card.$unwrapCollection(futureCardData); // a collection of cards\n };\n\n /**\n * @function filterCategories\n * @memberof Card.prototype\n * @desc Search for categories matching some criterias\n * @param {string} search - the search string to match\n * @returns a collection of strings\n */\n Card.filterCategories = function(query) {\n var re = new RegExp(query, 'i');\n return _.map(_.filter(Card.$categories, function(category) {\n return category.search(re) != -1;\n }), function(category) {\n return { value: category };\n });\n };\n\n /**\n * @memberof Card\n * @desc Unwrap to a collection of Card instances.\n * @param {object} futureCardData\n */\n Card.$unwrapCollection = function(futureCardData) {\n var collection = {};\n\n collection.$futureCardData = futureCardData;\n\n futureCardData.then(function(cards) {\n Card.$timeout(function() {\n angular.forEach(cards, function(data, index) {\n collection[data.id] = new Card(data);\n });\n });\n });\n\n return collection;\n };\n\n /**\n * @function init\n * @memberof Card.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of card\n */\n Card.prototype.init = function(data, partial) {\n var _this = this;\n\n this.refs = [];\n this.categories = [];\n this.notes = [this.note];\n this.c_screenname = null;\n angular.extend(this, data);\n if (!this.$$fullname)\n this.$$fullname = this.$fullname();\n if (!this.$$email)\n this.$$email = this.$preferredEmail(partial);\n if (!this.$$image)\n this.$$image = this.image;\n if (!this.$$image)\n Card.$Preferences.avatar(this.$$email, 32, {no_404: true}).then(function(url) {\n _this.$$image = url;\n });\n if (this.isgroup)\n this.c_component = 'vlist';\n this.$loaded = angular.isDefined(this.c_name)? Card.STATUS.LOADED : Card.STATUS.NOT_LOADED;\n\n // An empty attribute to trick md-autocomplete when adding attendees from the appointment editor\n this.empty = ' ';\n };\n\n /**\n * @function $id\n * @memberof Card.prototype\n * @desc Return the card ID.\n * @returns the card ID\n */\n Card.prototype.$id = function() {\n return this.$futureCardData.then(function(data) {\n return data.id;\n });\n };\n\n /**\n * @function $isLoading\n * @memberof Card.prototype\n * @returns true if the Card definition is still being retrieved from server after a specific delay\n * @see sgCard_STATUS\n */\n Card.prototype.$isLoading = function() {\n return this.$loaded == Card.STATUS.LOADING;\n };\n\n /**\n * @function $reload\n * @memberof Message.prototype\n * @desc Fetch the viewable message body along with other metadata such as the list of attachments.\n * @returns a promise of the HTTP operation\n */\n Card.prototype.$reload = function() {\n var futureCardData;\n\n if (this.$futureCardData)\n return this;\n\n futureCardData = Card.$$resource.fetch([this.pid, this.id].join('/'), 'view');\n\n return this.$unwrap(futureCardData);\n };\n\n /**\n * @function $save\n * @memberof Card.prototype\n * @desc Save the card to the server.\n */\n Card.prototype.$save = function() {\n var _this = this,\n action = 'saveAsContact';\n\n if (this.c_component == 'vlist') 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 /**\n * @function export\n * @memberof Card.prototype\n * @desc Download the current card\n * @returns a promise of the HTTP operation\n */\n Card.prototype.export = function() {\n var selectedIDs;\n\n selectedIDs = [ this.id ];\n\n return Card.$$resource.download(this.pid, 'export', {uids: selectedIDs}, {type: 'application/octet-stream'});\n };\n\n Card.prototype.$fullname = function(options) {\n var fn = this.c_cn || '', html = options && options.html, email, names;\n if (fn.length === 0) {\n names = [];\n if (this.c_givenname && this.c_givenname.length > 0)\n names.push(this.c_givenname);\n if (this.nickname && this.nickname.length > 0)\n names.push((html?'':'') + this.nickname + (html?'':''));\n if (this.c_sn && this.c_sn.length > 0)\n names.push(this.c_sn);\n if (names.length > 0)\n fn = names.join(' ');\n else if (this.c_org && this.c_org.length > 0) {\n fn = this.c_org;\n }\n else if (this.emails && this.emails.length > 0) {\n email = _.find(this.emails, function(i) { return i.value !== ''; });\n if (email)\n fn = email.value;\n }\n }\n\n return fn;\n };\n\n Card.prototype.$description = function() {\n var description = [];\n if (this.title) description.push(this.title);\n if (this.role) description.push(this.role);\n if (this.orgUnits && this.orgUnits.length > 0)\n _.forEach(this.orgUnits, function(unit) {\n if (unit.value !== '')\n description.push(unit.value);\n });\n if (this.c_org) description.push(this.c_org);\n if (this.description) description.push(this.description);\n\n return description.join(', ');\n };\n\n /**\n * @function $preferredEmail\n * @memberof Card.prototype\n * @desc Get the preferred email address.\n * @param {string} [partial] - a partial string that the email must match\n * @returns the first email address of type \"pref\" or the first address if none found\n */\n Card.prototype.$preferredEmail = function(partial) {\n var email, re;\n if (partial) {\n re = new RegExp(partial, 'i');\n email = _.find(this.emails, function(o) {\n return re.test(o.value);\n });\n }\n if (email) {\n email = email.value;\n }\n else {\n email = _.find(this.emails, function(o) {\n return o.type == 'pref';\n });\n if (email) {\n email = email.value;\n }\n else if (this.emails && this.emails.length) {\n email = this.emails[0].value;\n }\n else if (this.c_mail && this.c_mail.length) {\n email = this.c_mail[0];\n }\n else {\n email = '';\n }\n }\n\n return email;\n };\n\n /**\n * @function $shortFormat\n * @memberof Card.prototype\n * @param {string} [partial] - a partial string that the email must match\n * @returns the fullname along with a matching email address in parentheses\n */\n Card.prototype.$shortFormat = function(partial) {\n var fullname = [this.$$fullname],\n email = this.$preferredEmail(partial);\n if (email && email != this.$$fullname)\n fullname.push(' <' + email + '>');\n return fullname.join(' ');\n };\n\n Card.prototype.$isCard = function() {\n return this.c_component == 'vcard';\n };\n\n Card.prototype.$isList = function(options) {\n // isGroup attribute means it's a group of a LDAP source (not expandable on the client-side)\n var condition = (!options || !options.expandable || options.expandable && !this.isgroup);\n return this.c_component == 'vlist' && condition;\n };\n\n Card.prototype.$addOrgUnit = function(orgUnit) {\n if (angular.isUndefined(this.orgUnits)) {\n this.orgUnits = [{value: orgUnit}];\n }\n else {\n for (var i = 0; i < this.orgUnits.length; i++) {\n if (this.orgUnits[i].value == orgUnit) {\n break;\n }\n }\n if (i == this.orgUnits.length)\n this.orgUnits.push({value: orgUnit});\n }\n return this.orgUnits.length - 1;\n };\n\n // Card.prototype.$addCategory = function(category) {\n // if (category) {\n // if (angular.isUndefined(this.categories)) {\n // this.categories = [{value: category}];\n // }\n // else {\n // for (var i = 0; i < this.categories.length; i++) {\n // if (this.categories[i].value == category) {\n // break;\n // }\n // }\n // if (i == this.categories.length)\n // this.categories.push({value: category});\n // }\n // }\n // };\n\n Card.prototype.$addEmail = function(type) {\n if (angular.isUndefined(this.emails)) {\n this.emails = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.emails, function(i) { return i.value === ''; }))) {\n this.emails.push({type: type, value: ''});\n }\n return this.emails.length - 1;\n };\n\n Card.prototype.$addScreenName = function(screenName) {\n this.c_screenname = screenName;\n };\n\n Card.prototype.$addPhone = function(type) {\n if (angular.isUndefined(this.phones)) {\n this.phones = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.phones, function(i) { return i.value === ''; }))) {\n this.phones.push({type: type, value: ''});\n }\n return this.phones.length - 1;\n };\n\n Card.prototype.$addUrl = function(type, url) {\n if (angular.isUndefined(this.urls)) {\n this.urls = [{type: type, value: url}];\n }\n else if (_.isUndefined(_.find(this.urls, function(i) { return i.value == url; }))) {\n this.urls.push({type: type, value: url});\n }\n return this.urls.length - 1;\n };\n\n Card.prototype.$addAddress = function(type, postoffice, street, street2, locality, region, country, postalcode) {\n if (angular.isUndefined(this.addresses)) {\n this.addresses = [{type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode}];\n }\n else if (!_.find(this.addresses, function(i) {\n return i.street == street &&\n i.street2 == street2 &&\n i.locality == locality &&\n i.country == country &&\n i.postalcode == postalcode;\n })) {\n this.addresses.push({type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode});\n }\n return this.addresses.length - 1;\n };\n\n Card.prototype.$addMember = function(email) {\n var card = new Card({email: email, emails: [{value: email}]}),\n i;\n if (angular.isUndefined(this.refs)) {\n this.refs = [card];\n }\n else if (email.length === 0) {\n this.refs.push(card);\n }\n else {\n for (i = 0; i < this.refs.length; i++) {\n if (this.refs[i].email == email) {\n break;\n }\n }\n if (i == this.refs.length)\n this.refs.push(card);\n }\n return this.refs.length - 1;\n };\n\n /**\n * @function explode\n * @memberof Card.prototype\n * @desc Create a new Card associated to each email address of this card.\n * @return an array of Card instances\n */\n Card.prototype.explode = function() {\n var _this = this, cards = [], data;\n\n if (this.emails.length > 1) {\n data = this.$omit();\n _.forEach(this.emails, function(email) {\n var card = new Card(angular.extend({}, data, {emails: [email]}));\n cards.push(card);\n });\n return cards;\n }\n else\n return [this];\n };\n\n /**\n * @function $reset\n * @memberof Card.prototype\n * @desc Reset the original state the card's data.\n */\n Card.prototype.$reset = function() {\n var _this = this;\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n delete _this[key];\n }\n });\n 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.DELAYED_LOADING;\n Card.$timeout(function() {\n if (_this.$loaded != Card.STATUS.LOADED)\n _this.$loaded = Card.STATUS.LOADING;\n }, Card.STATUS.DELAYED_MS);\n\n // Expose the promise\n this.$futureCardData = futureCardData.then(function(data) {\n _this.init(data);\n // 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 return this.$futureCardData;\n };\n\n /**\n * @function $omit\n * @memberof Card.prototype\n * @desc Return a sanitized object used to send to the server.\n * @param {boolean} [deep] - make a deep copy if true\n * @return an object literal copy of the Card instance\n */\n Card.prototype.$omit = function(deep) {\n var card = {};\n angular.forEach(this, function(value, key) {\n if (key == 'refs') {\n card.refs = _.map(value, function(o) {\n return o.$omit(deep);\n });\n }\n else if (key != 'constructor' && key[0] != '$') {\n if (deep)\n card[key] = angular.copy(value);\n else\n card[key] = value;\n }\n });\n\n // We convert back our birthday object\n if (!deep) {\n if (card.birthday)\n card.birthday = card.birthday.format(Card.$Preferences.$mdDateLocaleProvider, '%Y-%m-%d');\n else\n card.birthday = '';\n }\n\n 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","mapKeys","key","toLowerCase","debug","when","$add","addressbook","list","sibling","i","isSubscription","$subscriptions","$addressbooks","o","localeCompare","indexOf","map","$findAll","_this","$remotes","isRemote","push","union","$subscribe","uid","path","userResource","addressbookData","prototype","$$cards","idsMap","isOwned","isSuperUser","owner","login","$id","$futureAddressBookData","getLength","getItemAtIndex","$isLoading","$lastVisibleIndex","Math","max","$loadCard","endIndex","ids","futureHeadersData","cardId","startIndex","loaded","isDefined","$loaded","STATUS","NOT_LOADED","min","LOADED","LOADING","join","post","$unwrapHeaders","hasSelectedCard","selectedCard","isSelectedCard","$selectedCard","$selectedCards","selected","$selectedCount","count","$startRefreshTimeout","cancel","refreshViewCheck","defaults","SOGoRefreshViewCheck","f","$reload","timeInterval","$filter","query","dry","copy","partial","addressbookId","futureData","fields","idFieldIndex","cards","headers","invokeMap","pid","oldIndex","removedCards","findIndex","zipObject","$rename","$save","$delete","promise","d","defer","remove","resolve","reject","$_deleteCards","forEachRight","selectedIndex","$deleteCards","uids","$copyCards","folder","$moveCards","save","$omit","exportCards","selectedOnly","selectedUIDs","selectedCards","download","type","$topIndex","reduce","isError","isObject","j","cardHeaders","futureCardData","newCardData","newguid","isNew","$TEL_TYPES","$EMAIL_TYPES","$URL_TYPES","$ADDRESS_TYPES","Card_STATUS","SOGoContactsCategories","$categories","SOGoAlternateAvatar","$alternateAvatar","DELAYED_LOADING","DELAYED_MS","$find","$unwrapCollection","filterCategories","re","RegExp","category","collection","$futureCardData","refs","categories","notes","note","c_screenname","$$fullname","$fullname","$$email","$preferredEmail","$$image","image","avatar","no_404","url","isgroup","c_component","c_name","empty","action","birthday","$birthday","$mdDateLocaleProvider","formatDate","$shadowData","attribute","export","selectedIDs","email","names","fn","c_cn","html","c_givenname","nickname","c_sn","c_org","emails","$description","description","title","role","orgUnits","unit","test","c_mail","$shortFormat","fullname","$isCard","$isList","condition","expandable","$addOrgUnit","orgUnit","$addEmail","$addScreenName","screenName","$addPhone","phones","$addUrl","urls","$addAddress","postoffice","street","street2","locality","region","country","postalcode","addresses","$addMember","explode","$reset","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(_.mapKeys(data, function(value, key) {\n return key.toLowerCase();\n }), search);\n AddressBook.$cards.splice(index, 0, card);\n }\n });\n AddressBook.$log.debug(AddressBook.$cards);\n return AddressBook.$cards;\n });\n };\n\n /**\n * @memberof AddressBook\n * @desc Add a new addressbook to the static list of addressbooks\n * @param {AddressBook} addressbook - an Addressbook object instance\n */\n AddressBook.$add = function(addressbook) {\n // Insert new addressbook at proper index\n var list, sibling, i;\n\n list = addressbook.isSubscription? this.$subscriptions : this.$addressbooks;\n sibling = _.find(list, function(o) {\n return (addressbook.id == 'personal' ||\n (o.id != 'personal' &&\n o.name.localeCompare(addressbook.name) === 1));\n });\n i = sibling ? _.indexOf(_.map(list, 'id'), sibling.id) : 1;\n list.splice(i, 0, addressbook);\n };\n\n /**\n * @memberof AddressBook\n * @desc Set or get the list of addressbooks. Will instantiate a new AddressBook object for each item.\n * @param {array} [data] - the metadata of the addressbooks\n * @returns the list of addressbooks\n */\n AddressBook.$findAll = function(data) {\n var _this = this;\n if (data) {\n this.$addressbooks = [];\n this.$subscriptions = [];\n this.$remotes = [];\n // Instanciate AddressBook objects\n angular.forEach(data, function(o, i) {\n var addressbook = new AddressBook(o);\n if (addressbook.isRemote)\n _this.$remotes.push(addressbook);\n else if (addressbook.isSubscription)\n _this.$subscriptions.push(addressbook);\n else\n _this.$addressbooks.push(addressbook);\n });\n }\n return _.union(this.$addressbooks, this.$subscriptions, this.$remotes);\n };\n\n /**\n * @memberOf AddressBook\n * @desc Subscribe to another user's addressbook and add it to the list of addressbooks.\n * @param {string} uid - user id\n * @param {string} path - path of folder for specified user\n * @returns a promise of the HTTP query result\n */\n AddressBook.$subscribe = function(uid, path) {\n var _this = this;\n return AddressBook.$$resource.userResource(uid).fetch(path, 'subscribe').then(function(addressbookData) {\n var addressbook = new AddressBook(addressbookData);\n if (_.isUndefined(_.find(_this.$subscriptions, function(o) {\n return o.id == addressbookData.id;\n }))) {\n // Not already subscribed\n AddressBook.$add(addressbook);\n }\n return addressbook;\n });\n };\n\n /**\n * @function init\n * @memberof AddressBook.prototype\n * @desc Extend instance with new data and compute additional attributes.\n * @param {object} data - attributes of addressbook\n */\n AddressBook.prototype.init = function(data, options) {\n var _this = this;\n if (!this.$$cards) {\n // Array of cards for \"dry\" searches (see $filter)\n this.$$cards = [];\n }\n this.idsMap = {};\n this.$cards = []; // 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 hasSelectedMessage\n * @memberof AddressBook.prototype\n * @desc Check if a card is selected.\n * @returns true if the a card is selected\n */\n AddressBook.prototype.hasSelectedCard = function() {\n return angular.isDefined(this.selectedCard);\n };\n\n /**\n * @function isSelectedCard\n * @memberof AddressBook.prototype\n * @desc Check if the specified card is selected.\n * @param {string} CardId\n * @returns true if the specified card is selected\n */\n AddressBook.prototype.isSelectedCard = function(cardId) {\n return this.hasSelectedCard() && this.selectedCard == cardId;\n };\n\n /**\n * @function $selectedCard\n * @memberof AddressBook.prototype\n * @desc Return the currently visible card.\n * @returns a Card instance or undefined if no card is displayed\n */\n AddressBook.prototype.$selectedCard = function() {\n var _this = this;\n\n return _.find(this.$cards, function(card) { return card.id == _this.selectedCard; });\n };\n\n /**\n * @function $selectedCards\n * @memberof AddressBook.prototype\n * @desc Return the cards selected by the user.\n * @returns Card instances\n */\n AddressBook.prototype.$selectedCards = function() {\n return _.filter(this.$cards, function(card) { return card.selected; });\n };\n\n /**\n * @function $selectedCount\n * @memberof AddressBook.prototype\n * @desc Return the number of cards selected by the user.\n * @returns the number of selected cards\n */\n AddressBook.prototype.$selectedCount = function() {\n var count;\n\n count = 0;\n if (this.$cards) {\n count = (_.filter(this.$cards, function(card) { return card.selected; })).length;\n }\n return count;\n };\n\n /**\n * @function $startRefreshTimeout\n * @memberof AddressBook.prototype\n * @desc Starts the refresh timeout for the current selected address book\n */\n AddressBook.prototype.$startRefreshTimeout = function() {\n var _this = this;\n\n if (AddressBook.$refreshTimeout)\n AddressBook.$timeout.cancel(AddressBook.$refreshTimeout);\n\n AddressBook.$Preferences.ready().then(function() {\n // Restart the refresh timer, if needed\n var refreshViewCheck = AddressBook.$Preferences.defaults.SOGoRefreshViewCheck;\n if (refreshViewCheck && refreshViewCheck != 'manually') {\n var f = angular.bind(_this, AddressBook.prototype.$reload);\n AddressBook.$refreshTimeout = AddressBook.$timeout(f, refreshViewCheck.timeInterval()*1000);\n }\n });\n };\n\n /**\n * @function $reload\n * @memberof AddressBook.prototype\n * @desc Reload list of cards\n * @returns a promise of the Cards instances\n */\n AddressBook.prototype.$reload = function() {\n var _this = this;\n\n this.$startRefreshTimeout();\n return this.$filter();\n };\n\n /**\n * @function $filter\n * @memberof AddressBook.prototype\n * @desc Search for cards matching some criterias\n * @param {string} search - the search string to match\n * @param {object} [options] - additional options to the query (dry, excludeList)\n * @returns a collection of Cards instances\n */\n AddressBook.prototype.$filter = function(search, options, excludedCards) {\n var _this = this, query,\n dry = options && options.dry;\n\n if (dry) {\n // Don't keep a copy of the query in dry mode\n query = angular.copy(AddressBook.$query);\n }\n else {\n this.$isLoading = true;\n query = AddressBook.$query;\n if (!this.isRemote) query.partial = 1;\n }\n\n return AddressBook.$Preferences.ready().then(function() {\n if (options) {\n angular.extend(query, options);\n if (dry) {\n if (!search) {\n // No query specified\n _this.$$cards = [];\n return AddressBook.$q.when(_this.$$cards);\n }\n }\n }\n\n if (angular.isDefined(search))\n query.value = search;\n\n return _this.$id().then(function(addressbookId) {\n var futureData = AddressBook.$$resource.fetch(addressbookId, 'view', query);\n\n if (dry) {\n futureData.then(function(response) {\n var results, headers, card, index, fields, idFieldIndex,\n cards = _this.$$cards,\n compareIds = function(card) {\n return this == card.id;\n };\n\n if (response.headers) {\n // First entry of 'headers' are keys\n fields = _.invokeMap(response.headers[0], 'toLowerCase');\n idFieldIndex = fields.indexOf('id');\n response.headers.splice(0, 1);\n }\n\n if (excludedCards)\n // Remove excluded cards from results\n results = _.filter(response.ids, function(id) {\n return _.isUndefined(_.find(excludedCards, _.bind(compareIds, id)));\n });\n else\n results = response.ids;\n\n // Remove cards that no longer match the search query\n for (index = cards.length - 1; index >= 0; index--) {\n card = cards[index];\n if (_.isUndefined(_.find(results, _.bind(compareIds, card.id)))) {\n cards.splice(index, 1);\n }\n }\n\n // Add new cards matching the search query\n _.forEach(results, function(cardId, index) {\n if (_.isUndefined(_.find(cards, _.bind(compareIds, cardId)))) {\n var data = { pid: addressbookId, id: cardId };\n var card = new AddressBook.$Card(data, search);\n cards.splice(index, 0, card);\n }\n });\n\n // Respect the order of the results\n _.forEach(results, function(cardId, index) {\n var oldIndex, removedCards;\n if (cards[index].id != cardId) {\n oldIndex = _.findIndex(cards, _.bind(compareIds, cardId));\n removedCards = cards.splice(oldIndex, 1);\n cards.splice(index, 0, removedCards[0]);\n }\n });\n\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var card, index = _.findIndex(cards, _.bind(compareIds, data[idFieldIndex]));\n if (index > -1) {\n card = _.zipObject(fields, data);\n cards[index].init(card, search);\n }\n });\n\n _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 object.\n * @param {string[]} ids - the cards ids\n */\n AddressBook.prototype.$_deleteCards = function(ids) {\n var _this = this;\n\n // Remove cards from $cards and idsMap\n _.forEachRight(this.$cards, function(card, index) {\n var selectedIndex = _.findIndex(ids, function(id) {\n return card.id == id;\n });\n if (selectedIndex > -1) {\n ids.splice(selectedIndex, 1);\n delete _this.idsMap[card.id];\n if (_this.isSelectedCard(card.id))\n delete _this.selectedCard;\n _this.$cards.splice(index, 1);\n }\n else {\n _this.idsMap[card.id] -= ids.length;\n }\n });\n };\n\n /**\n * @function $deleteCards\n * @memberof AddressBook.prototype\n * @desc Delete multiple cards from addressbook.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$deleteCards = function(cards) {\n var _this = this,\n ids = _.map(cards, 'id');\n \n return AddressBook.$$resource.post(this.id, 'batchDelete', {uids: ids}).then(function() {\n _this.$_deleteCards(ids);\n });\n };\n\n /**\n * @function $copyCards\n * @memberof AddressBook.prototype\n * @desc Copy multiple cards from addressbook to an other one.\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$copyCards = function(cards, folder) {\n var uids = _.map(cards, 'id');\n return AddressBook.$$resource.post(this.id, 'copy', {uids: uids, folder: folder});\n };\n\n /**\n * @function $moveCards\n * @memberof AddressBook.prototype\n * @desc Move multiple cards from the current addressbook to a target one\n * @param {object[]} cards - instances of Card object\n * @param {string} folder - the destination folder id\n * @return a promise of the HTTP operation\n */\n AddressBook.prototype.$moveCards = function(cards, folder) {\n var _this = this, uids;\n\n uids = _.map(cards, 'id');\n return AddressBook.$$resource.post(this.id, 'move', {uids: uids, folder: folder})\n .then(function() {\n return _this.$_deleteCards(uids);\n });\n };\n\n /**\n * @function $save\n * @memberof AddressBook.prototype\n * @desc Save the addressbook to the server. This currently can only affect the name of the addressbook.\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.$save = function() {\n return AddressBook.$$resource.save(this.id, this.$omit()).then(function(data) {\n return data;\n });\n };\n\n /**\n * @function $exportCards\n * @memberof AddressBook.prototype\n * @desc Export the selected/all cards\n * @returns a promise of the HTTP operation\n */\n AddressBook.prototype.exportCards = function(selectedOnly) {\n var selectedUIDs;\n\n if (selectedOnly) {\n var selectedCards = _.filter(this.$cards, function(card) { return card.selected; });\n selectedUIDs = _.map(selectedCards, 'id');\n }\n\n return AddressBook.$$resource.download(this.id, 'export', (angular.isDefined(selectedUIDs) ? {uids: selectedUIDs} : null), {type: 'application/octet-stream'});\n };\n\n /**\n * @function $unwrap\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and instanciate new Card objects using received data.\n * @param {promise} futureAddressBookData - a promise of the AddressBook's data\n */\n AddressBook.prototype.$unwrap = function(futureAddressBookData) {\n var _this = this;\n\n this.$isLoading = true;\n\n // Expose and resolve the promise\n this.$futureAddressBookData = futureAddressBookData.then(function(response) {\n return AddressBook.$timeout(function() {\n var headers;\n\n if (!response.ids || _this.$topIndex > response.ids.length - 1)\n _this.$topIndex = 0;\n\n // Extend AddressBook instance from data of addressbooks list.\n // Will inherit attributes such as isEditable and isRemote.\n angular.forEach(AddressBook.$findAll(), function(o, i) {\n if (o.id == response.id) {\n angular.extend(_this, o);\n }\n });\n\n // Extend AddressBook instance with received data\n _this.init(response);\n\n if (_this.ids) {\n AddressBook.$log.debug('unwrapping ' + _this.ids.length + ' cards');\n\n // Instanciate Card objects\n _.reduce(_this.ids, function(cards, card, i) {\n var data = { pid: _this.id, id: card };\n\n // Build map of ID <=> index\n _this.idsMap[data.id] = i;\n\n cards.push(new AddressBook.$Card(data));\n\n return cards;\n }, _this.$cards);\n }\n\n if (response.headers) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(response.headers[0], 'toLowerCase');\n response.headers.splice(0, 1);\n\n if (_this.ids) {\n // Extend Card objects with received headers\n _.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data),\n i = _this.idsMap[o.id];\n _this.$cards[i].init(o);\n });\n }\n else {\n // Instanciate Card objects\n _this.$cards = [];\n angular.forEach(response.headers, function(data) {\n var o = _.zipObject(headers, data);\n angular.extend(o, { pid: _this.id });\n _this.$cards.push(new AddressBook.$Card(o));\n });\n }\n }\n\n // Instanciate Acl object\n _this.$acl = new AddressBook.$$Acl('Contacts/' + _this.id);\n\n _this.$startRefreshTimeout();\n\n _this.$isLoading = false;\n\n AddressBook.$log.debug('addressbook ' + _this.id + ' ready');\n\n return _this;\n });\n }, function(data) {\n _this.isError = true;\n if (angular.isObject(data)) {\n AddressBook.$timeout(function() {\n angular.extend(_this, data);\n });\n }\n });\n };\n\n /**\n * @function $unwrapHeaders\n * @memberof AddressBook.prototype\n * @desc Unwrap a promise and extend matching Card objects with received data.\n * @param {promise} futureHeadersData - a promise of the metadata of some cards\n */\n AddressBook.prototype.$unwrapHeaders = function(futureHeadersData) {\n var _this = this;\n\n futureHeadersData.then(function(data) {\n AddressBook.$timeout(function() {\n var headers, j;\n if (data.length > 0) {\n // First entry of 'headers' are keys\n headers = _.invokeMap(data[0], 'toLowerCase');\n data.splice(0, 1);\n _.forEach(data, function(cardHeaders) {\n cardHeaders = _.zipObject(headers, cardHeaders);\n j = _this.idsMap[cardHeaders.id];\n if (angular.isDefined(j)) {\n _this.$cards[j].init(cardHeaders);\n }\n });\n }\n });\n });\n };\n\n /**\n * @function $omit\n * @memberof AddressBook.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the Addressbook instance\n */\n AddressBook.prototype.$omit = function() {\n var addressbook = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' &&\n key != 'ids' &&\n key[0] != '$') {\n addressbook[key] = value;\n }\n });\n return addressbook;\n };\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Card\n * @constructor\n * @param {object} futureCardData\n * @param {string} [partial]\n */\n function Card(futureCardData, partial) {\n\n // Data is immediately available\n if (typeof futureCardData.then !== 'function') {\n this.init(futureCardData, partial);\n if (this.pid && !this.id) {\n // Prepare for the creation of a new card;\n // Get UID from the server.\n var newCardData = Card.$$resource.newguid(this.pid);\n this.$unwrap(newCardData);\n this.isNew = true;\n }\n }\n else {\n // The promise will be unwrapped first\n this.$unwrap(futureCardData);\n }\n }\n\n Card.$TEL_TYPES = ['work', 'home', 'cell', 'fax', 'pager'];\n Card.$EMAIL_TYPES = ['work', 'home', 'pref'];\n Card.$URL_TYPES = ['work', 'home', 'pref'];\n Card.$ADDRESS_TYPES = ['work', 'home'];\n\n /**\n * @memberof Card\n * @desc The factory we'll use to register with Angular.\n * @returns the Card constructor\n */\n Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($timeout, Settings, Card_STATUS, Resource, Preferences) {\n angular.extend(Card, {\n STATUS: Card_STATUS,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),\n $timeout: $timeout,\n $Preferences: Preferences\n });\n // Initialize categories from user's defaults\n Preferences.ready().then(function() {\n if (Preferences.defaults.SOGoContactsCategories) {\n Card.$categories = Preferences.defaults.SOGoContactsCategories;\n }\n if (Preferences.defaults.SOGoAlternateAvatar)\n Card.$alternateAvatar = Preferences.defaults.SOGoAlternateAvatar;\n });\n\n return Card; // return constructor\n }];\n\n /**\n * @module SOGo.ContactsUI\n * @desc Factory registration of Card in Angular module.\n */\n try {\n angular.module('SOGo.ContactsUI');\n }\n catch(e) {\n angular.module('SOGo.ContactsUI', ['SOGo.Common', 'SOGo.PreferencesUI']);\n }\n angular.module('SOGo.ContactsUI')\n .constant('sgCard_STATUS', {\n NOT_LOADED: 0,\n DELAYED_LOADING: 1,\n LOADING: 2,\n LOADED: 3,\n DELAYED_MS: 300\n })\n .factory('Card', Card.$factory);\n\n /**\n * @memberof Card\n * @desc Fetch a card from a specific addressbook.\n * @param {string} addressbookId - the addressbook ID\n * @param {string} cardId - the card ID\n * @see {@link AddressBook.$getCard}\n */\n Card.$find = function(addressbookId, cardId) {\n var futureCardData = this.$$resource.fetch([addressbookId, cardId].join('/'), 'view');\n\n if (cardId) return new Card(futureCardData); // a single card\n\n return Card.$unwrapCollection(futureCardData); // a collection of cards\n };\n\n /**\n * @function filterCategories\n * @memberof Card.prototype\n * @desc Search for categories matching some criterias\n * @param {string} search - the search string to match\n * @returns a collection of strings\n */\n Card.filterCategories = function(query) {\n var re = new RegExp(query, 'i');\n return _.map(_.filter(Card.$categories, function(category) {\n return category.search(re) != -1;\n }), function(category) {\n return { value: category };\n });\n };\n\n /**\n * @memberof Card\n * @desc Unwrap to a collection of Card instances.\n * @param {object} futureCardData\n */\n Card.$unwrapCollection = function(futureCardData) {\n var collection = {};\n\n collection.$futureCardData = futureCardData;\n\n futureCardData.then(function(cards) {\n Card.$timeout(function() {\n angular.forEach(cards, function(data, index) {\n collection[data.id] = new Card(data);\n });\n });\n });\n\n return collection;\n };\n\n /**\n * @function init\n * @memberof Card.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of card\n */\n Card.prototype.init = function(data, partial) {\n var _this = this;\n\n this.refs = [];\n this.categories = [];\n this.notes = [this.note];\n this.c_screenname = null;\n angular.extend(this, data);\n if (!this.$$fullname)\n this.$$fullname = this.$fullname();\n if (!this.$$email)\n this.$$email = this.$preferredEmail(partial);\n if (!this.$$image)\n this.$$image = this.image;\n if (!this.$$image)\n Card.$Preferences.avatar(this.$$email, 32, {no_404: true}).then(function(url) {\n _this.$$image = url;\n });\n if (this.isgroup)\n this.c_component = 'vlist';\n this.$loaded = angular.isDefined(this.c_name)? Card.STATUS.LOADED : Card.STATUS.NOT_LOADED;\n\n // An empty attribute to trick md-autocomplete when adding attendees from the appointment editor\n this.empty = ' ';\n };\n\n /**\n * @function $id\n * @memberof Card.prototype\n * @desc Return the card ID.\n * @returns the card ID\n */\n Card.prototype.$id = function() {\n return this.$futureCardData.then(function(data) {\n return data.id;\n });\n };\n\n /**\n * @function $isLoading\n * @memberof Card.prototype\n * @returns true if the Card definition is still being retrieved from server after a specific delay\n * @see sgCard_STATUS\n */\n Card.prototype.$isLoading = function() {\n return this.$loaded == Card.STATUS.LOADING;\n };\n\n /**\n * @function $reload\n * @memberof Message.prototype\n * @desc Fetch the viewable message body along with other metadata such as the list of attachments.\n * @returns a promise of the HTTP operation\n */\n Card.prototype.$reload = function() {\n var futureCardData;\n\n if (this.$futureCardData)\n return this;\n\n futureCardData = Card.$$resource.fetch([this.pid, this.id].join('/'), 'view');\n\n return this.$unwrap(futureCardData);\n };\n\n /**\n * @function $save\n * @memberof Card.prototype\n * @desc Save the card to the server.\n */\n Card.prototype.$save = function() {\n var _this = this,\n action = 'saveAsContact';\n\n if (this.c_component == 'vlist') 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 /**\n * @function export\n * @memberof Card.prototype\n * @desc Download the current card\n * @returns a promise of the HTTP operation\n */\n Card.prototype.export = function() {\n var selectedIDs;\n\n selectedIDs = [ this.id ];\n\n return Card.$$resource.download(this.pid, 'export', {uids: selectedIDs}, {type: 'application/octet-stream'});\n };\n\n Card.prototype.$fullname = function(options) {\n var fn = this.c_cn || '', html = options && options.html, email, names;\n if (fn.length === 0) {\n names = [];\n if (this.c_givenname && this.c_givenname.length > 0)\n names.push(this.c_givenname);\n if (this.nickname && this.nickname.length > 0)\n names.push((html?'':'') + this.nickname + (html?'':''));\n if (this.c_sn && this.c_sn.length > 0)\n names.push(this.c_sn);\n if (names.length > 0)\n fn = names.join(' ');\n else if (this.c_org && this.c_org.length > 0) {\n fn = this.c_org;\n }\n else if (this.emails && this.emails.length > 0) {\n email = _.find(this.emails, function(i) { return i.value !== ''; });\n if (email)\n fn = email.value;\n }\n }\n\n return fn;\n };\n\n Card.prototype.$description = function() {\n var description = [];\n if (this.title) description.push(this.title);\n if (this.role) description.push(this.role);\n if (this.orgUnits && this.orgUnits.length > 0)\n _.forEach(this.orgUnits, function(unit) {\n if (unit.value !== '')\n description.push(unit.value);\n });\n if (this.c_org) description.push(this.c_org);\n if (this.description) description.push(this.description);\n\n return description.join(', ');\n };\n\n /**\n * @function $preferredEmail\n * @memberof Card.prototype\n * @desc Get the preferred email address.\n * @param {string} [partial] - a partial string that the email must match\n * @returns the first email address of type \"pref\" or the first address if none found\n */\n Card.prototype.$preferredEmail = function(partial) {\n var email, re;\n if (partial) {\n re = new RegExp(partial, 'i');\n email = _.find(this.emails, function(o) {\n return re.test(o.value);\n });\n }\n if (email) {\n email = email.value;\n }\n else {\n email = _.find(this.emails, function(o) {\n return o.type == 'pref';\n });\n if (email) {\n email = email.value;\n }\n else if (this.emails && this.emails.length) {\n email = this.emails[0].value;\n }\n else if (this.c_mail && this.c_mail.length) {\n email = this.c_mail[0];\n }\n else {\n email = '';\n }\n }\n\n return email;\n };\n\n /**\n * @function $shortFormat\n * @memberof Card.prototype\n * @param {string} [partial] - a partial string that the email must match\n * @returns the fullname along with a matching email address in parentheses\n */\n Card.prototype.$shortFormat = function(partial) {\n var fullname = [this.$$fullname],\n email = this.$preferredEmail(partial);\n if (email && email != this.$$fullname)\n fullname.push(' <' + email + '>');\n return fullname.join(' ');\n };\n\n Card.prototype.$isCard = function() {\n return this.c_component == 'vcard';\n };\n\n Card.prototype.$isList = function(options) {\n // isGroup attribute means it's a group of a LDAP source (not expandable on the client-side)\n var condition = (!options || !options.expandable || options.expandable && !this.isgroup);\n return this.c_component == 'vlist' && condition;\n };\n\n Card.prototype.$addOrgUnit = function(orgUnit) {\n if (angular.isUndefined(this.orgUnits)) {\n this.orgUnits = [{value: orgUnit}];\n }\n else {\n for (var i = 0; i < this.orgUnits.length; i++) {\n if (this.orgUnits[i].value == orgUnit) {\n break;\n }\n }\n if (i == this.orgUnits.length)\n this.orgUnits.push({value: orgUnit});\n }\n return this.orgUnits.length - 1;\n };\n\n // Card.prototype.$addCategory = function(category) {\n // if (category) {\n // if (angular.isUndefined(this.categories)) {\n // this.categories = [{value: category}];\n // }\n // else {\n // for (var i = 0; i < this.categories.length; i++) {\n // if (this.categories[i].value == category) {\n // break;\n // }\n // }\n // if (i == this.categories.length)\n // this.categories.push({value: category});\n // }\n // }\n // };\n\n Card.prototype.$addEmail = function(type) {\n if (angular.isUndefined(this.emails)) {\n this.emails = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.emails, function(i) { return i.value === ''; }))) {\n this.emails.push({type: type, value: ''});\n }\n return this.emails.length - 1;\n };\n\n Card.prototype.$addScreenName = function(screenName) {\n this.c_screenname = screenName;\n };\n\n Card.prototype.$addPhone = function(type) {\n if (angular.isUndefined(this.phones)) {\n this.phones = [{type: type, value: ''}];\n }\n else if (_.isUndefined(_.find(this.phones, function(i) { return i.value === ''; }))) {\n this.phones.push({type: type, value: ''});\n }\n return this.phones.length - 1;\n };\n\n Card.prototype.$addUrl = function(type, url) {\n if (angular.isUndefined(this.urls)) {\n this.urls = [{type: type, value: url}];\n }\n else if (_.isUndefined(_.find(this.urls, function(i) { return i.value == url; }))) {\n this.urls.push({type: type, value: url});\n }\n return this.urls.length - 1;\n };\n\n Card.prototype.$addAddress = function(type, postoffice, street, street2, locality, region, country, postalcode) {\n if (angular.isUndefined(this.addresses)) {\n this.addresses = [{type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode}];\n }\n else if (!_.find(this.addresses, function(i) {\n return i.street == street &&\n i.street2 == street2 &&\n i.locality == locality &&\n i.country == country &&\n i.postalcode == postalcode;\n })) {\n this.addresses.push({type: type, postoffice: postoffice, street: street, street2: street2, locality: locality, region: region, country: country, postalcode: postalcode});\n }\n return this.addresses.length - 1;\n };\n\n Card.prototype.$addMember = function(email) {\n var card = new Card({email: email, emails: [{value: email}]}),\n i;\n if (angular.isUndefined(this.refs)) {\n this.refs = [card];\n }\n else if (email.length === 0) {\n this.refs.push(card);\n }\n else {\n for (i = 0; i < this.refs.length; i++) {\n if (this.refs[i].email == email) {\n break;\n }\n }\n if (i == this.refs.length)\n this.refs.push(card);\n }\n return this.refs.length - 1;\n };\n\n /**\n * @function explode\n * @memberof Card.prototype\n * @desc Create a new Card associated to each email address of this card.\n * @return an array of Card instances\n */\n Card.prototype.explode = function() {\n var _this = this, cards = [], data;\n\n if (this.emails.length > 1) {\n data = this.$omit();\n _.forEach(this.emails, function(email) {\n var card = new Card(angular.extend({}, data, {emails: [email]}));\n cards.push(card);\n });\n return cards;\n }\n else\n return [this];\n };\n\n /**\n * @function $reset\n * @memberof Card.prototype\n * @desc Reset the original state the card's data.\n */\n Card.prototype.$reset = function() {\n var _this = this;\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n delete _this[key];\n }\n });\n 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.DELAYED_LOADING;\n Card.$timeout(function() {\n if (_this.$loaded != Card.STATUS.LOADED)\n _this.$loaded = Card.STATUS.LOADING;\n }, Card.STATUS.DELAYED_MS);\n\n // Expose the promise\n this.$futureCardData = futureCardData.then(function(data) {\n _this.init(data);\n // 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 return this.$futureCardData;\n };\n\n /**\n * @function $omit\n * @memberof Card.prototype\n * @desc Return a sanitized object used to send to the server.\n * @param {boolean} [deep] - make a deep copy if true\n * @return an object literal copy of the Card instance\n */\n Card.prototype.$omit = function(deep) {\n var card = {};\n angular.forEach(this, function(value, key) {\n if (key == 'refs') {\n card.refs = _.map(value, function(o) {\n return o.$omit(deep);\n });\n }\n else if (key != 'constructor' && key[0] != '$') {\n if (deep)\n card[key] = angular.copy(value);\n else\n card[key] = value;\n }\n });\n\n // We convert back our birthday object\n if (!deep) {\n if (card.birthday)\n card.birthday = card.birthday.format(Card.$Preferences.$mdDateLocaleProvider, '%Y-%m-%d');\n else\n card.birthday = '';\n }\n\n 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