Drupal form with Drag and drop sort order with weight
Based on good article referenced below, I have added some more form items to be used in my case.
When adding more columns or removing, it is important that the number of header items is the same as the number of columns, if you have less header items the drag and drop will not work.
I have added an extra row to be able to add new items. I added an extra item to the database result (//Add new row) and set the id to "new".
In this case I select the latest occurrence of the status types from the database and have added them in a kind of messy why as a #suffix to the last form item and by CCS made it show up below the the form items.
<?php
/**
* Hook menu
*
* @return unknown
*/
function support_filter_menu() {
$items['admin/settings/support_filter'] = array(
'title' => 'Support Filter settings',
'description' => 'Settings to Support Filter module.',
'page callback' => 'support_filter_admin',
'access arguments' => array('access administration pages'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Build the administration settings panel
*/
function support_filter_admin() {
$output .= '<h2>Support Filter settings</h2>';
$output .= '<p>You are now on server: ' . $_SERVER['HTTP_HOST'];
//Just another form I have with a fieldset with instructions
$output .= drupal_get_form('support_filter_admin_form');
$output .= drupal_get_form('support_filter_status_types_form');
return $output;
}
/**
* Support filter admin form
* This function has a theme function theme_support_filter_status_types_form
*
* @param unknown_type $form_state
* @return unknown
*/
function support_filter_status_types_form($form_state) {
$data = array();
$query = db_query("SELECT * FROM {sabas_statustypes} WHERE 1 ORDER BY weight, id");
while ($row = db_fetch_object($query)) {
$data[] = array(
'id' => $row->id,
'title' => $row->title,
'job_status' => $row->job_status,
'report_error' => $row->report_error,
'code' => $row->code,
'mailaction' => $row->mailaction,
'readable_code' => $row->readable_code,
'weight' => $row->weight,
);
}
//Add new row
$data[] = array(
'id' => 'new',
'title' => '',
'job_status' => '',
'report_error' => '',
'code' => 0,
'mailaction' => 0,
'readable_code' => '',
'weight' => 0,
);
//Get latest occurrens of all filter types
if($latestresult = db_query("SELECT l . * , from_unixtime( timestamp ) AS tiden, sc.name FROM sabas_logs l
LEFT JOIN {support_client} sc USING (clid)
INNER JOIN (SELECT code_id, MAX( timestamp ) AS maxtime FROM sabas_logs
GROUP BY code_id) joiner ON l.code_id = joiner.code_id AND l.timestamp = joiner.maxtime")) {
while ($latestdata = db_fetch_object($latestresult)) {
$latest[$latestdata->code_id] = $latestdata;
}
}
$form = array();
$form['items'] = array();
$form['items']['#tree'] = TRUE;
foreach ($data as $item) {
$r = $item['id'];
if ($latest[$r]->id > 0) {
$latest_string = '<b>'.t('Latest occurred').':</b> account:'.$latest[$r]->account.' time:'.$latest[$r]->tiden.' code:'.$latest[$r]->code.' nid:'.($latest[$r]->nid == 0 ? 0 : l($latest[$r]->nid, 'node/'.$latest[$r]->nid)).' client: ('.$latest[$r]->clid.') '.$latest[$r]->name;
}else{
$latest_string = "";
}
$form['items'][$item['id']] = array(
'idnbr' => array(
'#type' => 'markup',
'#value' => $item['id'],
),
'title' => array(
'#type' => 'textfield',
'#size' => 33,
'#value' => $item['title'],
),
'job_status' => array(
'#type' => 'textfield',
'#size' => 33,
'#value' => $item['job_status'],
),
'report_error' => array(
'#type' => 'textfield',
'#size' => 33,
'#value' => $item['report_error'],
),
'code' => array(
'#type' => 'select',
'#options' => _get_statustype_opt(),
'#value' => $item['code'],
),
'mailaction' => array(
'#type' => 'select',
'#options' => _get_statustype_opt(),
'#options' => array('delete' => 'delete', 'none' => 'none'),
'#value' => $item['mailaction'],
),
'readable_code' => array(
'#type' => 'textfield',
'#value' => $item['readable_code'],
'#size' => 9,
'#maxlength' => 6,
'#attributes' => array('class' => 'support-filter-'.$item['code']),
),
'delete' => array(
'#type' => 'checkbox',
'#title' => t('Delete'),
'#suffix' => '<div class="description description-extra">'.$latest_string.'</div>',
),
'weight' => array(
'#type' => 'weight',
'#delta' => count($data),
'#default_value' => isset($item['weight']) ? $item['weight'] : 0,
),
'id' => array(
'#type' => 'hidden',
'#value' => $item['id'],
),
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save Changes'),
);
return $form;
}
/**
* Hook theme
*
* @return unknown
*/
function support_filter_theme() {
return array(
'support_filter_status_types_form' => array(
'arguments' => array('form' => NULL),
),
);
}
/**
* Theme function adding draggable rows to the form support_filter_status_types_form
*
* @param unknown_type $form
* @return unknown
*/
function theme_support_filter_status_types_form($form) {
drupal_add_tabledrag('draggable-table', 'order', 'sibling', 'weight-group');
$header = array('Id', 'Title', 'Job status', 'Report error', 'Code', 'Mailaction', 'Readable code', 'Delete', 'Weight');
foreach (element_children($form['items']) as $key) {
$element = &$form['items'][$key];
$element['weight']['#attributes']['class'] = 'weight-group';
$row = array();
$row[] = drupal_render($element['idnbr']);
$row[] = drupal_render($element['title']);
$row[] = drupal_render($element['job_status']);
$row[] = drupal_render($element['report_error']);
$row[] = drupal_render($element['code']);
$row[] = drupal_render($element['mailaction']);
$row[] = drupal_render($element['readable_code']);
$row[] = drupal_render($element['delete']);
$row[] = drupal_render($element['weight']) . drupal_render($element['id']);
$rows[] = array('data' => $row, 'class' => 'draggable');
}
$output = theme('table', $header, $rows, array('id' => 'draggable-table'));
$output .= drupal_render($form);
return $output;
}
function support_filter_status_types_form_submit($form, &$form_state) {
//foreach ($form_state['values']['items'] as $item) {
foreach ($form['#post']['items'] as $item) {
if ($item['delete'] == 1) {
db_query('DELETE FROM {sabas_statustypes} WHERE id=%d', $item['id']);
}else{
if (is_numeric($item['id']) AND !empty($item['title'])) {
db_query('UPDATE {sabas_statustypes} SET title="%s", job_status="%s", report_error="%s", code="%s", mailaction="%s", readable_code="%s", weight="%s"
WHERE id=%d', $item['title'], $item['job_status'], $item['report_error'], $item['code'], $item['mailaction'], $item['readable_code'], $item['weight'], $item['id']);
}elseif($item['id'] == "new" AND !empty($item['title'])){
db_query("INSERT INTO {sabas_statustypes} (title, job_status, report_error, code, mailaction, readable_code, weight)
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s')", $item['title'], $item['job_status'], $item['report_error'], $item['code'], $item['mailaction'], $item['readable_code'], $item['weight']);
}
}
}
}
/**
* Return options for status type code
*
* @return unknown
*/
function _get_statustype_opt() {
for($i=0; $i <= 10; $i++) {
$opt[$i] = $i;
}
return $opt;
}
?>
And some style
.admin-settings-support-filter #inside #content {
padding-left: 0px;
}
.admin-settings-support-filter #sidebar-left {
width: 0px;
display: none;
}
#support-filter-status-types-form tbody tr {
height: 60px;
vertical-align: text-top;
padding-top: 2px;
position: relative;
border: none;
}
.description-extra {
position: absolute;
left: 79px;
padding-top: 3px;
}
.content-in {
position: relative;
}
.support-filter-1,
.support-filter-1 a {
background-color: #10C710; /*Green*/
color:#111111;
}
.support-filter-3 {
background-color: #C71010; /*Red*/
color:#FFC710; /*Yellow*/
}
span.support-filter-0,
span.support-filter-1,
span.support-filter-2,
span.support-filter-3,
span.support-filter-4 {
background: transparent;
}
.support-filter-0,
.support-filter-2,
.support-filter-4 {
background-color: #FFC710; /*Yellow*/
color:#C71010; /*Red*/
}
My database table structure
CREATE TABLE IF NOT EXISTS `old_sabas_statustypes` (
`id` int(99) NOT NULL auto_increment,
`title` varchar(250) NOT NULL,
`job_status` varchar(100) NOT NULL,
`report_error` varchar(100) NOT NULL,
`code` varchar(50) NOT NULL,
`mailaction` varchar(250) NOT NULL,
`readable_code` varchar(10) NOT NULL COMMENT 'Readable code',
`weight` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=36 ;
Source: http://www.appnovation.com/simple-walkthrough-creating-drag-reorder-tables