Add user picker property editor (#7613)
This commit is contained in:
committed by
GitHub
parent
2ca7cc9ccc
commit
41d1e33fc4
@@ -295,6 +295,38 @@
|
||||
"Failed to retrieve data for user " + userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.usersResource#getUsers
|
||||
* @methodOf umbraco.resources.usersResource
|
||||
*
|
||||
* @description
|
||||
* Gets users from ids
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* usersResource.getUsers([1,2,3])
|
||||
* .then(function(data) {
|
||||
* alert("It's here");
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} userIds user ids.
|
||||
* @returns {Promise} resourcePromise object containing the users array.
|
||||
*
|
||||
*/
|
||||
function getUsers(userIds) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"userApiBaseUrl",
|
||||
"GetByIds",
|
||||
{ ids: userIds })),
|
||||
"Failed to retrieve data for users " + userIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.usersResource#createUser
|
||||
@@ -481,6 +513,7 @@
|
||||
setUserGroupsOnUsers: setUserGroupsOnUsers,
|
||||
getPagedResults: getPagedResults,
|
||||
getUser: getUser,
|
||||
getUsers: getUsers,
|
||||
createUser: createUser,
|
||||
inviteUser: inviteUser,
|
||||
saveUser: saveUser,
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid @gray-9;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.umb-editor-wrapper .umb-user-preview {
|
||||
.umb-property-editor--limit-width();
|
||||
}
|
||||
|
||||
.umb-user-preview:last-of-type {
|
||||
@@ -29,22 +34,26 @@
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.umb-user-preview__action {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
border: 0 none;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: @gray-5;
|
||||
color: @ui-action-type;
|
||||
}
|
||||
|
||||
.umb-user-preview__action:hover {
|
||||
color: @turquoise;
|
||||
color: @ui-action-type-hover;
|
||||
text-decoration: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-user-preview__action--red:hover {
|
||||
color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
+38
-20
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function UserPickerController($scope, usersResource, localizationService) {
|
||||
function UserPickerController($scope, usersResource, localizationService, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -15,15 +15,18 @@
|
||||
vm.submit = submit;
|
||||
vm.close = close;
|
||||
|
||||
//////////
|
||||
vm.multiPicker = $scope.model.multiPicker === false ? false : true;
|
||||
|
||||
function onInit() {
|
||||
|
||||
vm.loading = true;
|
||||
|
||||
// set default title
|
||||
if(!$scope.model.title) {
|
||||
localizationService.localize("defaultdialogs_selectUsers").then(function(value){
|
||||
if (!$scope.model.title) {
|
||||
|
||||
var labelKey = vm.multiPicker ? "defaultdialogs_selectUsers" : "defaultdialogs_selectUser";
|
||||
|
||||
localizationService.localize(labelKey).then(function(value){
|
||||
$scope.model.title = value;
|
||||
});
|
||||
}
|
||||
@@ -35,12 +38,11 @@
|
||||
|
||||
// get users
|
||||
getUsers();
|
||||
|
||||
}
|
||||
|
||||
function preSelect(selection, users) {
|
||||
angular.forEach(selection, function(selected){
|
||||
angular.forEach(users, function(user){
|
||||
Utilities.forEach(selection, function(selected){
|
||||
Utilities.forEach(users, function(user){
|
||||
if(selected.id === user.id) {
|
||||
user.selected = true;
|
||||
}
|
||||
@@ -50,22 +52,39 @@
|
||||
|
||||
function selectUser(user) {
|
||||
|
||||
if(!user.selected) {
|
||||
|
||||
if (!user.selected) {
|
||||
user.selected = true;
|
||||
$scope.model.selection.push(user);
|
||||
|
||||
} else {
|
||||
|
||||
angular.forEach($scope.model.selection, function(selectedUser, index){
|
||||
if(selectedUser.id === user.id) {
|
||||
user.selected = false;
|
||||
$scope.model.selection.splice(index, 1);
|
||||
if (user.selected) {
|
||||
Utilities.forEach($scope.model.selection, function (selectedUser, index) {
|
||||
if (selectedUser.id === user.id) {
|
||||
user.selected = false;
|
||||
$scope.model.selection.splice(index, 1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!vm.multiPicker) {
|
||||
deselectAllUsers($scope.model.selection);
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.emit("dialogs.userPicker.select", user);
|
||||
user.selected = true;
|
||||
$scope.model.selection.push(user);
|
||||
}
|
||||
}
|
||||
|
||||
if (!vm.multiPicker) {
|
||||
submit($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
function deselectAllUsers(users) {
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
var user = users[i];
|
||||
user.selected = false;
|
||||
}
|
||||
users.length = 0;
|
||||
}
|
||||
|
||||
var search = _.debounce(function () {
|
||||
@@ -95,7 +114,6 @@
|
||||
preSelect($scope.model.selection, vm.users);
|
||||
|
||||
vm.loading = false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,14 +123,14 @@
|
||||
}
|
||||
|
||||
function submit(model) {
|
||||
if($scope.model.submit) {
|
||||
if ($scope.model.submit) {
|
||||
$scope.model.submit(model);
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close();
|
||||
if ($scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -19,7 +19,7 @@
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<div class="form-search" style="margin-bottom: 15px;">
|
||||
<i class="icon-search"></i>
|
||||
<i class="icon-search" aria-hidden="true"></i>
|
||||
<input type="text"
|
||||
ng-model="vm.usersOptions.filter"
|
||||
ng-change="vm.searchUsers()"
|
||||
@@ -78,7 +78,9 @@
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
ng-if="vm.multiPicker"
|
||||
type="button"
|
||||
disabled="model.selection.length === 0"
|
||||
button-style="success"
|
||||
label-key="general_submit"
|
||||
action="vm.submit(model)">
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-user-preview__actions">
|
||||
<button type="button" class="umb-user-preview__action umb-user-preview__action--red btn-link" title="Remove" ng-if="allowRemove" ng-click="onRemove()"><localize key="general_remove">Remove</localize></button>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="umb-user-preview__action umb-user-preview__action--red btn-link"
|
||||
title="Remove {{name}}"
|
||||
ng-if="allowRemove"
|
||||
ng-click="onRemove()">
|
||||
<localize key="general_remove">Remove</localize>
|
||||
<span class="sr-only">{{name}}</span>
|
||||
</button>
|
||||
<div>
|
||||
</div>
|
||||
|
||||
+1
-2
@@ -56,10 +56,9 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
|
||||
};
|
||||
|
||||
editorService.treePicker(memberPicker);
|
||||
|
||||
};
|
||||
|
||||
$scope.remove =function(index){
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<a ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
href="#"
|
||||
ng-click="openMemberPicker()"
|
||||
prevent-default>
|
||||
ng-click="openMemberPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</button>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
function userPickerController($scope, usersResource , iconHelper, editorService){
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
|
||||
$scope.renderModel = [];
|
||||
$scope.allowRemove = true;
|
||||
|
||||
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
|
||||
|
||||
$scope.openUserPicker = function () {
|
||||
|
||||
var currentSelection = [];
|
||||
var userPicker = {
|
||||
multiPicker: multiPicker,
|
||||
selection: currentSelection,
|
||||
submit: function (model) {
|
||||
if (model.selection) {
|
||||
_.each(model.selection, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
editorService.userPicker(userPicker);
|
||||
};
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.add = function (item) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
if ($scope.model.config.idType === "udi") {
|
||||
return i.udi;
|
||||
}
|
||||
else {
|
||||
return i.id;
|
||||
}
|
||||
});
|
||||
|
||||
var itemId = $scope.model.config.idType === "udi" ? item.udi : item.id;
|
||||
|
||||
if (currIds.indexOf(itemId) < 0) {
|
||||
item.icon = item.icon ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user";
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon, avatars: item.avatars });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
if ($scope.model.config.idType === "udi") {
|
||||
return i.udi;
|
||||
}
|
||||
else {
|
||||
return i.id;
|
||||
}
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
//load user data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
// entityResource.getByIds doesn't support "User" and we would like to show avatars in umb-user-preview as well.
|
||||
usersResource.getUsers(modelIds).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
// set default icon if it's missing
|
||||
item.icon = item.icon ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user";
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon, avatars: item.avatars });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.UserPickerController", userPickerController);
|
||||
@@ -0,0 +1,21 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.UserPickerController" class="umb-property-editor umb-userpicker">
|
||||
|
||||
<div>
|
||||
<umb-user-preview
|
||||
ng-repeat="user in renderModel"
|
||||
name="user.name"
|
||||
avatars="user.avatars"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-user-preview>
|
||||
</div>
|
||||
|
||||
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="openUserPicker()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
|
||||
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
|
||||
|
||||
</div>
|
||||
@@ -469,6 +469,7 @@
|
||||
<key alias="selectMemberType">Vælg medlemstype</key>
|
||||
<key alias="selectNode">Vælg node</key>
|
||||
<key alias="selectSections">Vælg sektioner</key>
|
||||
<key alias="selectUser">Vælg bruger</key>
|
||||
<key alias="selectUsers">Vælg brugere</key>
|
||||
<key alias="noIconsFound">Ingen ikoner blev fundet</key>
|
||||
<key alias="noMacroParams">Der er ingen parametre for denne makro</key>
|
||||
|
||||
@@ -491,6 +491,7 @@
|
||||
<key alias="selectMemberType">Select member type</key>
|
||||
<key alias="selectNode">Select node</key>
|
||||
<key alias="selectSections">Select sections</key>
|
||||
<key alias="selectUser">Select user</key>
|
||||
<key alias="selectUsers">Select users</key>
|
||||
<key alias="noIconsFound">No icons were found</key>
|
||||
<key alias="noMacroParams">There are no parameters for this macro</key>
|
||||
|
||||
@@ -496,6 +496,7 @@
|
||||
<key alias="selectMemberType">Select member type</key>
|
||||
<key alias="selectNode">Select node</key>
|
||||
<key alias="selectSections">Select sections</key>
|
||||
<key alias="selectUser">Select user</key>
|
||||
<key alias="selectUsers">Select users</key>
|
||||
<key alias="noIconsFound">No icons were found</key>
|
||||
<key alias="noMacroParams">There are no parameters for this macro</key>
|
||||
|
||||
@@ -178,6 +178,33 @@ namespace Umbraco.Web.Editors
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get users by integer ids
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
[AdminUsersAuthorize]
|
||||
public IEnumerable<UserDisplay> GetByIds([FromJsonPath]int[] ids)
|
||||
{
|
||||
if (ids == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
if (ids.Length == 0)
|
||||
return Enumerable.Empty<UserDisplay>();
|
||||
|
||||
var users = Services.UserService.GetUsersById(ids);
|
||||
if (users == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var result = Mapper.MapEnumerable<IUser, UserDisplay>(users);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged users collection
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
public override IDictionary<string, object> DefaultConfiguration => new Dictionary<string, object>
|
||||
{
|
||||
{"entityType", "User"}
|
||||
{ "entityType", "User" },
|
||||
{ "multiPicker", "0" }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.UserPicker,
|
||||
"User picker",
|
||||
"entitypicker",
|
||||
"User Picker",
|
||||
"userpicker",
|
||||
ValueType = ValueTypes.Integer,
|
||||
Group = Constants.PropertyEditors.Groups.People,
|
||||
Icon = Constants.Icons.User)]
|
||||
|
||||
Reference in New Issue
Block a user