diff -rupN content.module content.module --- content.module 2008-11-10 16:56:35.000000000 +0100 +++ content.module 2008-11-30 18:04:43.000000000 +0100 @@ -485,6 +485,9 @@ function theme_content_multiple_values($ ), t('Order'), ); + if ($field['multiple'] == 1) { + $header[] = t('Delete'); + } $rows = array(); // Sort items according to '_weight' (needed when the form comes back after @@ -492,20 +495,26 @@ function theme_content_multiple_values($ $items = array(); foreach (element_children($element) as $key) { if ($key !== $element['#field_name'] .'_add_more') { - $items[] = &$element[$key]; + $items[$element[$key]['#delta']] = &$element[$key]; } } - usort($items, '_content_sort_items_value_helper'); + uasort($items, '_content_sort_items_value_helper'); // Add the items as table rows. - foreach ($items as $key => $item) { + foreach ($items as $delta => $item) { $item['_weight']['#attributes']['class'] = $order_class; $delta_element = drupal_render($item['_weight']); + if ($field['multiple'] == 1) { + $delete_element = drupal_render($item['_delete']); + } $cells = array( array('data' => '', 'class' => 'content-multiple-drag'), drupal_render($item), array('data' => $delta_element, 'class' => 'delta-order'), ); + if ($field['multiple'] == 1) { + $cells[] = array('data' => $delete_element); + } $rows[] = array( 'data' => $cells, 'class' => 'draggable', @@ -709,9 +718,21 @@ function content_field($op, &$node, $fie $items = _content_sort_items($field, $items); } + // Remove items marked for deletion. + foreach ($items as $delta => $item) { + if (isset($item['_delete']) && $item['_delete']) { + unset($items[$delta]); + } + } + // Filter out empty values. $items = content_set_empty($field, $items); + // Rebuild deltas for fields with multiple values. + if ($field['multiple'] >= 1) { + $items = array_values($items); + } + break; case 'view': @@ -724,6 +745,13 @@ function content_field($op, &$node, $fie $items = _content_sort_items($field, $items); } + // Remove items marked for deletion. + foreach ($items as $delta => $item) { + if (isset($item['_delete']) && $item['_delete']) { + unset($items[$delta]); + } + } + // Filter out empty values. $items = content_set_empty($field, $items); } @@ -762,10 +790,10 @@ function content_field($op, &$node, $fie ); // Fill-in items. - foreach ($items as $delta => $item) { + foreach (array_keys($items) as $weight => $delta) { $element['items'][$delta] = array( - '#item' => $item, - '#weight' => $delta, + '#item' => $items[$delta], + '#weight' => $weight, ); } @@ -885,22 +913,37 @@ function content_field($op, &$node, $fie * returns filtered and adjusted item array */ function content_set_empty($field, $items) { - // Filter out empty values. + // Prepare an empty item. + $empty = array(); + foreach (array_keys($field['columns']) as $column) { + $empty[$column] = NULL; + } + + // Keep track of empty values. $filtered = array(); $function = $field['module'] .'_content_is_empty'; foreach ((array) $items as $delta => $item) { - if (!$function($item, $field)) { - $filtered[] = $item; - } + $filtered[$delta] = $function($item, $field) ? $empty : $item; } // Make sure we store the right number of 'empty' values. - $empty = array(); - foreach (array_keys($field['columns']) as $column) { - $empty[$column] = NULL; + if ($field['multiple'] == 1) { + // Remove last element if empty for multi-valued fields. + $last_item = end($filtered); + if ($function($last_item, $field)) { + unset($filtered[key($filtered)]); + } + } + else { + $pad = $field['multiple'] > 1 ? (int)$field['multiple'] : 1; + $count = count($filtered); + if ($count < $pad) { + $delta = max(array_keys($filtered)) + 1; + for ($i = $count; $i < $pad; $i++) { + $filtered[$delta++] = $empty; + } + } } - $pad = $field['multiple'] > 1 ? $field['multiple'] : 1; - $filtered = array_pad($filtered, $pad, $empty); return $filtered; } @@ -911,7 +954,7 @@ function content_set_empty($field, $item */ function _content_sort_items($field, $items) { if ($field['multiple'] >= 1 && isset($items[0]['_weight'])) { - usort($items, '_content_sort_items_helper'); + uasort($items, '_content_sort_items_helper'); foreach ($items as $delta => $item) { if (is_array($items[$delta])) { unset($items[$delta]['_weight']); @@ -994,7 +1037,14 @@ function content_storage($op, $node) { if (!isset($additions[$field_name])) { $additions[$field_name] = array(); } - $additions[$field_name][] = $item; + + // Preserve deltas when loading items from database. + if (isset($row['delta'])) { + $additions[$field_name][$row['delta']] = $item; + } + else { + $additions[$field_name][] = $item; + } } } } @@ -2381,8 +2431,7 @@ function content_extra_field_weight($typ * Do we want to eliminate them from the results? */ function content_max_delta($field_name, $type_name = NULL) { - $fields = content_fields(); - $field = $fields[$field_name]; + $field = content_fields($field_name); // Non-multiple value fields don't use the delta column, // but could exist in multiple databases. If any value @@ -2393,8 +2442,7 @@ function content_max_delta($field_name, if (empty($type_name) || $content_type['type'] == $type_name) { foreach ($content_type['fields'] as $field) { $db_info = content_database_info($field); - $table = $db_info['table']; - if (db_result(db_query("SELECT COUNT(*) FROM {$table}")) >= 1) { + if (db_result(db_query('SELECT COUNT(*) FROM {'. $db_info['table'] .'}')) >= 1) { return 0; } } @@ -2406,14 +2454,13 @@ function content_max_delta($field_name, // in the node table to limit the type. else { $db_info = content_database_info($field); - $table = $db_info['table']; if (!empty($type_name)) { - $delta = db_result(db_query("SELECT MAX(delta) FROM {$table} f LEFT JOIN {node} n ON f.vid = n.vid WHERE n.type = '%s'", $type_name)); + $delta = db_result(db_query('SELECT MAX(delta) FROM {'. $db_info['table'] ."} f LEFT JOIN {node} n ON f.vid = n.vid WHERE n.type = '%s'", $type_name)); } else { - $delta = db_result(db_query("SELECT MAX(delta) FROM {$table}")); + $delta = db_result(db_query('SELECT MAX(delta) FROM {'. $db_info['table'] .'}')); } - if ($delta >= 0) { + if ($delta !== FALSE && $delta >= 0) { return $delta; } } diff -rupN includes/content.node_form.inc includes/content.node_form.inc --- includes/content.node_form.inc 2008-10-04 15:14:21.000000000 +0200 +++ includes/content.node_form.inc 2008-11-28 17:16:32.000000000 +0100 @@ -157,21 +157,24 @@ function content_multiple_value_form(&$f switch ($field['multiple']) { case 0: + $deltas = array(0); $max = 0; break; + case 1: - $filled_items = content_set_empty($field, $items); - $current_item_count = isset($form_state['item_count'][$field_name]) - ? $form_state['item_count'][$field_name] - : count($items); + $deltas = array_keys(content_set_empty($field, $items)); // We always want at least one empty icon for the user to fill in. - $max = ($current_item_count > count($filled_items)) - ? $current_item_count - 1 - : $current_item_count; - + $current_item_count = (isset($form_state['item_count'][$field_name]) ? $form_state['item_count'][$field_name] : count($deltas) + 1); + $max = (!empty($deltas) ? max($deltas) : 0); + while (count($deltas) < $current_item_count) { + $max++; + $deltas[] = $max; + } break; + default: $max = $field['multiple'] - 1; + $deltas = array_keys(array_fill(0, $field['multiple'], 0)); break; } @@ -186,7 +189,7 @@ function content_multiple_value_form(&$f ); $function = $field['widget']['module'] .'_widget'; - for ($delta = 0; $delta <= $max; $delta++) { + foreach ($deltas as $delta) { if ($element = $function($form, $form_state, $field, $items, $delta)) { $defaults = array( '#title' => ($field['multiple'] >= 1) ? '' : $title, @@ -212,6 +215,17 @@ function content_multiple_value_form(&$f ); } + // Add a checkbox to delete items for unlimited multiple value fields. + if ($field['multiple'] == 1) { + // We name the element '_delete' to avoid clashing with column names + // defined by field modules. + $element['_delete'] = array( + '#type' => 'checkbox', + '#default_value' => isset($items[$delta]['_delete']) ? $items[$delta]['_delete'] : 0, + '#weight' => 100, + ); + } + $form_element[$delta] = array_merge($element, $defaults); } }