diff options
Diffstat (limited to 'core/modules/user/user.permissions.js')
-rw-r--r-- | core/modules/user/user.permissions.js | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/core/modules/user/user.permissions.js b/core/modules/user/user.permissions.js index 0188fab2873..ae22cbb5e3d 100644 --- a/core/modules/user/user.permissions.js +++ b/core/modules/user/user.permissions.js @@ -1,18 +1,28 @@ /** -* DO NOT EDIT THIS FILE. -* See the following change record for more information, -* https://www.drupal.org/node/2815083 -* @preserve -**/ + * @file + * User permission page behaviors. + */ (function ($, Drupal) { + /** + * Shows checked and disabled checkboxes for inherited permissions. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches functionality to the permissions table. + */ Drupal.behaviors.permissions = { attach(context) { - once('permissions', 'table#permissions').forEach(table => { + once('permissions', 'table#permissions').forEach((table) => { + // On a site with many roles and permissions, this behavior initially + // has to perform thousands of DOM manipulations to inject checkboxes + // and hide them. By detaching the table from the DOM, all operations + // can be performed without triggering internal layout and re-rendering + // processes in the browser. const $table = $(table); let $ancestor; let method; - if ($table.prev().length) { $ancestor = $table.prev(); method = 'after'; @@ -20,25 +30,63 @@ $ancestor = $table.parent(); method = 'append'; } - $table.detach(); - const $dummy = $(Drupal.theme('checkbox')).removeClass('form-checkbox').addClass('dummy-checkbox js-dummy-checkbox').attr('disabled', 'disabled').attr('checked', 'checked').attr('title', Drupal.t('This permission is inherited from the authenticated user role.')).hide(); - $table.find('input[type="checkbox"]').not('.js-rid-anonymous, .js-rid-authenticated').addClass('real-checkbox js-real-checkbox').after($dummy); - $table.find('input[type=checkbox].js-rid-authenticated').on('click.permissions', this.toggle).each(this.toggle); + + // Create dummy checkboxes. We use dummy checkboxes instead of reusing + // the existing checkboxes here because new checkboxes don't alter the + // submitted form. If we'd automatically check existing checkboxes, the + // permission table would be polluted with redundant entries. This is + // deliberate, but desirable when we automatically check them. + const $dummy = $(Drupal.theme('checkbox')) + .removeClass('form-checkbox') + .addClass('dummy-checkbox js-dummy-checkbox') + .attr('disabled', 'disabled') + .attr('checked', 'checked') + .attr( + 'title', + Drupal.t( + 'This permission is inherited from the authenticated user role.', + ), + ) + .hide(); + + $table + .find('input[type="checkbox"]') + .not('.js-rid-anonymous, .js-rid-authenticated') + .addClass('real-checkbox js-real-checkbox') + .after($dummy); + + // Initialize the authenticated user checkbox. + $table + .find('input[type=checkbox].js-rid-authenticated') + .on('click.permissions', this.toggle) + // .triggerHandler() cannot be used here, as it only affects the first + // element. + .each(this.toggle); + + // Re-insert the table into the DOM. $ancestor[method]($table); }); }, + /** + * Toggles all dummy checkboxes based on the checkboxes' state. + * + * If the "authenticated user" checkbox is checked, the checked and disabled + * checkboxes are shown, the real checkboxes otherwise. + */ toggle() { const authCheckbox = this; const $row = $(this).closest('tr'); + // jQuery performs too many layout calculations for .hide() and .show(), + // leading to a major page rendering lag on sites with many roles and + // permissions. Therefore, we toggle visibility directly. $row.find('.js-real-checkbox').each(function () { this.style.display = authCheckbox.checked ? 'none' : ''; }); $row.find('.js-dummy-checkbox').each(function () { this.style.display = authCheckbox.checked ? '' : 'none'; }); - } - + }, }; -})(jQuery, Drupal);
\ No newline at end of file +})(jQuery, Drupal); |