/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* JavaScript for SOGo.ContactsUI (mobile) module */ (function() { 'use strict'; angular.module('SOGo.Common', []); angular.module('SOGo.ContactsUI', ['ionic', 'SOGo.Common', 'SOGo.UIMobile']) .constant('sgSettings', { baseURL: ApplicationBaseURL }) .run(function($ionicPlatform) { $ionicPlatform.ready(function() { // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard // for form inputs) if (window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if (window.StatusBar) { // org.apache.cordova.statusbar required StatusBar.styleDefault(); } }); }) .config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('app', { url: '/app', abstract: true, templateUrl: 'menu.html', controller: 'AppCtrl' }) .state('app.addressbooks', { url: '/addressbooks', views: { menuContent: { templateUrl: 'addressbooks.html', controller: 'AddressBooksCtrl' } } }) .state('app.addressbook', { url: '/addressbook/:addressbookId', views: { menuContent: { templateUrl: 'addressbook.html', controller: 'AddressBookCtrl', resolve: { stateAddressbook: function($stateParams, sgAddressBook) { return sgAddressBook.$find($stateParams.addressbookId); } } } } }) .state('app.newCard', { url: '/addressbook/:addressbookId/:contactType/new', views: { menuContent: { templateUrl: 'card.html', controller: 'CardCtrl', resolve: { stateCard: ['$rootScope', '$stateParams', 'sgAddressBook', 'sgCard', function($rootScope, $stateParams, sgAddressBook, Card) { var tag = 'v' + $stateParams.contactType; if (!$rootScope.addressbook) { $rootScope.addressbook = sgAddressBook.$find($stateParams.addressbookId); } return new Card( { pid: $stateParams.addressbookId, tag: tag, isNew: true } ); }] } } } }) .state('app.card', { url: '/addressbook/:addressbookId/:cardId', views: { menuContent: { templateUrl: 'card.html', controller: 'CardCtrl', resolve: { stateCard: ['$rootScope', '$stateParams', 'sgAddressBook', function($rootScope, $stateParams, AddressBook) { if (!$rootScope.addressbook) { $rootScope.addressbook = AddressBook.$find($stateParams.addressbookId); } return $rootScope.addressbook.$getCard($stateParams.cardId); }] } } } }); // if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/app/addressbooks'); }) .directive('ionSearch', function() { return { restrict: 'E', replace: true, scope: { getData: '&source', clearData: '&clear', model: '=?', search: '=?filter' }, link: function(scope, element, attrs) { attrs.minLength = attrs.minLength || 0; scope.placeholder = attrs.placeholder || ''; scope.search = {value: ''}; if (attrs.class) element.addClass(attrs.class); if (attrs.source) { scope.$watch('search.value', function (newValue, oldValue) { if (newValue.length > attrs.minLength) { scope.getData({search: newValue}).then(function (results) { scope.model = results; }); } }); } scope.clearSearch = function() { scope.search.value = ''; scope.clearData(); }; }, template: '
' + '' + '' + '' + '
' }; }) .controller('AppCtrl', ['$scope', '$http', function($scope, $http) { $scope.UserLogin = UserLogin; $scope.UserFolderURL = UserFolderURL; $scope.ApplicationBaseURL = ApplicationBaseURL; // $scope.logout = function(url) { // $http.get(url) // .success(function(data, status, headers) { // console.debug(headers); // }); // }; }]) .controller('AddressBooksCtrl', ['$scope', '$rootScope', '$ionicModal', '$ionicListDelegate', '$ionicActionSheet', 'sgDialog', 'sgAddressBook', 'sgAclUsers', 'sgUser', function($scope, $rootScope, $ionicModal, $ionicListDelegate, $ionicActionSheet, Dialog, AddressBook, sgAclUsers, sgUser) { // Initialize with data from template $scope.addressbooks = AddressBook.$findAll(contactFolders); $scope.newAddressbook = function() { Dialog.prompt(l('Create addressbook'), l('Name of new addressbook')) .then(function(res) { if (res && res.length > 0) { var addressbook = new AddressBook( { name: res, isEditable: true, isRemote: false } ); AddressBook.$add(addressbook); } }); }; $scope.edit = function(addressbook) { $ionicActionSheet.show({ buttons: [ { text: l('Rename') }, { text: l('Sharing') } ], destructiveText: l('Delete'), cancelText: l('Cancel'), buttonClicked: function(index) { if(index == 0) { // Rename addressbook Dialog.prompt(l('Rename addressbook'), addressbook.name) .then(function(name) { if (name && name.length > 0) { addressbook.$rename(name); } }); } else if(index == 1) { // Build modal editor $ionicModal.fromTemplateUrl('acl-modal.html', { scope: $scope }).then(function(modal) { if ($scope.$aclEditorModal) { $scope.$aclEditorModal.remove(); } // Variables in scope $scope.$aclEditorModal = modal; $scope.addressbook = addressbook; $scope.AclUsers = new sgAclUsers(addressbook); $scope.User = new sgUser(addressbook); var aclUsers = {}; $scope.User.$acls().then(function(users) { $scope.refreshUsers(users); }); $scope.showDelete = false; $scope.onGoingSearch = false; // Variables in javascript var dirtyObjects = {}; // Local functions $scope.refreshUsers = function(users) { $scope.users = []; $scope.onGoingSearch = false; angular.forEach(users, function(user){ user.inAclList = true; user.canSubscribeUser = (user.isSubscribed) ? false : true; $scope.users.push(user); aclUsers[user.uid] = user; }) }; // Function in scope $scope.closeModal = function() { $scope.$aclEditorModal.remove(); }; $scope.saveModal = function() { if(!_.isEmpty(dirtyObjects)) { if(dirtyObjects["anonymous"]) { Dialog.confirm(l("Warning"), l("Any user with an account on this system will be able to access your folder. Are you certain you trust them all?")).then(function(res){ if(res){ $scope.AclUsers.saveUsersRights(dirtyObjects); $scope.$aclEditorModal.remove(); }; }) } else if (dirtyObjects[""]) { Dialog.confirm(l("Warning"), l("Potentially anyone on the Internet will be able to access your folder, even if they do not have an account on this system. Is this information suitable for the public Internet?")).then(function(res){ if(res){ $scope.AclUsers.saveUsersRights(dirtyObjects); $scope.$aclEditorModal.remove(); }; }) } else { $scope.AclUsers.saveUsersRights(dirtyObjects); var usersToSubscribe = []; angular.forEach(dirtyObjects, function(dirtyObject){ if(dirtyObject.canSubscribeUser && dirtyObject.isSubscribed){ usersToSubscribe.push(dirtyObject.uid); } }) if(!_.isEmpty(usersToSubscribe)) $scope.AclUsers.subscribeUsers(usersToSubscribe); $scope.$aclEditorModal.remove(); } } else $scope.$aclEditorModal.remove(); }; $scope.cancelSearch = function() { $scope.User.$acls().then(function(users) { $scope.refreshUsers(users); }); }; $scope.toggleDelete = function(boolean) { $scope.showDelete = boolean; }; $scope.removeUser = function(user) { if (user) { if(dirtyObjects[user.uid]) delete dirtyObjects[user.uid]; delete aclUsers[user.uid]; $scope.AclUsers.removeUser(user.uid); // Remove from the users list $scope.users = _.reject($scope.users, function(o) { return o.uid == user.uid; }); $scope.userSelected = {}; } }; $scope.addUser = function (user) { if (user.uid) { if(!aclUsers[user.uid]) { $scope.AclUsers.addUser(user.uid); user.inAclList = true; user.canSubscribeUser = (user.isSubscribed) ? false : true; aclUsers[user.uid] = user; } else Dialog.alert(l('Warning'), l('You have already subscribed to that folder!')); } else Dialog.alert(l('Warning'), l('Please select a user inside your domain')); }; $scope.editUser = function(user) { if ($scope.userSelected != user){ $scope.userSelected = user; if (dirtyObjects[$scope.userSelected.uid]) { // If the user already made changes on the user rights, it is saved inside an object called dirty. // We preverse these changes untill the user decide to save or discard them. $scope.userSelected.aclOptions = dirtyObjects[$scope.userSelected.uid].aclOptions; } else { // Otherwise, if it's the first time the user consult the user rights; fetch from server $scope.AclUsers.userRights($scope.userSelected.uid).then(function(userRights) { $scope.userSelected.aclOptions = userRights; }); } } }; $scope.searchUsers = function(search){ $scope.users = []; $scope.onGoingSearch = true; return $scope.User.$filter(search).then(function(results) { angular.forEach(results, function(userFound){ userFound.inAclList = (aclUsers[userFound.uid]) ? true : false; $scope.users.push(userFound); }) }); }; $scope.toggleUser = function(user) { if (user.inAclList) { if ($scope.isUserShown(user)) { $scope.shownUser = null; } else { $scope.shownUser = user; $scope.editUser(user); } } else { $scope.addUser(user); } }; $scope.isUserShown = function(user) { return $scope.shownUser === user; }; $scope.markUserAsDirty = function() { dirtyObjects[$scope.userSelected.uid] = $scope.userSelected; }; $scope.displayUserRights = function() { // Does the rights applies on the user/group return ($scope.userSelected && ($scope.userSelected.uid != "anonymous")) ? true : false; }; $scope.displaySubscribeUser = function() { // Is the user/group available for subscription return ($scope.userSelected && !($scope.userSelected.uid == "anonymous" || $scope.userSelected.uid == "")) ? true : false; }; $scope.displayIcon = function(user) { if (user.inAclList) return ($scope.isUserShown(user) ? 'ion-ios7-arrow-down' : 'ion-ios7-arrow-right'); else return 'ion-plus'; } // Show modal $scope.$aclEditorModal.show(); }); } return true; }, destructiveButtonClicked: function() { // Delete addressbook addressbook.$delete() .then(function() { addressbook = null; }, function(data) { Dialog.alert(l('An error occured while deleting the addressbook "%{0}".', addressbook.name), l(data.error)); }); return true; } // cancel: function() { // }, }); $ionicListDelegate.closeOptionButtons(); }; }]) .controller('AddressBookCtrl', ['$scope', '$rootScope', '$stateParams', '$state', '$ionicActionSheet', 'sgAddressBook', 'sgCard', 'stateAddressbook', function($scope, $rootScope, $stateParams, $state, $ionicActionSheet, AddressBook, Card, stateAddressbook) { $rootScope.addressbook = stateAddressbook; $scope.search = { status: null, filter: null, lastFilter: null }; $scope.addCard = function() { $ionicActionSheet.show({ //titleText: l('Create a new card or a new list'), buttons: [ { text: l('New Card')}, { text: l('New List')} ], canceltext: l('Cancel'), buttonClicked: function(index) { if (index == 0){ $state.go('app.newCard', { addressbookId: stateAddressbook.id, contactType: 'card' }); } else if (index == 1){ $state.go('app.newCard', { addressbookId: stateAddressbook.id, contactType: 'list' }); } return true; } }); }; $scope.doSearch = function(keyEvent) { if ($scope.search.lastFilter != $scope.search.filter) { if ($scope.search.filter.length > 2) { $rootScope.addressbook.$filter($scope.search.filter).then(function(data) { if (data.length == 0) $scope.search.status = 'no-result'; else $scope.search.status = ''; }); } else if ($scope.search.filter.length == 0) { $scope.searchStatus = ''; $rootScope.addressbook = AddressBook.$find($rootScope.addressbook.id); } else { $scope.search.status = 'min-char'; $rootScope.addressbook.cards = []; } } $scope.search.lastFilter = $scope.search.filter; }; }]) .controller('CardCtrl', ['$scope', '$rootScope', '$state', '$stateParams', '$ionicModal', '$ionicPopover', 'sgDialog', 'sgAddressBook', 'sgCard', 'stateCard', function($scope, $rootScope, $state, $stateParams, $ionicModal, $ionicPopover, Dialog, AddressBook, Card, stateCard) { $scope.card = stateCard; $scope.UserFolderURL = UserFolderURL; $scope.allEmailTypes = Card.$EMAIL_TYPES; $scope.allTelTypes = Card.$TEL_TYPES; $scope.allUrlTypes = Card.$URL_TYPES; $scope.allAddressTypes = Card.$ADDRESS_TYPES; $scope.search = {query: ""}; $scope.cardsFilter = function(item) { var query, id = false; if (item.tag == "vcard" && $scope.search.query) { query = $scope.search.query.toLowerCase(); if (item.emails && item.emails.length > 0) { // Is one of the email addresses match the query string? if (_.find(item.emails, function(email) { return (email.value.toLowerCase().indexOf(query) >= 0); })) id = item.id; } if (!id && item.fn) // Is the fn attribute matches the query string? if (item.fn.toLowerCase().indexOf(query) >= 0) id = item.id; if (id) { // Is the card already part of the members? If so, ignore it. if (_.find($scope.card.refs, function(ref) { return ref.reference == id; })) id = false; } } return id; }; $scope.resetSearch = function() { $scope.search.query = null; }; $scope.addMember = function(member) { var i = $scope.card.$addMember(''), email = member.$preferredEmail($scope.search.query); $scope.card.$updateMember(i, email, member); $scope.popover.hide(); }; $ionicPopover.fromTemplateUrl('searchFolderContacts.html', { scope: $scope, }).then(function(popover) { $scope.popover = popover; }); $scope.edit = function() { // Build modal editor $ionicModal.fromTemplateUrl('cardEditor.html', { scope: $scope, focusFirstInput: false }).then(function(modal) { if ($scope.$cardEditorModal) { // Delete previous modal $scope.$cardEditorModal.remove(); } $scope.$cardEditorModal = modal; // Show modal $scope.$cardEditorModal.show(); }); }; $scope.cancel = function() { if ($scope.card.isNew) { $scope.$cardEditorModal.hide().then(function() { // Go back to addressbook $state.go('app.addressbook', { addressbookId: $rootScope.addressbook.id }); }); } else { $scope.card.$reset(); $scope.$cardEditorModal.hide() } }; $scope.addOrgUnit = function() { var i = $scope.card.$addOrgUnit(''); focus('orgUnit_' + i); }; $scope.addCategory = function() { var i = $scope.card.$addCategory(''); focus('category_' + i); }; $scope.addEmail = function() { var i = $scope.card.$addEmail(''); focus('email_' + i); }; $scope.addPhone = function() { var i = $scope.card.$addPhone(''); focus('phone_' + i); }; $scope.addUrl = function() { var i = $scope.card.$addUrl('', ''); focus('url_' + i); }; $scope.addAddress = function() { var i = $scope.card.$addAddress('', '', '', '', '', '', '', ''); focus('address_' + i); }; $scope.showPopOver = function(keyEvent) { $scope.popover.show(keyEvent); } $scope.save = function(form) { if (form.$valid) { $scope.card.$save() .then(function(data) { var i; delete $scope.card.isNew; i = _.indexOf(_.pluck($rootScope.addressbook.cards, 'id'), $scope.card.id); if (i < 0) { // New card // Reload contacts list and show addressbook in which the card has been created $rootScope.addressbook = AddressBook.$find(data.pid); $state.go('app.addressbook', { addressbookId: data.pid }); } else { // Update contacts list with new version of the Card object $rootScope.addressbook.cards[i] = angular.copy($scope.card); } // Close editor $scope.$cardEditorModal.hide(); }); } }; $scope.confirmDelete = function(card) { Dialog.confirm(l('Warning'), l('Are you sure you want to delete the card of %{0}?', card.$fullname())) .then(function(res) { if (res) { // User confirmed the deletion card.$delete() .then(function() { // Remove card from list of addressbook $rootScope.addressbook.cards = _.reject($rootScope.addressbook.cards, function(o) { return o.id == card.id; }); // Remove card object from scope delete $scope.card; // Delete modal editor $scope.$cardEditorModal.remove(); // Go back to addressbook $state.go('app.addressbook', { addressbookId: $rootScope.addressbook.id }); }, function(data, status) { Dialog.alert(l('Warning'), l('An error occured while deleting the card "%{0}".', card.$fullname())); }); } }); }; if ($scope.card && $scope.card.isNew) { // New contact $scope.edit(); } }]); })();