core/modules/system/system.admin.inc | 24 ++++++++++++--
core/modules/system/system.base.css | 10 ++++++
core/modules/system/system.module | 2 +-
core/modules/system/system.modules.js | 56 +++++++++++++++++++++++++++++++++
4 files changed, 89 insertions(+), 3 deletions(-)
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 37a2bf2..88b869c 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -809,6 +809,26 @@ function system_modules($form, $form_state = array()) {
return system_modules_confirm_form($visible_files, $form_state['storage']);
}
+ // JavaScript-only table filters.
+ $form['filters'] = array(
+ '#type' => 'container',
+ '#attributes' => array(
+ 'class' => array('table-filter', 'js-show'),
+ ),
+ );
+ $form['filters']['text'] = array(
+ '#type' => 'search',
+ '#title' => t('Search module list'),
+ '#title_display' => 'invisible',
+ '#size' => 20,
+ '#placeholder' => t('Search modules...'),
+ '#attributes' => array(
+ 'class' => array('table-filter-text'),
+ 'data-table' => '#system-modules',
+ 'autocomplete' => 'off',
+ ),
+ );
+
$modules = array();
$form['modules'] = array('#tree' => TRUE);
@@ -2336,11 +2356,11 @@ function theme_system_modules_details($variables) {
$row[] = array('class' => array('checkbox'), 'data' => drupal_render($module['enable']));
// Add the module label and expand/collapse functionalty.
- $col2 = '';
+ $col2 = '';
$row[] = array('class' => array('module'), 'data' => $col2);
// Add the description, along with any modules it requires.
- $description = '' . drupal_render($module['description']) . '';
+ $description = '' . drupal_render($module['description']) . '';
if ($version || $requires || $required_by) {
$description .= '
';
if ($version) {
diff --git a/core/modules/system/system.base.css b/core/modules/system/system.base.css
index 233c6d7..c386b3e 100644
--- a/core/modules/system/system.base.css
+++ b/core/modules/system/system.base.css
@@ -204,6 +204,16 @@ tr .ajax-progress-throbber .throbber {
}
/**
+ * For anything you want to show on page load only when JS is enabled.
+ */
+.js-show {
+ display: none;
+}
+.js .js-show {
+ display: block;
+}
+
+/**
* Hide elements from all users.
*
* Used for elements which should not be immediately displayed to any user. An
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index c621915..6d25a04 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2133,7 +2133,7 @@ function system_library_info() {
),
);
$libraries['drupal.system.modules'] = array(
- 'title' => 'System cron',
+ 'title' => 'System modules',
'version' => VERSION,
'js' => array(
drupal_get_path('module', 'system') . '/system.modules.js' => array(),
diff --git a/core/modules/system/system.modules.js b/core/modules/system/system.modules.js
index 0df6629..eeba481 100644
--- a/core/modules/system/system.modules.js
+++ b/core/modules/system/system.modules.js
@@ -64,4 +64,60 @@ Drupal.behaviors.hideModuleInformation = {
}
};
+/**
+ * Filters the module list table by a text input search string.
+ *
+ * Additionally accounts for multiple tables being wrapped in "package" details
+ * elements.
+ *
+ * Text search input: input.table-filter-text
+ * Target table: input.table-filter-text[data-table]
+ * Source text: .table-filter-text-source
+ */
+Drupal.behaviors.tableFilterByText = {
+ attach: function (context, settings) {
+ var $input = $('input.table-filter-text').once('table-filter-text');
+ var $table = $($input.attr('data-table'));
+ var $rows, $rowsAndDetails, $details;
+
+ function hidePackageDetails(index, element) {
+ var $details = $(element);
+ var $visibleRows = $details.find('table:not(.sticky-header)').find('tbody tr:visible');
+ $details.toggle($visibleRows.length > 0);
+ }
+
+ function filterModuleList (e) {
+ var query = $(e.target).val().toLowerCase();
+
+ function showModuleRow (index, row) {
+ var $row = $(row);
+ var $sources = $row.find('.table-filter-text-source');
+ var textMatch = $sources.text().toLowerCase().indexOf(query) !== -1;
+ $row.toggle(textMatch);
+ }
+
+ // Filter if the length of the query is at least 2 characters.
+ if (query.length >= 2) {
+ $rows.each(showModuleRow);
+
+ // Hide the package if they don't have any visible rows.
+ // Note that we first show() all to be able to use ':visible'.
+ $details.show().each(hidePackageDetails);
+ }
+ else {
+ $rowsAndDetails.show();
+ }
+ }
+
+ if ($table.length) {
+ $rowsAndDetails = $table.find('tr, details');
+ $rows = $table.find('tbody tr');
+ $details = $table.find('details');
+
+ // @todo Use autofocus attribute when possible.
+ $input.focus().on('keyup', filterModuleList);
+ }
+ }
+};
+
}(jQuery, Drupal));