(function () {
'use strict';
angular.module('api.module.Components')
/**
* @class api.module.Components.directives.EloUserSelection
* @transclusion
* @ngDirective
* @xtype elo-user-selection
*
* This directive provides a user selection component. Depending on
* its configuration a set of chosen users can be selected from a set
* of given choices.
*
* For every selected user a data object will be created, that can be
* altered in order to configure any data for a selected user.
*
* # Example:
*
* <elo-user-selection config="store.config" chosen-users="store.users" chosen-data="store.data" selected-index="store.index">
* ...
* </elo-user-selection>
*
* Here all selected users will appear in the chosen-users array of
* de.elo.ix.client.UserInfo objects (i.e. store.users will hold this array).
* The array chosen-data will always have the same length as chosen-users (i.e. store.data).
* The users are bound by index to their according data object.
* The index of the selected user in the list will be selected-index
* (i.e. store.index).
*
* # Transclusion:
* This directive uses transclusion. Inside it their can be a form that
* will fill the data object of the selected user (in the example
* above store.data[store.index] as ngModel).
*
* @cfg {Object} config
* The config object of the user selection. It can hold:
*
* @cfg {String} config.label
* A string message that is displayed above the user selection.
*
* @cfg {String} config.placeholder
* A string message that is displayed in the empty user selection.
*
* @cfg {Array} config.sourceUsers
* An array of de.elo.ix.client.UserName objects that are the users that can be selected.
*
* @cfg {Number} config.type
* The type of users that can be selected (see: api.ix.ListUtils.listUsers),
* one of USERTYPE_USER, USERTYPE_GROUP, USERTYPE_BOTH.
* Please chose carefull the use of *_INCL_INVISIBLE constants here.
*
* @cfg {Boolean} config.isDynamic
* True to use a dynamic search to retrieve the users in the list.
* If this is set a optional FindUserInfo object can be given
* in config.findUserInfo to modify the search. Only the name of
* the FindUserInfo object will be overwritten by the input of the field.
* This option produces more communication requests to the
* server and should be used if the number of possible users is very large (>1000).
* With this option the config.type constant will still be evaluated to filter invisible users.
*
* @cfg {Object} config.findUserInfo
* A de.elo.ix.client.FindUserInfo object to use for the dynamic
* search. It will be ignored, if config.isDynamic is not set to true.
* If the onlyGroups and onlyUsers properties in this object
* conflict with the config.type constant it is possible, that
* to many or to view users will be present.
*
* @cfg {Boolean} config.singleSelect
* True to only select one user.
*
* @cfg {Object} config.defaultData
* An object that should hold the initial data for a new selected user.
* A clone of that object will be added to chosenData if a new user is added to chosenUsers.
*
* @cfg {Boolean} config.ordered
* True to add move capabilities. This is needed if the order of
* selected users is relevant.
*
* @cfg {String} config.dataTemplate
* A template string to visualize the data object of every user inside the selected user list.
* The data object of the user can accessed by chosenData[$index] in the template string.
*
* @cfg {Funtion} config.onAddUser
* Event function that triggers if a user is selected in the dropdown.
* The function gets the new UserInfo object and the scope as parameters.
* If the function returns true the user will be added or replaced (in case
* of singleSelect) if the function returns false the event is cancelled.
* If this event is not given, a user is only added if it is not already in the list.
*
* @cfg {Boolean} config.expandGroups
* true to add functionality to expand a group into their members. This
* has not effect if singleSelect is true.
*
*
* @cfg {Array} chosenUsers
* The list of current selected users as array of
* de.elo.ix.client.UserInfo objects.
*
* @cfg {Array} chosenData
* The list of data objects for chosenUsers.
*
* @cfg {Number} index
* The index of the current selected user in the list.
*/
.directive('eloUserSelection', [function () {
return {
restrict: 'E',
transclude: true,
replace: true,
scope: {
config: '=',
selectedIndex: '=',
chosenUsers: '=',
chosenData: '='
},
controller: ['$scope', 'InputUtilsFactory', function ($scope, InputUtilsFactory) {
$scope.store = {
everyoneGroup: elo.CONST.USER_INFO.ID_EVERYONE_GROUP
};
$scope.loadingMask = false;
$scope.initAll = function () {
var i, factOptions;
$scope.filtered = {};
$scope.userInputConfig = {};
if (!$scope.chosenUsers) {
$scope.chosenUsers = [];
}
if (!$scope.chosenData) {
$scope.chosenData = [];
}
if ($scope.chosenUsers.length > 0 && $scope.chosenData.length < $scope.chosenUsers.length) {
for (i = $scope.chosenData.length; i < $scope.chosenUsers.length; i += 1) {
$scope.chosenData.push($scope.initDefaultData());
}
}
if (!$scope.config) {
elo.helpers.Console.error('api.module.Components.eloUserSelection: Config object missing');
return;
}
$scope.userInputConfig.label = $scope.config.label;
$scope.userInputConfig.placeholder = $scope.config.placeholder;
$scope.userInputConfig.name = 'userInfo';
$scope.userInputConfig.focused = true;
factOptions = {};
factOptions.sourceUsers = $scope.config.sourceUsers;
factOptions.type = $scope.config.type;
factOptions.isDynamic = $scope.config.isDynamic;
factOptions.findUserInfo = $scope.config.findUserInfo;
$scope.userInputConfig = InputUtilsFactory.addUserListConfig($scope.userInputConfig, factOptions);
$scope.userInputConfig.kwl.onSelect = $scope.addUser;
// remove to many initial users if singleSelect
if ($scope.config.singleSelect && $scope.chosenUsers.length > 1) {
$scope.chosenUsers = [$scope.chosenUsers[0]];
}
};
// DO NOT CHANGE BEHAVIOUR USED IN ONADDUSER
$scope.initDefaultData = function () {
if ($scope.config.defaultData && $scope.config.defaultData.constructor === Object) {
return angular.copy($scope.config.defaultData);
}
return {};
};
$scope.angularIndexOf = function (arr, obj) {
var i;
for (i = 0; i < arr.length; i += 1) {
if (angular.equals(arr[i], obj)) {
return i;
}
}
return -1;
};
$scope.addUser = function ($item, $model, $label) {
$scope.filtered = {};
if ($scope.config.singleSelect && (!$scope.config.onAddUser || $scope.config.onAddUser($item, $scope))) {
$scope.chosenUsers = [$item];
$scope.chosenData = [$scope.initDefaultData()];
$scope.selectedIndex = 0;
} else if ((!$scope.config.onAddUser && $scope.angularIndexOf($scope.chosenUsers, $item) === -1) || ($scope.config.onAddUser && $scope.config.onAddUser($item, $scope))) {
$scope.chosenUsers.push($item);
$scope.chosenData.push($scope.initDefaultData());
$scope.selectedIndex = $scope.chosenUsers.length - 1;
}
};
$scope.removeSelection = function (userId) {
var i;
for (i = 0; i < $scope.chosenUsers.length; i += 1) {
if ($scope.chosenUsers[i].id === userId) {
$scope.chosenUsers.splice(i, 1);
$scope.chosenData.splice(i, 1);
if ($scope.chosenUsers.length <= i && $scope.selectedIndex === i) {
// last item was removed, unselect
$scope.selectedIndex = -1;
}
break;
}
}
};
$scope.expandSelection = function (userId) {
var i, group, groupData;
for (i = 0; i < $scope.chosenUsers.length; i += 1) {
if ($scope.chosenUsers[i].id === userId) {
if ($scope.config.expandGroups && $scope.chosenUsers[i].type === api.CONST.USER_INFO.TYPE_GROUP) {
group = $scope.chosenUsers.splice(i, 1)[0];
groupData = $scope.chosenData.splice(i, 1)[0];
break;
}
}
}
if (group && groupData) {
// expand group
$scope.loadingMask = {
loading: true,
noLoadingMsg: true
};
api.IX.ix().checkoutUsers([group.id], api.CONST.CHECKOUT_USERS.MEMBERS_OF_GROUP, api.CONST.LOCK.NO, new de.elo.ix.client.AsyncCallback(
function (users) {
var h, j, found;
for (h = 0; h < users.length; h += 1) {
found = false;
for (j = 0; j < $scope.chosenUsers.length; j += 1) {
if (users[h].id === $scope.chosenUsers[j].id) {
found = true;
break;
}
}
if (!found) {
$scope.chosenUsers.splice(i, 0, users[h]);
$scope.chosenData.splice(i, 0, groupData);
}
}
$scope.loadingMask = false;
$scope.$apply();
}, function (e) {
elo.helpers.Console.error(api.helpers.Text.getText("ELOCMP.ERROR"), e.toString());
api.webapps.WebApp.showToast(api.helpers.Text.getText("ELOCMP.ERROR"), e.toString(), api.webapps.WebApp.TOAST_TYPE.ERROR);
$scope.loadingMask = false;
$scope.$apply();
}));
}
};
$scope.selectUser = function (index) {
$scope.selectedIndex = index;
};
$scope.listItemClass = function (idx) {
if (idx === $scope.selectedIndex) {
return 'list-group-item selected-user active';
}
return 'list-group-item selected-user';
};
$scope.move = function (oldIndex, newIndex) {
var tmp1, tmp2;
tmp1 = $scope.chosenUsers.splice(oldIndex, 1)[0];
tmp2 = $scope.chosenData.splice(oldIndex, 1)[0];
$scope.chosenUsers.splice(newIndex, 0, tmp1);
$scope.chosenData.splice(newIndex, 0, tmp2);
};
$scope.userSelectionTracking = function (index, user) {
return [user.id, index].join(' ');
};
$scope.initAll();
}
],
templateUrl: api.module.Components.relativeUrl + 'directives/user-selection/user-selection.html'
};
}]);
}());