summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2007-11-14 09:50:00 +0000
committerDries Buytaert <dries@buytaert.net>2007-11-14 09:50:00 +0000
commit6049f23760cc3653e46ee4bf3f7843590d9954f8 (patch)
treeed41382080f5f28965e5c73bc9eb4a9ccb565f37 /modules
parent44373cf0b16a181b5dd380b1f6e6aae1e2d118d5 (diff)
downloadbrdo-6049f23760cc3653e46ee4bf3f7843590d9954f8.tar.gz
brdo-6049f23760cc3653e46ee4bf3f7843590d9954f8.tar.bz2
- Patch #181066 by quicksketch et al: drag and drop of table rows on the block adminsitration page.
Diffstat (limited to 'modules')
-rw-r--r--modules/block/block-admin-display-form.tpl.php39
-rw-r--r--modules/block/block-rtl.css15
-rw-r--r--modules/block/block.admin.inc166
-rw-r--r--modules/block/block.css17
-rw-r--r--modules/block/block.js95
-rw-r--r--modules/block/block.module7
-rw-r--r--modules/system/system.css48
7 files changed, 215 insertions, 172 deletions
diff --git a/modules/block/block-admin-display-form.tpl.php b/modules/block/block-admin-display-form.tpl.php
index f7bf2e030..2a20ff4e0 100644
--- a/modules/block/block-admin-display-form.tpl.php
+++ b/modules/block/block-admin-display-form.tpl.php
@@ -6,13 +6,14 @@
* Default theme implementation to configure blocks.
*
* Available variables:
- * - $block_listing: An array of block controls within regions.
+ * - $block_regions: An array of regions. Keyed by name with the title as value.
+ * - $block_listing: An array of blocks keyed by region and then delta.
* - $form_submit: Form submit button.
* - $throttle: TRUE or FALSE depending on throttle module being enabled.
*
- * Each $data in $block_listing contains:
- * - $data->is_region_first: TRUE or FALSE depending on the listed blocks
- * positioning. Used here to insert a region header.
+ * Each $block_listing[$region] contains an array of blocks for that region.
+ *
+ * Each $data in $block_listing[$region] contains:
* - $data->region_title: Region title for the listed block.
* - $data->block_title: Block title.
* - $data->region_select: Drop-down menu for assigning a region.
@@ -25,9 +26,15 @@
* @see theme_block_admin_display()
*/
?>
-<?php drupal_add_js('misc/tableheader.js'); ?>
-<?php print $messages; ?>
-
+<?php
+ // Add table javascript.
+ drupal_add_js('misc/tableheader.js');
+ drupal_add_js(drupal_get_path('module', 'block') .'/block.js');
+ foreach ($block_regions as $region => $title) {
+ drupal_add_tabledrag('blocks', 'match', 'sibling', 'block-region-select', 'block-region-'. $region, NULL, FALSE);
+ drupal_add_tabledrag('blocks', 'order', 'sibling', 'block-weight', 'block-weight-'. $region);
+ }
+?>
<table id="blocks">
<thead>
<tr>
@@ -42,15 +49,16 @@
</thead>
<tbody>
<?php $row = 0; ?>
- <?php foreach ($block_listing as $data): ?>
- <?php if ($data->is_region_first): ?>
- <tr class="<?php print $row % 2 == 0 ? 'odd' : 'even'; ?>">
- <td colspan="<?php print $throttle ? '7' : '6'; ?>" class="region"><?php print $data->region_title; ?></td>
+ <?php foreach ($block_regions as $region => $title): ?>
+ <tr class="region region-<?php print $region?>">
+ <td colspan="<?php print $throttle ? '6' : '5'; ?>" class="region"><?php print $title; ?></td>
</tr>
- <?php $row++; ?>
- <?php endif; ?>
- <tr class="<?php print $row % 2 == 0 ? 'odd' : 'even'; ?><?php print $data->row_class ? ' '. $data->row_class : ''; ?>">
- <td class="block"><?php print $data->block_title; ?><?php print $data->block_modified ? '<span class="warning">*</span>' : ''; ?></td>
+ <tr class="region-message region-<?php print $region?>-message <?php print empty($block_listing[$region]) ? 'region-empty' : 'region-populated'; ?>">
+ <td colspan="<?php print $throttle ? '6' : '5'; ?>"><em><?php print t('No blocks in this region'); ?></em></td>
+ </tr>
+ <?php foreach ($block_listing[$region] as $delta => $data): ?>
+ <tr class="draggable <?php print $row % 2 == 0 ? 'odd' : 'even'; ?><?php print $data->row_class ? ' '. $data->row_class : ''; ?>">
+ <td class="block"><?php print $data->block_title; ?></td>
<td><?php print $data->region_select; ?></td>
<td><?php print $data->weight_select; ?></td>
<?php if ($throttle): ?>
@@ -60,6 +68,7 @@
<td><?php print $data->delete_link; ?></td>
</tr>
<?php $row++; ?>
+ <?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
diff --git a/modules/block/block-rtl.css b/modules/block/block-rtl.css
deleted file mode 100644
index b43e9cd29..000000000
--- a/modules/block/block-rtl.css
+++ /dev/null
@@ -1,15 +0,0 @@
-/* $Id$ */
-
-#blocks td.block {
- padding-left: inherit;
- padding-right: 1.5em;
-}
-#blocks select {
- margin-left: 24px;
-}
-#blocks select.progress-disabled {
- margin-left: 0px;
-}
-#blocks .progress .bar {
- float: right;
-}
diff --git a/modules/block/block.admin.inc b/modules/block/block.admin.inc
index be886fd44..a90264075 100644
--- a/modules/block/block.admin.inc
+++ b/modules/block/block.admin.inc
@@ -36,16 +36,14 @@ function block_admin_display_form(&$form_state, $blocks, $theme = NULL) {
init_theme();
$throttle = module_exists('throttle');
- $block_regions = array(BLOCK_REGION_NONE => '<'. t('none') .'>') + system_region_list($theme_key);
+ $block_regions = system_region_list($theme_key) + array(BLOCK_REGION_NONE => '<'. t('none') .'>');
// Build form tree
$form = array(
'#action' => arg(3) ? url('admin/build/block/list/'. $theme_key) : url('admin/build/block'),
'#tree' => TRUE,
- '#cache' => TRUE,
- '#prefix' => '<div id="block-admin-display-form-wrapper">',
- '#suffix' => '</div>',
);
+
foreach ($blocks as $i => $block) {
$key = $block['module'] .'_'. $block['delta'];
$form[$key]['module'] = array(
@@ -69,7 +67,7 @@ function block_admin_display_form(&$form_state, $blocks, $theme = NULL) {
);
$form[$key]['region'] = array(
'#type' => 'select',
- '#default_value' => $block['status'] ? (isset($block['region']) ? $block['region'] : system_default_region($theme_key)) : BLOCK_REGION_NONE,
+ '#default_value' => $block['region'],
'#options' => $block_regions,
);
@@ -82,20 +80,9 @@ function block_admin_display_form(&$form_state, $blocks, $theme = NULL) {
}
}
- // Attach the AHAH events to the submit button. Set the AHAH selector to every
- // select element in the form. The AHAH event could be attached to every select
- // element individually, but using the selector is more efficient, especially
- // on a page where hundreds of AHAH enabled elements may be present.
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save blocks'),
- '#ahah' => array(
- 'path' => 'admin/build/block/list/js/'. $theme_key,
- 'selector' => '#block-admin-display-form-wrapper select',
- 'wrapper' => 'block-admin-display-form-wrapper',
- 'event' => 'change',
- 'effect' => 'fade',
- ),
);
return $form;
@@ -115,104 +102,28 @@ function block_admin_display_form_submit($form, &$form_state) {
}
/**
- * Javascript callback for AHAH replacement. Re-generate the form with the
- * updated values and return necessary html.
- */
-function block_admin_display_js($theme = NULL) {
- // Load the cached form.
- $form_cache = cache_get('form_'. $_POST['form_build_id'], 'cache_form');
-
- // Set the new weights and regions for each block.
- $blocks = array();
- foreach (element_children($form_cache->data) as $key) {
- $field = $form_cache->data[$key];
- if (isset($field['info'])) {
- $block = array(
- 'module' => $field['module']['#value'],
- 'delta' => $field['delta']['#value'],
- 'info' => html_entity_decode($field['info']['#value'], ENT_QUOTES),
- 'region' => $_POST[$key]['region'],
- 'weight' => $_POST[$key]['weight'],
- 'status' => $_POST[$key]['region'] == BLOCK_REGION_NONE ? 0 : 1,
- );
-
- $throttle = module_exists('throttle');
- if ($throttle) {
- $block['throttle'] = !empty($_POST[$key]['throttle']);
- }
-
- if ($block['weight'] != $form_cache->data[$key]['weight']['#default_value'] || $block['region'] != $form_cache->data[$key]['region']['#default_value']) {
- $changed_block = $block['module'] .'_'. $block['delta'];
- }
-
- $blocks[] = $block;
- }
- }
-
- // Resort the blocks with the new weights.
- usort($blocks, '_block_compare');
-
- // Create a form in the new order.
- $form_state = array('submitted' => FALSE);
- $form = block_admin_display_form($form_state, $blocks, $theme);
-
- // Maintain classes set on individual blocks.
- foreach (element_children($form_cache->data) as $key) {
- if (isset($form_cache->data[$key]['#attributes'])) {
- $form[$key]['#attributes'] = $form_cache->data[$key]['#attributes'];
- }
- }
-
- // Preserve the order of the new form while merging the previous data.
- $form_order = array_flip(array_keys($form)); // Save the form order.
- $form = array_merge($form_cache->data, $form); // Merge the data.
- $form = array_merge($form_order, $form); // Put back into the correct order.
-
- // Add a permanent class to the changed block.
- $form[$changed_block]['#attributes']['class'] = 'block-modified';
-
- cache_set('form_'. $_POST['form_build_id'], $form, 'cache_form', $form_cache->expire);
-
- // Add a temporary class to mark the new AHAH content.
- $form[$changed_block]['#attributes']['class'] = empty($form[$changed_block]['#attributes']['class']) ? 'ahah-new-content' : $form[$changed_block]['#attributes']['class'] .' ahah-new-content';
- $form['js_modified'] = array(
- '#type' => 'value',
- '#value' => TRUE,
- );
-
- $form['#post'] = $_POST;
- $form['#theme'] = 'block_admin_display_form';
-
- // Add messages to our output.
- drupal_set_message(t('Your settings will not be saved until you click the <em>Save blocks</em> button.'), 'warning');
-
- // Render the form.
- drupal_alter('form', $form, array(), 'block_admin_display_form');
- $form = form_builder('block_admin_display_form', $form, $form_state);
-
- // Remove the wrapper from the form to prevent duplicate div IDs.
- unset($form['#prefix'], $form['#suffix']);
-
- $output = drupal_render($form);
-
- // Return the output in JSON format.
- drupal_json(array('status' => TRUE, 'data' => $output));
-}
-
-/**
* Helper function for sorting blocks on admin/build/block.
*
* Active blocks are sorted by region, then by weight.
* Disabled blocks are sorted by name.
*/
function _block_compare($a, $b) {
- $status = $b['status'] - $a['status'];
+ global $theme_key;
+ static $regions;
+
+ // We need the region list to correctly order by region.
+ if (!isset($regions)) {
+ $regions = array_flip(array_keys(system_region_list($theme_key)));
+ $regions[BLOCK_REGION_NONE] = count($regions);
+ }
+
// Separate enabled from disabled.
+ $status = $b['status'] - $a['status'];
if ($status) {
return $status;
}
- // Sort by region.
- $place = strcmp($a['region'], $b['region']);
+ // Sort by region (in the order defined by theme .info file).
+ $place = $regions[$a['region']] - $regions[$b['region']];
if ($place) {
return $place;
}
@@ -442,14 +353,20 @@ function block_box_delete_submit($form, &$form_state) {
function template_preprocess_block_admin_display_form(&$variables) {
global $theme_key;
- $variables['throttle'] = module_exists('throttle');
$block_regions = system_region_list($theme_key);
+ $variables['throttle'] = module_exists('throttle');
+ $variables['block_regions'] = $block_regions + array(BLOCK_REGION_NONE => t('Disabled'));
- // Highlight regions on page to provide visual reference.
foreach ($block_regions as $key => $value) {
+ // Highlight regions on page to provide visual reference.
drupal_set_content($key, '<div class="block-region">'. $value .'</div>');
+ // Initialize an empty array for the region.
+ $variables['block_listing'][$key] = array();
}
+ // Initialize disabled blocks array.
+ $variables['block_listing'][BLOCK_REGION_NONE] = array();
+
// Setup to track previous region in loop.
$last_region = '';
foreach (element_children($variables['form']) as $i) {
@@ -460,34 +377,23 @@ function template_preprocess_block_admin_display_form(&$variables) {
// Fetch region for current block.
$region = $block['region']['#default_value'];
- // Track first block listing to insert region header inside block_admin_display.tpl.php.
- $is_region_first = FALSE;
- if ($last_region != $region) {
- $is_region_first = TRUE;
- // Set region title. Block regions already translated.
- if ($region != BLOCK_REGION_NONE) {
- $region_title = drupal_ucfirst($block_regions[$region]);
- }
- else {
- $region_title = t('Disabled');
- }
- }
-
- $variables['block_listing'][$i]->is_region_first = $is_region_first;
- $variables['block_listing'][$i]->row_class = isset($block['#attributes']['class']) ? $block['#attributes']['class'] : '';
- $variables['block_listing'][$i]->block_modified = isset($block['#attributes']['class']) && strpos($block['#attributes']['class'], 'block-modified') !== FALSE ? TRUE : FALSE;
- $variables['block_listing'][$i]->region_title = $region_title;
- $variables['block_listing'][$i]->block_title = drupal_render($block['info']);
- $variables['block_listing'][$i]->region_select = drupal_render($block['region']) . drupal_render($block['theme']);
- $variables['block_listing'][$i]->weight_select = drupal_render($block['weight']);
- $variables['block_listing'][$i]->throttle_check = $variables['throttle'] ? drupal_render($block['throttle']) : '';
- $variables['block_listing'][$i]->configure_link = drupal_render($block['configure']);
- $variables['block_listing'][$i]->delete_link = !empty($block['delete']) ? drupal_render($block['delete']) : '';
+ // Set special classes needed for table drag and drop.
+ $variables['form'][$i]['region']['#attributes']['class'] = 'block-region-select block-region-'. $region;
+ $variables['form'][$i]['weight']['#attributes']['class'] = 'block-weight block-weight-'. $region;
+
+ $variables['block_listing'][$region][$i]->row_class = isset($block['#attributes']['class']) ? $block['#attributes']['class'] : '';
+ $variables['block_listing'][$region][$i]->block_modified = isset($block['#attributes']['class']) && strpos($block['#attributes']['class'], 'block-modified') !== FALSE ? TRUE : FALSE;
+ $variables['block_listing'][$region][$i]->block_title = drupal_render($block['info']);
+ $variables['block_listing'][$region][$i]->region_select = drupal_render($block['region']) . drupal_render($block['theme']);
+ $variables['block_listing'][$region][$i]->weight_select = drupal_render($block['weight']);
+ $variables['block_listing'][$region][$i]->throttle_check = $variables['throttle'] ? drupal_render($block['throttle']) : '';
+ $variables['block_listing'][$region][$i]->configure_link = drupal_render($block['configure']);
+ $variables['block_listing'][$region][$i]->delete_link = !empty($block['delete']) ? drupal_render($block['delete']) : '';
+ $variables['block_listing'][$region][$i]->printed = FALSE;
$last_region = $region;
}
}
- $variables['messages'] = isset($variables['form']['js_modified']) ? theme('status_messages') : '';
$variables['form_submit'] = drupal_render($variables['form']);
}
diff --git a/modules/block/block.css b/modules/block/block.css
index 87eac484f..3d579ee6c 100644
--- a/modules/block/block.css
+++ b/modules/block/block.css
@@ -3,8 +3,12 @@
#blocks td.region {
font-weight: bold;
}
-#blocks td.block {
- padding-left: 1.5em; /* LTR */
+#blocks tr.region-message {
+ font-weight: normal;
+ color: #999;
+}
+#blocks tr.region-populated {
+ display: none;
}
.block-region {
background-color: #ff6;
@@ -12,12 +16,3 @@
margin-bottom: 4px;
padding: 3px;
}
-#blocks select {
- margin-right: 24px; /* LTR */
-}
-#blocks select.progress-disabled {
- margin-right: 0px; /* LTR */
-}
-#blocks tr.ahah-new-content {
- background-color: #ffd;
-}
diff --git a/modules/block/block.js b/modules/block/block.js
new file mode 100644
index 000000000..6a2a31d02
--- /dev/null
+++ b/modules/block/block.js
@@ -0,0 +1,95 @@
+// $Id $
+
+/**
+ * Move a block in the blocks table from one region to another via select list.
+ *
+ * This behavior is dependent on the tableDrag behavior, since it uses the
+ * objects initialized in that behavior to update the row.
+ */
+Drupal.behaviors.blockDrag = function(context) {
+ var table = $('table#blocks');
+ var tableDrag = Drupal.tableDrag.blocks; // Get the blocks tableDrag object.
+
+ // Add a handler for when a row is swapped, update empty regions.
+ tableDrag.row.prototype.onSwap = function(swappedRow) {
+ checkEmptyRegions(table, this);
+ };
+
+ // A custom message for the blocks page specifically.
+ Drupal.theme.tableDragChangedWarning = function () {
+ return '<div class="warning">' + Drupal.theme('tableDragChangedMarker') + ' ' + Drupal.t("The changes to these blocks will not be saved until the <em>Save blocks</em> button is clicked.") + '</div>';
+ };
+
+ // Add a handler so when a row is dropped, update fields dropped into new regions.
+ tableDrag.onDrop = function() {
+ dragObject = this;
+ if ($(dragObject.rowObject.element).prev('tr').is('.region-message')) {
+ var regionRow = $(dragObject.rowObject.element).prev('tr').get(0);
+ var regionName = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+ var regionField = $('select.block-region-select', dragObject.rowObject.element);
+ var weightField = $('select.block-weight', dragObject.rowObject.element);
+ var oldRegionName = weightField[0].className.replace(/([^ ]+[ ]+)*block-weight-([^ ]+)([ ]+[^ ]+)*/, '$2');
+
+ if (!regionField.is('.block-region-'+ regionName)) {
+ regionField.removeClass('block-region-' + oldRegionName).addClass('block-region-' + regionName);
+ weightField.removeClass('block-weight-' + oldRegionName).addClass('block-weight-' + regionName);
+ regionField.val(regionName);
+ }
+ }
+ };
+
+ // Add the behavior to each region select list.
+ $('select.block-region-select:not(.blockregionselect-processed)', context).each(function() {
+ $(this).change(function(event) {
+ // Make our new row and select field.
+ var row = $(this).parents('tr:first');
+ var select = $(this);
+ tableDrag.rowObject = new tableDrag.row(row);
+
+ // Find the correct region and insert the row as the first in the region.
+ $('tr.region-message', table).each(function() {
+ if ($(this).is('.region-' + select[0].value + '-message')) {
+ // Add the new row and remove the old one.
+ $(this).after(row);
+ // Manually update weights and restripe.
+ tableDrag.updateFields(row.get(0));
+ tableDrag.rowObject.changed = true;
+ if (tableDrag.oldRowElement) {
+ $(tableDrag.oldRowElement).removeClass('drag-previous');
+ }
+ tableDrag.oldRowElement = row.get(0);
+ tableDrag.restripeTable();
+ tableDrag.rowObject.markChanged();
+ tableDrag.oldRowElement = row;
+ $(row).addClass('drag-previous');
+ }
+ });
+
+ // Modify empty regions with added or removed fields.
+ checkEmptyRegions(table, row);
+ // Remove focus from selectbox.
+ select.get(0).blur();
+ });
+ $(this).addClass('blockregionselect-processed');
+ });
+
+ var checkEmptyRegions = function(table, rowObject) {
+ $('tr.region-message', table).each(function() {
+ // If the dragged row is in this region, but above the message row, swap it down one space.
+ if ($(this).prev('tr').get(0) == rowObject.element) {
+ // Prevent a recursion problem when using the keyboard to move rows up.
+ if ((rowObject.method != 'keyboard' || rowObject.direction == 'down')) {
+ rowObject.swap('after', this);
+ }
+ }
+ // This region has become empty
+ if ($(this).next('tr').is(':not(.draggable)') || $(this).next('tr').size() == 0) {
+ $(this).removeClass('region-populated').addClass('region-empty');
+ }
+ // This region has become populated.
+ else if ($(this).is('.region-empty')) {
+ $(this).removeClass('region-empty').addClass('region-populated');
+ }
+ });
+ };
+};
diff --git a/modules/block/block.module b/modules/block/block.module
index 53d6974c6..aa44be98c 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -248,6 +248,9 @@ function _block_rehash() {
}
// Add defaults and save it into the database.
drupal_write_record('blocks', $block);
+ // Set region to none if not enabled.
+ $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE;
+ // Add to the list of blocks we return.
$blocks[] = $block;
}
else {
@@ -257,7 +260,9 @@ function _block_rehash() {
// do not need to update the database here.
// Add 'info' to this block.
$old_blocks[$module][$delta]['info'] = $block['info'];
- // Add this block to the list of blocks we return
+ // Set region to none if not enabled.
+ $old_blocks[$module][$delta]['region'] = $old_blocks[$module][$delta]['status'] ? $old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE;
+ // Add this block to the list of blocks we return.
$blocks[] = $old_blocks[$module][$delta];
// Remove this block from the list of blocks to be deleted.
unset($old_blocks[$module][$delta]);
diff --git a/modules/system/system.css b/modules/system/system.css
index 795ed99cc..172fc29a8 100644
--- a/modules/system/system.css
+++ b/modules/system/system.css
@@ -3,6 +3,9 @@
/*
** HTML elements
*/
+body.drag {
+ cursor: move;
+}
th.active img {
display: inline;
}
@@ -11,6 +14,12 @@ tr.even, tr.odd {
border-bottom: 1px solid #ccc;
padding: 0.1em 0.6em;
}
+tr.drag {
+ background-color: #fffff0;
+}
+tr.drag-previous {
+ background-color: #ffd;
+}
td.active {
background-color: #ddd;
}
@@ -32,6 +41,21 @@ thead th {
.breadcrumb {
padding-bottom: .5em
}
+div.indentation {
+ width: 20px;
+ margin: -0.4em 0.2em -0.4em -0.4em;
+ padding: 0.4em 0 0.4em 0.6em;
+ float: left;
+}
+div.tree-child {
+ background: url(../../misc/tree.png) no-repeat 11px center;
+}
+div.tree-child-last {
+ background: url(../../misc/tree-bottom.png) no-repeat 11px center;
+}
+div.tree-child-horizontal {
+ background: url(../../misc/tree.png) no-repeat -11px center;
+}
.error {
color: #e55;
}
@@ -334,6 +358,30 @@ html.js .resizable-textarea textarea {
}
/*
+** Table drag and drop.
+*/
+a.tabledrag-handle {
+ cursor: move;
+ float: left;
+ height: 1.7em;
+ margin: -0.42em 0 -0.42em -0.5em;
+ padding: 0.42em 1.5em 0.42em 0.5em;
+ text-decoration: none;
+}
+a.tabledrag-handle:hover {
+ text-decoration: none;
+}
+a.tabledrag-handle .handle {
+ margin-top: 4px;
+ height: 13px;
+ width: 13px;
+ background: url(../../misc/draggable.png) no-repeat 0 0;
+}
+a.tabledrag-handle-hover .handle {
+ background-position: 0 -20px;
+}
+
+/*
** Teaser splitter
*/
.joined + .grippie {