Index: misc/upload.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/upload.js,v
retrieving revision 1.12
diff -u -r1.12 upload.js
--- misc/upload.js	1 Jun 2007 09:05:45 -0000	1.12
+++ misc/upload.js	7 Jun 2007 11:59:33 -0000
@@ -13,6 +13,11 @@
     var hide = base + '-hide';
     var upload = new Drupal.jsUpload(uri, button, wrapper, hide);
   });
+
+  $('.file-delete-button-wrapper').each(function () {
+    fileDeleteData = Drupal.getFileDeleteData(this.id);
+    Drupal.initFileDelete(fileDeleteData);
+  });
 };
 
 /**
@@ -55,6 +60,12 @@
  * Handler for the form redirection completion.
  */
 Drupal.jsUpload.prototype.oncomplete = function (data) {
+  // Store status of the Delete checkboxes, so that they can be restored later
+  var fileDeleteData = new Array();
+  $('.file-delete-button-wrapper').each(function () {
+    fileDeleteData[this.id] = Drupal.getFileDeleteData(this.id);
+  });
+
   // Remove old form
   Drupal.freezeHeight(); // Avoid unnecessary scrolling
   $(this.wrapper).html('');
@@ -65,11 +76,10 @@
 
   // If uploading the first attachment fade in everything
   if ($('tr', div).size() == 2) {
-    // Replace form and re-attach behaviour
+    // Replace form and fade in items
     $(div).hide();
     $(this.wrapper).append(div);
     $(div).fadeIn('slow');
-    Drupal.uploadAutoAttach();
   }
   // Else fade in only the last table row
   else {
@@ -85,11 +95,15 @@
       }
     });
 
-    // Replace form, fade in items and re-attach behaviour
+    // Replace form and fade in items
     $(this.wrapper).append(div);
     $('table tr:last-of-type td', div).fadeIn('slow');
     $(this.hide, div).fadeIn('slow');
-    Drupal.uploadAutoAttach();
+  }
+  // Re-attach behaviour and update previous marked-for-deletion status
+  Drupal.uploadAutoAttach();
+  for (key in fileDeleteData) {
+    Drupal.updateFileDelete(fileDeleteData[key], 'show');
   }
   Drupal.unfreezeHeight();
 };
@@ -109,6 +123,72 @@
   });
 };
 
