summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwebchick <webchick@24967.no-reply.drupal.org>2011-07-03 10:48:40 -0700
committerwebchick <webchick@24967.no-reply.drupal.org>2011-07-03 10:48:40 -0700
commita79e2f074f923046cb0401950178b2108683a1eb (patch)
tree6b736af742bd9187ba9062a7be71b0da5c246ec2
parent214fb8de72c757418cee693391a2747e9d42451a (diff)
downloadbrdo-a79e2f074f923046cb0401950178b2108683a1eb.tar.gz
brdo-a79e2f074f923046cb0401950178b2108683a1eb.tar.bz2
Issue #1203766 by sun, lyricnz: Fixed With large number of permissions /admin/people/permissions becomes unusable.
-rw-r--r--modules/user/user.admin.inc7
-rw-r--r--modules/user/user.permissions.js70
2 files changed, 56 insertions, 21 deletions
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
index 0596bde4c..0044b18a4 100644
--- a/modules/user/user.admin.inc
+++ b/modules/user/user.admin.inc
@@ -712,7 +712,12 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
// Have to build checkboxes here after checkbox arrays are built
foreach ($role_names as $rid => $name) {
- $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => isset($status[$rid]) ? $status[$rid] : array());
+ $form['checkboxes'][$rid] = array(
+ '#type' => 'checkboxes',
+ '#options' => $options,
+ '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
+ '#attributes' => array('class' => array('rid-' . $rid)),
+ );
$form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
}
diff --git a/modules/user/user.permissions.js b/modules/user/user.permissions.js
index 4ef576cd4..988820e12 100644
--- a/modules/user/user.permissions.js
+++ b/modules/user/user.permissions.js
@@ -5,34 +5,64 @@
*/
Drupal.behaviors.permissions = {
attach: function (context) {
- $('table#permissions:not(.permissions-processed)').each(function () {
+ var self = this;
+ $('table#permissions').once('permissions', function () {
+ // 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.
+ var $table = $(this);
+ if ($table.prev().length) {
+ var $ancestor = $table.prev(), method = 'after';
+ }
+ else {
+ var $ancestor = $table.parent(), method = 'append';
+ }
+ $table.detach();
+
// 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.
- $(':checkbox', this).not('[name^="2["]').not('[name^="1["]').each(function () {
- $(this).addClass('real-checkbox');
- $('<input type="checkbox" class="dummy-checkbox" disabled="disabled" checked="checked" />')
- .attr('title', Drupal.t("This permission is inherited from the authenticated user role."))
- .insertAfter(this)
- .hide();
- });
+ var $dummy = $('<input type="checkbox" class="dummy-checkbox" disabled="disabled" checked="checked" />')
+ .attr('title', Drupal.t("This permission is inherited from the authenticated user role."))
+ .hide();
- // Helper function 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.
- var toggle = function () {
- $(this).closest('tr')
- .find('.real-checkbox')[this.checked ? 'hide' : 'show']().end()
- .find('.dummy-checkbox')[this.checked ? 'show' : 'hide']();
- };
+ $('input[type=checkbox]', this).not('.rid-2, .rid-1').addClass('real-checkbox').each(function () {
+ $dummy.clone().insertAfter(this);
+ });
// Initialize the authenticated user checkbox.
- $(':checkbox[name^="2["]', this)
- .click(toggle)
- .each(function () { toggle.call(this); });
- }).addClass('permissions-processed');
+ $('input[type=checkbox].rid-2', this)
+ .bind('click.permissions', self.toggle)
+ // .triggerHandler() cannot be used here, as it only affects the first
+ // element.
+ .each(self.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: function () {
+ var authCheckbox = this, $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('.real-checkbox').each(function () {
+ this.style.display = (authCheckbox.checked ? 'none' : '');
+ });
+ $row.find('.dummy-checkbox').each(function () {
+ this.style.display = (authCheckbox.checked ? '' : 'none');
+ });
}
};