Изменения документа AdminUsersSheet
Редактировал(а) Alexey Semenihin 23.10.2026, 15:12
От версии 1.1
отредактировано Admin xWiKi
на 15.10.2019, 13:19
на 15.10.2019, 13:19
Изменить комментарий:
Install extension [org.xwiki.platform:xwiki-platform-administration-ui/11.8.1]
К версии 4.1
отредактировано Alexey Semenihin
на 23.10.2026, 15:12
на 23.10.2026, 15:12
Изменить комментарий:
Install extension [org.xwiki.platform:xwiki-platform-administration-ui/17.10.12]
Сводка
-
Свойства страницы (3 изменено, 0 добавлено, 0 удалено)
-
Объекты (2 изменено, 0 добавлено, 0 удалено)
Подробности
- Свойства страницы
-
- Автор документа
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. admin1 +XWiki.semenihinaa - Синтаксис
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki 2. 01 +XWiki 2.1 - Содержимое
-
... ... @@ -1,52 +1,93 @@ 1 1 {{velocity output="false"}} 2 -#macro (userScopeFilter) 3 - <select name="wiki"> 4 - <option selected="selected" value="local"> 5 - $escapetool.xml($services.localization.render('rightsmanager.local')) 6 - </option> 7 - <option value="global"> 8 - $escapetool.xml($services.localization.render('rightsmanager.global')) 9 - </option> 10 - <option value="both"> 11 - $escapetool.xml($services.localization.render('rightsmanager.both')) 12 - </option> 13 - </select> 14 -#end 15 - 16 -#macro (displayUsersLiveTable) 17 - #set ($columnOptions = { 18 - 'name': {'type': 'text', 'sortable': false, 'html': true}, 19 - 'first_name': {'type': 'text', 'sortable': false}, 20 - 'last_name': {'type': 'text', 'sortable': false}, 21 - 'scope': {'type': 'list', 'sortable': false}, 22 - '_actions': { 23 - 'actions': [ 24 - 'edit', 25 - {'id': 'disable', 'icon': 'lock'}, 26 - {'id': 'enable', 'icon': 'unlock'}, 27 - 'delete' 28 - ], 29 - 'labels': false 30 - } 2 +#macro (displayUsersLiveData) 3 + #set ($properties = ['name', 'first_name', 'last_name', '_actions']) 4 + #set ($sourceParameters = { 5 + 'template': 'getusers.vm', 6 + 'translationPrefix': 'xe.admin.users.' 31 31 }) 32 - #set ($columns = ['name', 'first_name', 'last_name', '_actions']) 33 - #set ($liveTableOptions = { 34 - 'url': $doc.getURL('view', 'xpage=getusers'), 35 - 'translationPrefix': 'xe.admin.users.', 36 - 'outputOnlyHtml': true 37 - }) 38 38 #if (!$xcontext.isMainWiki()) 39 - #set ($discard = $columns.add(3, 'scope')) 40 - ## We use the top filters option to show only the local users by default because the JavaScript code from the sheet 41 - ## is executed after the livetable is loaded. The JavaScript code removes the top filters and updates the scope filter 42 - ## afterwards. 43 - #set ($liveTableOptions.topFilters = "#userScopeFilter") 9 + #set ($discard = $properties.add(3, 'scope')) 44 44 #end 45 45 <div class="medium-avatars"> 46 - #livetable('userstable' $columns $columnOptions $liveTableOptions) 12 + $services.liveData.render({ 13 + 'id': 'userstable', 14 + 'source': 'liveTable', 15 + 'properties': $stringtool.join($properties, ','), 16 + 'sourceParameters': $escapetool.url($sourceParameters) 17 + }, { 18 + 'query': { 19 + 'filters': [ 20 + { 21 + 'property': 'scope', 22 + 'constraints': [{ 23 + 'operator': 'contains', 24 + 'value': 'local' 25 + }] 26 + } 27 + ] 28 + }, 29 + 'meta': { 30 + 'propertyDescriptors': [ 31 + { 32 + 'id': 'name', 33 + 'displayer': 'html', 34 + 'sortable': false, 35 + 'editable': false 36 + }, 37 + { 38 + 'id': 'first_name', 39 + 'sortable': false, 40 + 'editable': false 41 + }, 42 + { 43 + 'id': 'last_name', 44 + 'sortable': false, 45 + 'editable': false 46 + }, 47 + { 48 + 'id': 'scope', 49 + 'sortable': false, 50 + 'editable': false, 51 + 'filter': { 52 + 'id': 'list', 53 + 'options': [ 54 + {'value': 'local', 'label': $services.localization.render('rightsmanager.local')}, 55 + {'value': 'global', 'label': $services.localization.render('rightsmanager.global')}, 56 + {'value': 'both', 'label': $services.localization.render('rightsmanager.both')} 57 + ] 58 + } 59 + }, 60 + { 61 + 'id': '_actions', 62 + 'displayer': { 63 + 'id': 'actions', 64 + 'actions': ['edit', 'disable', 'enable', 'delete'] 65 + } 66 + } 67 + ], 68 + 'actions': [ 69 + { 70 + 'id': 'disable', 71 + 'icon': 'lock', 72 + 'allowProperty': 'doc.hasdisable', 73 + 'urlProperty': 'doc.disable_url', 74 + 'extraIconClasses': 'text-warning' 75 + }, 76 + { 77 + 'id': 'enable', 78 + 'icon': 'unlock', 79 + 'allowProperty': 'doc.hasenable', 80 + 'urlProperty': 'doc.enable_url', 81 + 'extraIconClasses': 'text-success' 82 + } 83 + ] 84 + } 85 + }) 47 47 </div> 48 48 <p> 49 - <button type="button" class="btn btn-primary" data-toggle="modal" data-target="${escapetool.h}createUserModal"> 88 + <button type="button" class="btn btn-primary" data-toggle="modal" data-target="${escapetool.h}createUserModal" 89 + ## Disable the button until the JavaScript code that handles the user creation is ready. 90 + disabled="disabled"> 50 50 $escapetool.xml($services.localization.render('rightsmanager.addnewuser')) 51 51 </button> 52 52 </p> ... ... @@ -70,7 +70,9 @@ 70 70 <button type="button" class="btn btn-default" data-dismiss="modal"> 71 71 $escapetool.xml($services.localization.render('cancel')) 72 72 </button> 73 - <button type="button" class="btn btn-primary" disabled="disabled"> 114 + ## The registration form is not present on page load so we can't bind the submit button without triggerig an 115 + ## HTML validation error. That's why we set the form attribute from JavaScript instead. 116 + <button type="submit" class="btn btn-primary" disabled="disabled"> 74 74 $escapetool.xml($services.localization.render('create')) 75 75 </button> 76 76 </div> ... ... @@ -81,7 +81,7 @@ 81 81 82 82 #macro (editUserModal) 83 83 <div class="modal" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModal-label" 84 - data-backdrop="static" data-keyboard="false" data-live Table="#userstable" data-liveTableAction="edit">127 + data-backdrop="static" data-keyboard="false" data-live-data="#userstable" data-live-data-action="edit"> 85 85 <div class="modal-dialog modal-lg" role="document"> 86 86 <div class="modal-content"> 87 87 <div class="modal-header"> ... ... @@ -111,7 +111,7 @@ 111 111 ## have script or programming rights. 112 112 #userPicker_import 113 113 <div class="modal" id="deleteUserModal" tabindex="-1" role="dialog" aria-labelledby="deleteUserModal-label" 114 - data-live Table="#userstable" data-liveTableAction="delete">157 + data-live-data="#userstable" data-live-data-action="delete"> 115 115 <div class="modal-dialog" role="document"> 116 116 <div class="modal-content"> 117 117 <div class="modal-header"> ... ... @@ -165,11 +165,13 @@ 165 165 #macro (maybeShowDeleteUserWarning $userReference $right) 166 166 #countPagesLastModifiedBy($userReference) 167 167 #if ($pageCount > 0) 168 - <div class="box errormessage xform"> 211 + {{/html}} 212 + 213 + {{error cssClass="xform"}} 214 + {{html}} 169 169 #set ($pageIndexReference = $services.model.createDocumentReference( 170 170 $userReference.wikiReference.name, 'Main', 'AllDocs')) 171 - #set ($pageIndexURL = $xwiki.getURL($pageIndexReference) + '#|t=alldocs&doc.author=' + 172 - $escapetool.url($services.model.serialize($userReference, 'local'))) 217 + #set ($pageIndexURL = $xwiki.getURL($pageIndexReference, 'view', "doc.author=${escapetool.url($services.model.serialize($userReference, 'local'))}")) 173 173 #set ($translationKey = "administration.section.users.deleteUser.${right}RightsWarning") 174 174 $services.localization.render($translationKey, ["<a href='$pageIndexURL'>", $pageCount, '</a>']) 175 175 <dl> ... ... @@ -194,7 +194,10 @@ 194 194 [$rightTranslation]))</span> 195 195 </dd> 196 196 </dl> 197 - </div> 242 + {{/html}} 243 + {{/error}} 244 + 245 + {{html clean="false"}} 198 198 #end 199 199 #end 200 200 ... ... @@ -247,10 +247,10 @@ 247 247 #set ($discard = $xwiki.jsx.use("XWiki.AdminUsersSheet")) 248 248 249 249 {{html clean="false"}} 250 - #displayUsersLive Table251 - #createUserModal 252 - #editUserModal 253 - #deleteUserModal 298 + #displayUsersLiveData() 299 + #createUserModal() 300 + #editUserModal() 301 + #deleteUserModal() 254 254 {{/html}} 255 255 #end 256 256 #end
- XWiki.JavaScriptExtension[0]
-
- Код
-
... ... @@ -1,31 +1,25 @@ 1 1 require.config({ 2 2 paths: { 3 - 'xwiki-liveta ble-modal': new XWiki.Document('AdminGroupsSheet', 'XWiki').getURL('jsx', 'r=1')3 + 'xwiki-livedata-modal': new XWiki.Document('AdminGroupsSheet', 'XWiki').getURL('jsx', 'r=1') 4 4 } 5 5 }); 6 6 7 -// 8 -// Scope Filtering 9 -// 10 -require(['jquery'], function($) { 11 - var options = $('#userstable').prev('.tipfilters').remove().find('select[name="wiki"]').html(); 12 - var scopeFilter = $('#userstable .xwiki-livetable-display-filters select[name="scope"]') 13 - scopeFilter.attr('name', 'wiki').html(options); 14 -}); 15 - 16 -require(['jquery', 'xwiki-meta', 'xwiki-livetable-modal', 'xwiki-events-bridge'], function($, xm) { 7 +require(['jquery', 'xwiki-meta', 'xwiki-livedata-modal', 'xwiki-events-bridge'], function($, xm) { 17 17 // 18 18 // User Creation 19 19 // 20 - var createUserModal = $('#createUserModal'); 11 + const createUserModal = $('#createUserModal'); 12 + // We set the form attribute from JavaScript in order to avoid HTML validation errors because the form is not present 13 + // on page load (we load it the first time the modal is shown, see below). 14 + const createUserButton = createUserModal.find('.btn-primary').attr('form', 'register'); 21 21 22 22 var validateCreateUserForm = function(form) { 23 - return form. size()> 0&& (!window.LiveValidation ||17 + return form.length && (!window.LiveValidation || 24 24 LiveValidation.massValidate(LiveValidationForm.getInstance(form[0]).fields)); 25 25 }; 26 26 27 27 createUserModal.on('show.bs.modal', function() { 28 - varcreateUserButton= createUserModal.find('.btn-primary').prop('disabled', true);22 + createUserButton.prop('disabled', true); 29 29 var createUserURL = XWiki.currentDocument.getURL('view', 'xpage=registerinline'); 30 30 var createUserModalBody = createUserModal.find('.modal-body').empty().addClass('loading'); 31 31 $.get(createUserURL, function(html) { ... ... @@ -35,26 +35,27 @@ 35 35 createUserModalBody.removeClass('loading').append(createUserForm); 36 36 $(document).trigger('xwiki:dom:updated', {'elements': createUserModalBody.toArray()}); 37 37 createUserForm.find(':input').filter(':visible').first().focus(); 38 - createUserButton.prop('disabled', createUserForm. size()=== 0);32 + createUserButton.prop('disabled', !createUserForm.length); 39 39 }); 40 - }).on('click', '.btn-primary', function(event) { 34 + }).on('submit', 'form#register', function(event) { 35 + event.preventDefault(); 41 41 var createUserForm = createUserModal.find('form#register'); 42 42 if (!validateCreateUserForm(createUserForm)) { 43 43 return; 44 44 } 45 - varcreateUserButton= $(this).prop('disabled', true);40 + createUserButton.prop('disabled', true); 46 46 var notification = new XWiki.widgets.Notification( 47 47 $jsontool.serialize($services.localization.render('xe.admin.users.create.inProgress')), 48 48 'inprogress' 49 49 ); 50 - $.post(createUserForm.attr('action'), createUserForm.serialize()). done(function(html){45 + $.post(createUserForm.attr('action'), createUserForm.serialize()).then(html => { 51 51 var errorMessage = $('<div/>').html(html).find('.errormessage, .LV_validation_message.LV_invalid'); 52 - if (errorMessage. size()> 0){47 + if (errorMessage.length) { 53 53 createUserButton.prop('disabled', false); 54 54 notification.replace(new XWiki.widgets.Notification(errorMessage.text(), 'error')); 55 55 } else { 56 56 createUserModal.modal('hide'); 57 - window.livetable_userstable.refresh();52 + $('#userstable').data('liveData').updateEntries(); 58 58 $('#userstable').trigger('xwiki:user:created'); 59 59 notification.replace(new XWiki.widgets.Notification( 60 60 $jsontool.serialize($services.localization.render('xe.admin.users.create.done')), ... ... @@ -61,7 +61,7 @@ 61 61 'done' 62 62 )); 63 63 } 64 - }). fail(function(response) {59 + }).catch(() => { 65 65 createUserButton.prop('disabled', false); 66 66 notification.replace(new XWiki.widgets.Notification( 67 67 $jsontool.serialize($services.localization.render('xe.admin.users.create.failed')), ... ... @@ -78,20 +78,22 @@ 78 78 var loadEditForm = function(forceLock) { 79 79 var saveButton = editUserModal.find('.btn-primary').prop('disabled', true); 80 80 var rowData = editUserModal.data('rowData'); 81 - var userReference = XWiki.Model.resolve(rowData .doc_fullName, XWiki.EntityType.DOCUMENT, [rowData.doc_wiki]);76 + var userReference = XWiki.Model.resolve(rowData['doc.fullName'], XWiki.EntityType.DOCUMENT, [rowData['doc.wiki']]); 82 82 var userDocument = new XWiki.Document(userReference); 83 83 var editUserURL = userDocument.getURL('edit'); 84 84 var parameters = {xpage: 'edituser'}; 85 85 if (forceLock === true) { 81 + parameters.force_token = xm.form_token; 86 86 parameters.force = 1; 87 87 } 88 88 editUserModal.find('.modal-body').first().empty().addClass('loading').load(editUserURL, parameters, function() { 89 - this.removeClass('loading'); 90 - this.find('.column.half').removeClass('half').addClass('full'); 91 - $(document).trigger('xwiki:dom:updated', {'elements': this.toArray()}); 85 + var self = $(this); 86 + self.removeClass('loading'); 87 + self.find('.column.half').removeClass('half').addClass('full'); 88 + $(document).trigger('xwiki:dom:updated', {'elements': self.toArray()}); 92 92 var editUserForm = editUserModal.find('form#edituser'); 93 93 editUserForm.find(':input').filter(':visible').first().focus(); 94 - saveButton.prop('disabled', editUserForm. size()=== 0);91 + saveButton.prop('disabled', !editUserForm.length); 95 95 }); 96 96 }; 97 97 ... ... @@ -109,14 +109,14 @@ 109 109 'inprogress' 110 110 ); 111 111 $(document).trigger('xwiki:actions:beforeSave'); 112 - $.post(editForm.attr('action'), editForm.serialize()). done(function() {109 + $.post(editForm.attr('action'), editForm.serialize()).then(() => { 113 113 $(document).trigger('xwiki:document:saved'); 114 - editUserModal.modal('hide').data('live Table').refresh();111 + editUserModal.modal('hide').data('liveDataElement').data('liveData').updateEntries(); 115 115 notification.replace(new XWiki.widgets.Notification( 116 116 $jsontool.serialize($services.localization.render('core.editors.saveandcontinue.notification.done')), 117 117 'done' 118 118 )); 119 - }). fail(function(response){116 + }).catch(response => { 120 120 saveButton.prop('disabled', false); 121 121 var message = $jsontool.serialize($services.localization.render('core.editors.saveandcontinue.notification.error', 122 122 ['__reason__'])); ... ... @@ -145,29 +145,32 @@ 145 145 failed: $jsontool.serialize($services.localization.render('administration.section.users.disableUser.failed')) 146 146 } 147 147 } 148 - var onToggleUser = function(action, event) { 149 - event.preventDefault(); 150 - var actionTrigger = $(this); 151 - if (actionTrigger.hasClass('pending')) { 152 - // Another request is already in progress. 153 - return; 154 - } 155 - actionTrigger.addClass('pending'); 156 - var notification = new XWiki.widgets.Notification(notificationMessage[action].inProgress, 'inprogress'); 157 - // The enable and disable actions redirect to the user profile by default which may take a lot of time to render so 158 - // we redirect to a URL that doesn't render anything. 159 - var emptyResponseURL = new XWiki.Document('AdminUsersSheet', 'XWiki').getURL('get', 'outputSyntax=plain'); 160 - $.post(actionTrigger.attr('href'), {'xredirect': emptyResponseURL}).done(function() { 161 - window['livetable_userstable'].refresh(); 162 - notification.replace(new XWiki.widgets.Notification(notificationMessage[action].done, 'done')); 163 - }).fail(function() { 164 - notification.replace(new XWiki.widgets.Notification(notificationMessage[action].failed, 'error')); 165 - }).always(function() { 166 - actionTrigger.removeClass('pending'); 167 - }); 168 - }; 169 - $('#userstable').on('click', 'a.actionenable', $.proxy(onToggleUser, null, 'enable')); 170 - $('#userstable').on('click', 'a.actiondisable', $.proxy(onToggleUser, null, 'disable')); 145 + 146 + function onToggleUser(action) { 147 + return function (event) { 148 + event.preventDefault(); 149 + var actionTrigger = $(this); 150 + if (actionTrigger.hasClass('pending')) { 151 + // Another request is already in progress. 152 + return; 153 + } 154 + actionTrigger.addClass('pending'); 155 + var notification = new XWiki.widgets.Notification(notificationMessage[action].inProgress, 'inprogress'); 156 + // The enable and disable actions redirect to the user profile by default which may take a lot of time to 157 + // render so we redirect to a URL that doesn't render anything. 158 + var emptyResponseURL = new XWiki.Document('AdminUsersSheet', 'XWiki').getURL('get', 'outputSyntax=plain'); 159 + Promise.resolve($.post(actionTrigger.attr('href'), {'xredirect': emptyResponseURL})).then(function () { 160 + $('#userstable').data('liveData').updateEntries(); 161 + notification.replace(new XWiki.widgets.Notification(notificationMessage[action].done, 'done')); 162 + }).catch(function () { 163 + notification.replace(new XWiki.widgets.Notification(notificationMessage[action].failed, 'error')); 164 + }).finally(function () { 165 + actionTrigger.removeClass('pending'); 166 + }); 167 + }; 168 + } 169 + $(document).on('click', '#userstable a.action_enable', onToggleUser('enable')); 170 + $(document).on('click', '#userstable a.action_disable', onToggleUser('disable')); 171 171 })(); 172 172 173 173 // ... ... @@ -201,9 +201,9 @@ 201 201 202 202 deleteUserModal.on('show.bs.modal', function() { 203 203 var rowData = deleteUserModal.data('rowData'); 204 - var userReference = rowData .doc_fullName;205 - if (XWiki.currentWiki !== rowData .doc_wiki) {206 - userReference = XWiki.Model.resolve(userReference, XWiki.EntityType.DOCUMENT, [rowData .doc_wiki]);204 + var userReference = rowData['doc.fullName']; 205 + if (XWiki.currentWiki !== rowData['doc.wiki']) { 206 + userReference = XWiki.Model.resolve(userReference, XWiki.EntityType.DOCUMENT, [rowData['doc.wiki']]); 207 207 userReference = XWiki.Model.serialize(userReference); 208 208 } 209 209 deleteUserModal.data('userReference', userReference); ... ... @@ -224,9 +224,9 @@ 224 224 newAuthor: newAuthor, 225 225 requiredRight: requiredRight 226 226 }); 227 - return newAuthorValidationRequest; 227 + return Promise.resolve(newAuthorValidationRequest); 228 228 } else { 229 - return $.Deferred().resolve({valid: true}).promise();229 + return Promise.resolve({valid: true}); 230 230 } 231 231 }; 232 232 deleteUserModal.on('change', '#newAuthor', function(event) { ... ... @@ -235,17 +235,17 @@ 235 235 var newAuthorField = $(event.target); 236 236 // Hide the previous error message. 237 237 newAuthorField.nextAll('.xErrorMsg').addClass('hidden'); 238 - validateNewAuthor(newAuthorField.val(), newAuthorField.data('requiredRight')). done(function(result) {238 + validateNewAuthor(newAuthorField.val(), newAuthorField.data('requiredRight')).then(function(result) { 239 239 if (result.valid === false) { 240 240 newAuthorField.nextAll('.xErrorMsg').removeClass('hidden'); 241 241 } 242 - }).al ways(function() {242 + }).finally(function() { 243 243 // Re-enable the modal submit button. 244 244 deleteUserButton.prop('disabled', false); 245 245 }); 246 246 }); 247 247 248 - deleteUserButton.click (function() {248 + deleteUserButton.on('click', function() { 249 249 var notification = new XWiki.widgets.Notification( 250 250 $jsontool.serialize($services.localization.render('xe.admin.users.delete.inProgress')), 251 251 'inprogress' ... ... @@ -256,14 +256,14 @@ 256 256 docname: userReference, 257 257 newAuthor: deleteUserModal.find('#newAuthor').val(), 258 258 form_token: xm.form_token 259 - }). done(function() {260 - deleteUserModal.data('live Table').deleteRow(deleteUserModal.data('rowIndex'));261 - deleteUserModal.data('live TableElement').trigger('xwiki:user:deleted', {reference: userReference});259 + }).then(() => { 260 + deleteUserModal.data('liveDataElement').data('liveData').updateEntries(); 261 + deleteUserModal.data('liveDataElement').trigger('xwiki:user:deleted', {reference: userReference}); 262 262 notification.replace(new XWiki.widgets.Notification( 263 263 $jsontool.serialize($services.localization.render('xe.admin.users.delete.done')), 264 264 'done' 265 265 )); 266 - }). fail(function() {266 + }).catch(() => { 267 267 notification.replace(new XWiki.widgets.Notification( 268 268 $jsontool.serialize($services.localization.render('xe.admin.users.delete.failed')), 269 269 'error' ... ... @@ -270,4 +270,7 @@ 270 270 )); 271 271 }); 272 272 }); 273 + 274 + // Finally, enable the user creation. 275 + $('button[data-target="#createUserModal"]').prop('disabled', false); 273 273 });
- XWiki.StyleSheetExtension[0]
-
- Код
-
... ... @@ -1,19 +3,4 @@ 1 -#template('colorThemeInit.vm') 2 - 3 3 /** 4 - * Users Live Table 5 - */ 6 -#userstable td[data-title] { 7 - vertical-align: middle; 8 -} 9 -#userstable .actiondisable .action-icon { 10 - color: $theme.notificationWarningColor; 11 -} 12 -#userstable .actionenable .action-icon { 13 - color: $theme.notificationSuccessColor; 14 -} 15 - 16 -/** 17 17 * Delete User Modal 18 18 */ 19 19 #deleteUserModal .userName { - Content Type
-
... ... @@ -1,1 +1,1 @@ 1 - CSS1 +LESS - Разбор содержимого
-
... ... @@ -1,1 +1,1 @@ 1 - Да1 +Нет