+/**
+ * Retrieve some ids and classes that will be modified when Delete is pressed.
+ * The id of each wrapper div is used as base name (e.g. files-0-remove),
+ * other elements will have to adjust their id or class accordingly.
+ */
+Drupal.getFileDeleteData = function(wrapper) {
+  var fileDeleteData = new Array();
+  fileDeleteData['wrapper'] = wrapper;
+  // Transform stuff like update_0 to update-0, like Form API does
+  fileDeleteData['checkbox'] = 'edit-' + wrapper.replace(/_/g, '-');
+  fileDeleteData['button'] = wrapper + '-button';
+  fileDeleteData['classHide'] = '.' + wrapper + '-hide';
+  fileDeleteData['classShow'] = '.' + wrapper + '-show';
+  fileDeleteData['aboutToDelete'] = $('#' + fileDeleteData['checkbox']).attr('checked');
+  fileDeleteData['textDelete'] = Drupal.settings.fileDeleteButton[0];
+  fileDeleteData['textCancel'] = Drupal.settings.fileDeleteButton[1];
+  return fileDeleteData;
+};
+
+/**
+ * Initialize the JS file delete buttons and behaviour.
+ */
+Drupal.initFileDelete = function(fileDeleteData) {
+  // Hide the usual wrapper contents, and add a delete/cancel button instead.
+  $('#' + fileDeleteData['wrapper'] + '/*').hide();
+  $('#' + fileDeleteData['wrapper']).append(
+    "<input type=\"button\" class=\"file-delete-button\"" +
+    " value=\"" + fileDeleteData['textDelete'] + "\"" +
+    " id=\"" + fileDeleteData['button'] + "\" />"
+  );
+
+  // When the button is clicked, toggle the checkbox and css class visibility
+  $('#' + fileDeleteData['button']).click(function () {
+    fileDeleteData['aboutToDelete'] = ! $('#' + fileDeleteData['checkbox']).attr('checked');
+    Drupal.updateFileDelete(fileDeleteData, 'fade');
+  });
+};
+
+/**
+ * Show the right button text (Delete or Cancel) and css class visibility:
+ * when Delete has been pressed, classHide is hidden and classShow is shown.
+ */
+Drupal.updateFileDelete = function(fileDeleteData, appearanceMethod) {
+  $('#' + fileDeleteData['checkbox']).attr('checked', fileDeleteData['aboutToDelete']);
+
+  if (fileDeleteData['aboutToDelete']) {
+    $('#' + fileDeleteData['button']).val(fileDeleteData['textCancel']);
+    $(fileDeleteData['classHide']).hide();
+    toBeShown = $(fileDeleteData['classShow']);
+  }
+  else {
+    $('#' + fileDeleteData['button']).val(fileDeleteData['textDelete']);
+    $(fileDeleteData['classShow']).hide();
+    toBeShown = $(fileDeleteData['classHide']);
+  }
+
+  // When re-initialization is done after an attachment upload,
+  // we don't want stuff to be faded in - just plain show it.
+  if (appearanceMethod == 'show') {
+    toBeShown.show();
+  }
+  else {
+    toBeShown.fadeIn();
+  }
+};
+
 
 // Global killswitch
 if (Drupal.jsEnabled) {
Index: modules/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.164
diff -u -r1.164 upload.module
--- modules/upload/upload.module	4 Jun 2007 07:22:22 -0000	1.164
+++ modules/upload/upload.module	7 Jun 2007 11:59:34 -0000
@@ -368,6 +368,7 @@
     if ($form['type']['#value'] .'_node_form' == $form_id && variable_get("upload_$node->type", TRUE)) {
       drupal_add_js('misc/progress.js');
       drupal_add_js('misc/upload.js');
+      drupal_add_js(array('fileDeleteButton' => array(t('Delete'), t('Cancel'))), 'setting');
 
       // Attachments fieldset
       $form['attachments'] = array(
@@ -617,7 +618,15 @@
       $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description );
 
       $form['files'][$key]['size'] = array('#value' => format_size($file->filesize));
-      $form['files'][$key]['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove));
+      $form['files'][$key]['remove'] = array(
+        '#type' => 'checkbox',
+        '#default_value' => !empty($file->remove),
+        '#prefix' => '<div id="files-'. $key .'-remove" class="file-delete-button-wrapper">',
+        '#suffix' => '</div>',
+      );
+      $form['files'][$key]['delete-text'] = array(
+        '#value' => '<p>'. t('"%filename" is scheduled for deletion. Mind that it will not be deleted until you save this post.', array('%filename' => $file['filename'])) .'</p>',
+      );
       $form['files'][$key]['list'] = array('#type' => 'checkbox',  '#default_value' => $file->list);
       // If the file was uploaded this page request, set value. this fixes the
       // problem formapi has recognizing new checkboxes. see comments in
@@ -667,14 +676,20 @@
  * Theme the attachments list.
  */
 function theme_upload_form_current(&$form) {
-  $header = array(t('Delete'), t('List'), t('Description'), t('Size'));
+  $header = array(t('Description'), t('Size'), t('List'), t('Delete'));
 
   foreach (element_children($form) as $key) {
+    // Mark the items that will be hidden or shown when a file is deleted.
+    $div_hide = '<div class="files-'. $key .'-remove-hide">';
+    $div_show = '<div class="files-'. $key .'-remove-show" style="display: none;">';
+    $div_end = '</div>';
+    // Construct the row containing file information.
     $row = array();
+    $row[] = $div_hide . drupal_render($form[$key]['description']) . $div_end .
+             $div_show . drupal_render($form[$key]['delete-text']) . $div_end;
+    $row[] = $div_hide . drupal_render($form[$key]['size']) . $div_end;
+    $row[] = $div_hide . drupal_render($form[$key]['list']) . $div_end;
     $row[] = drupal_render($form[$key]['remove']);
-    $row[] = drupal_render($form[$key]['list']);
-    $row[] = drupal_render($form[$key]['description']);
-    $row[] = drupal_render($form[$key]['size']);
     $rows[] = $row;
   }
   $output = theme('table', $header, $rows);
