=== modified file 'sites/all/modules/swfupload/js/swfupload_widget.js'
--- js/swfupload_widget.js	2010-10-19 00:39:29 +0000
+++ js/swfupload_widget.js	2011-08-09 03:52:06 +0000
@@ -3,27 +3,50 @@
  */
 function SWFU(id, settings) {
   var ref = {};
-  ref.settings = {};
 
+  // SWFUpload object, initialized with ref.settings
+  ref.swfu;
+  ref.settings = {};
   ref.ajax_settings = {};
-  ref.queue = {};
-  ref.stats = {};
   ref.instance = {};
-  ref.upload_stack_length = 0;
-  ref.max_queue_size = 0;
-  ref.upload_stack = {};
-  ref.upload_stack_obj;
+
+  // Upload queue, used by implementations of variousinstance callbacks
+  // (fileQueued, uploadComplete, etc)
+  ref.queue = {};
+
+  // DOM object for upload button; is already built (but disabled)
+  // in HTML output from server.
   ref.upload_button_obj;
-  ref.upload_stack_size = 0;
+
+  // DOM object for hidden input element which will contain info about all
+  // uploaded files (plus those already present, when editing an existing node).
+  // Its value will be interpreted by the field's #value_callback on the server.
+  ref.upload_stack_obj;
+  // The same value, stored as an array for internal use
+  // (easier to manipulate than the JSON stored in upload_stack_obj).
+  ref.upload_stack = [];
+  ref.upload_stack_length = 0;  // number of files uploaded
+  ref.upload_stack_size = 0;    // total file size
+  ref.max_queue_size = 0;       // setting: max total file size
+
+  // DOM object containing HTML output for all uploaded files; this corresponds
+  // to the upload stack, and is the user-readable/editable version of it.
+  // Built by createWrapper() on initComplete()
   ref.wrapper_obj;
   ref.wrapper_id;
+  // Number of elements in one table row. (Elements proviced by AJAX request.)
   ref.num_elements;
   ref.key_pressed;
+
+  // DOM object containing feedback messages to display;
+  // inserted after wrapper_obj, by displayMessage()
   ref.message_wrapper_obj;
   ref.messages_timeout;
 
   /**
-   * 
+   * Initialization function. Stores provided settings in this object, prepares
+   * button, sends POST request to server (for access check and more settings),
+   * and calls ajaxResponse() with the result.
    */
   ref.init = function() {
     ref.settings = settings;
@@ -40,6 +63,21 @@ function SWFU(id, settings) {
       },
       success:function(result) {
         ref.ajaxResponse(result);
+      },
+      error:function(jqXHR, textStatus, errorThrown) {
+        switch (textStatus) {
+          case 'error':
+            var msg = Drupal.t('Error during initial callback to /swfupload')
+              + '! Status: ' + jqXHR.status + '/' + jqXHR.statusText
+              + ' /  Error: ' + errorThrown;
+            if (jqXHR.status == 403) {
+              msg += '. ' + Drupal.t('You may not have permission to upload files with swfupload.')
+            }
+            alert(msg);
+            break;
+          default:
+            alert(Drupal.t('Error during initial callback to /swfupload') + ': ' + textStatus);
+        }
       }
     };
 
@@ -69,25 +107,14 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Creates a hidden input field which will contain a JSON formatted string containing all uploaded files
-   */
-  ref.createStackObj = function() {
-    var upload_stack_value = settings.custom_settings.upload_stack_value;
-    ref.max_queue_size = settings.custom_settings.max_queue_size;
-    ref.upload_stack_obj = $('<input type="hidden" />').attr('name', ref.instance.name).val(upload_stack_value).prependTo(ref.upload_button_obj);
-    ref.upload_stack = Drupal.parseJson(upload_stack_value);
-    ref.upload_stack_length = ref.objectLength(ref.upload_stack);
-  };
-
-  /**
-   * 
+   * Gets new initialized SWFUpload object.
    */
   ref.newSWFUpload = function() {
     ref.swfu = new SWFUpload(ref.settings);
   };
 
   /**
-   * 
+   * Callback with result of a succesful POST request.
    */
   ref.ajaxResponse = function(result) {
     var result = Drupal.parseJson(result);
@@ -100,6 +127,7 @@ function SWFU(id, settings) {
           ref.settings[setting] = eval(callback);
         });
         ref.newSWFUpload();
+        // init_complete_handler is set on the server side; default is initComplete
         ref.settings.init_complete_handler(result);
         break;
     };
@@ -107,8 +135,8 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Custom function for when the initialization is complete
-   * This event handler is defined in swfupload.module as an instance callback function 
+   * Default 'init_complete_handler' (SWFUpload instance callback function)
+   * Event handlers are defined on the server side, in swfupload_js()
    */
   ref.initComplete = function(result) {
     ref.createWrapper(result.instance.name);
@@ -126,36 +154,48 @@ function SWFU(id, settings) {
   };
 
   /**
-   * This will process all file elements stored in the upload stack.
-   * The upload represents all files submitted in the upload form.
-   * For all files in the stack, a file element will be added to the wrapper using ref.addFileItem().
+   * Creates a hidden input field which will contain a JSON formatted string containing all uploaded files
+   */
+  ref.createStackObj = function() {
+    var upload_stack_value = settings.custom_settings.upload_stack_value;
+    ref.max_queue_size = settings.custom_settings.max_queue_size;
+    ref.upload_stack_obj = $('<input type="hidden" />').attr('name', ref.instance.name).val(upload_stack_value).prependTo(ref.upload_button_obj);
+    ref.upload_stack = Drupal.parseJson(upload_stack_value);
+    ref.upload_stack_length = ref.objectLength(ref.upload_stack);
+  };
+
+  /**
+   * Processes all file elements stored in the upload stack;
+   * 'populates' the wrapper object.
    */
   ref.addStoredFiles = function() {
+    var fid = 0;
     for(var i in ref.upload_stack) {
       if (ref.upload_stack[i] == 0) {
         break;
       };
-      ref.upload_stack[i].id = i;
-      ref.upload_stack[i].fid = i;
+      fid = ref.upload_stack[i].fid;
+      ref.upload_stack[i].id = fid;
       ref.upload_stack[i].extension = ref.getExtension(ref.upload_stack[i].filename);
       ref.addFileItem(ref.upload_stack[i]);
 
       // Adjust the bytes in the stack.
       ref.upload_stack_size += parseInt(ref.upload_stack[i].filesize);
     };
+    // Attach the tabledrag behavior.
+    Drupal.attachBehaviors(ref.wrapper_obj);
     ref.addEventHandlers('drag_enable');
   };
 
   /**
-   * Places the wrapper markup above the upload button
+   * Places the wrapper markup above the upload button.
    * Depending on what type isset by the instance, a table or a list element is created.
    */
   ref.createWrapper = function(field_name) {
     var use_header = false;
-    var element;
 
     if (ref.num_elements > 1 && ref.instance.type == 'table') {
-      // First we'll check if we need to create a header 
+      // First we'll check if we need to create a header
       for (var name in ref.instance.elements) {
         if (ref.instance.elements[name].title) {
            use_header = true;
@@ -176,11 +216,11 @@ function SWFU(id, settings) {
 
       Drupal.settings.tableDrag['swfupload_file_wrapper-' + field_name] = {};
     };
-  };    
+  };
 
   /**
    * Creates or changes a tablerow
-   * @param header Boolean Wheter or not the tablerow should contain th's. If sety to false, td's will be generated.
+   * @param header Boolean Wheter or not the tablerow should contain th's. If set to false, td's will be generated.
    * @param file Object A completed file object 
    *   - If this is not set, a row is created including the progressbar, which replaces the td's with contains_progressbar set to true.
    *   - If file is set, the progressbar will be replaced with the appropriate td's
@@ -190,7 +230,7 @@ function SWFU(id, settings) {
     var colspan = 0;
     var fid = (file) ? file.fid : 0;
     var progress_td_counter = 0;
-    var element, colum, content, input, progress_td, elem_value, value;
+    var element, column, content, input, progress_td, elem_value, value;
 
     var tr = (file) ? $('#' + file.fid) : $('<tr />');
     var wrapper = $('<div />').addClass('wrapper');
@@ -207,9 +247,24 @@ function SWFU(id, settings) {
 
       if (file) {
         if(!element.contains_progressbar) {
-          // The current td doesn't have to be replaced.
-          // We only need to replace fid of the id and name of the input field
+          // We need to replace fid of the id and name of the input field
           tr.find('#edit-' + name + '_0').attr({'name':name +'_' + fid, 'id':'edit-' + name + '_' + fid});
+
+          // No other updates needed, except for icon
+          if (element.type == 'icon') {
+            column = tr.find('.sfwupload-list-mime');
+            if (file.thumb) {
+              column.css({'background-image': 'url(' + file.thumb + ')'});
+            }
+            else if (file.extension) {
+              // Add the extension to the mime icon
+              column.addClass(file.extension);
+            }
+            // Fix transparency for IE6
+            if ($.cssPNGFix) {
+              column.cssPNGFix();
+            }
+          }
           continue;
         };
       }
@@ -317,7 +372,7 @@ function SWFU(id, settings) {
   };
 
   /**
-   * A file has been selected. This function creates the markup referring to the new file object
+   * Creates HTML markup for a file object; inserts it into the wrapper.
    */
   ref.addFileItem = function(file) {
     // Create the markup for the new file by copying the hidden template 
@@ -327,7 +382,8 @@ function SWFU(id, settings) {
     // Remove tabledrag elements
     new_file_obj.find('a.tabledrag-handle').remove();
 
-    // If it is a file earlier stored (a file in the upload_stack), remove it's progressbar.
+    // If it is a file earlier stored (a file in the upload_stack),
+    // remove its progressbar / update its icon
     if (file.filestatus !== -1) {
       ref.tableRow(false, file);
     };
@@ -354,20 +410,6 @@ function SWFU(id, settings) {
       };
     };
 
-    if (file.thumb) {
-      // Attach the thumbnail image
-      new_file_obj.find('.sfwupload-list-mime').css({'background-image': 'url(' + file.thumb + ')'});
-    }
-    else {
-      // Add the extension to the mime icon
-      new_file_obj.find('.sfwupload-list-mime').addClass(file.extension);
-    };
-
-    // Fix transparency for IE6
-    if ($.cssPNGFix) {
-      new_file_obj.find('.sfwupload-list-mime').cssPNGFix();
-    };
-
     new_file_obj.removeClass('hidden').addClass('draggable');
     ref.addEventHandlers((file.filestatus == -1 ? 'file_queued' : 'file_added'), file);
   };
@@ -409,16 +451,16 @@ function SWFU(id, settings) {
           };
         }).parents('td').dblclick(function() {
           ref.toggleInput($(this).find('span'), true, file);
-        }).find('.wrapper').append($('<a href="#" />').text(Drupal.t('edit')).addClass('toggle-editable').click(function() {
+        }).find('.wrapper').append($('<a id="swfupload-toggle-edit' + file.fid + '" />').text(Drupal.t('edit')).addClass('toggle-editable active').click(function() {
+          // we're using 'a.active' only to catch some standard CSS rules.
+          // ID is not used; we probably should replace it by a span, but then we'd need to redo code...
           ref.toggleInput($(this).parent().find('span'), true, file);
           return false;
         }));
         break;
 
       case 'drag_enable':
-        // Attach the tabledrag behavior
-        // This will we only executed once.
-        Drupal.attachBehaviors(ref.wrapper_obj);
+        // Attach the tabledrag behavior to yet-unprocessed tablerows
     
         $('tbody tr', ref.wrapper_obj).not('.hidden, .tabledrag-handle-swfupload-moved').each(function() {
     
@@ -476,7 +518,7 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Launched when the swf has been loaded.
+   * Default 'swfupload_loaded_handler' (SWFUpload instance callback function)
    */
   ref.swfUploadLoaded = function() {
     // Update the stats object in order to let SWFUpload know we've already got some files stored
@@ -485,6 +527,7 @@ function SWFU(id, settings) {
   };
 
   /**
+   * Default 'file_dialog_complete_handler' (SWFUpload instance callback function)
    * The file(s) have been selected.
    */
   ref.dialogComplete = function(files_selected, files_queued) {
@@ -497,6 +540,7 @@ function SWFU(id, settings) {
   };
 
   /**
+   * Default 'file_queued_handler' (SWFUpload instance callback function)
    * The file(s) have been selected by the user and added to the upload queue
    */
   ref.fileQueued = function(file) {
@@ -532,7 +576,7 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Responds on file queue errors 
+   * Default 'file_queue_error_handler' (SWFUpload instance callback function)
    */
   ref.fileQueueError = function(file, code, message) {
     switch (code) {
@@ -621,15 +665,16 @@ function SWFU(id, settings) {
    * Triggers a new upload.
    */
   ref.uploadNextInQueue = function() {
-		try {
-		  ref.swfu.startUpload();
-		}
-		catch (err) {
-		  ref.swfu.debug(err);
-		};
+    try {
+      ref.swfu.startUpload();
+    }
+    catch (err) {
+      ref.swfu.debug(err);
+    };
   };
 
   /**
+   * Default 'upload_progress_handler' (SWFUpload instance callback function)
    * Adjusts the progress indicator.
    */
   ref.uploadProgress = function(file, complete, total) {
@@ -639,7 +684,7 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Handles upload errors
+   * Default 'upload_error_handler' (SWFUpload instance callback function)
    */
   ref.uploadError = function(file, code, message) {
     // Check for messages which can be handled as 'status' messages
@@ -664,28 +709,7 @@ function SWFU(id, settings) {
   };
 
   /**
-   * Triggered after the upload is succesfully completed.
-   */
-  ref.uploadComplete = function(file) {
-    if (ref.queue[file.id] && !ref.queue[file.id].cancelled) {
-      setTimeout(function() {
-        $('#' + ref.queue[file.id].fid).find('.sfwupload-list-progressbar').animate({'opacity':0}, "slow", function() {
-          file.fid = ref.queue[file.id].fid;
-          ref.tableRow(false, file);
-          ref.updateStack(file);
-          ref.addEventHandlers('file_added', file);
-
-          if (ref.queue[file.id].thumb) {
-            $('.sfwupload-list-mime', $('#' + ref.queue[file.id].fid)).css({'background-image': 'url(' + ref.queue[file.id].thumb + ')'});
-          };
-          ref.upload_button_obj.removeClass('swfupload-error');
-        });
-      }, 1000);
-    };
-		ref.uploadNextInQueue();
-  };
-
-  /**
+   * Default 'upload_success_handler' (SWFUpload instance callback function)
    * Retrieves the data returned by the server
    */
   ref.uploadSuccess = function(file, server_data) {
@@ -721,34 +745,78 @@ function SWFU(id, settings) {
   };
 
   /**
+   * Default 'upload_complete_handler' (SWFUpload instance callback function)
+   */
+  ref.uploadComplete = function(file) {
+    if (ref.queue[file.id] && !ref.queue[file.id].cancelled) {
+      setTimeout(function() {
+        $('#' + ref.queue[file.id].fid).find('.sfwupload-list-progressbar').animate({'opacity':0}, "slow", function() {
+          file.fid = ref.queue[file.id].fid;
+          file.thumb = ref.queue[file.id].thumb;
+          ref.tableRow(false, file);
+          ref.updateStack(file);
+          ref.addEventHandlers('file_added', file);
+          ref.upload_button_obj.removeClass('swfupload-error');
+        });
+      }, 1000);
+    };
+    ref.uploadNextInQueue();
+  };
+
+  /**
    * Updates the value of the hidden input field which stores all uploaded files
    */
   ref.updateStack = function(file) {
-    var fid, input_field, element;
-    var old_upload_stack = ref.upload_stack;
+    var fid, input_field, fobj, i;
+    var old_stack = {};
+    var filefid = 0;
     var total_size = 0;
-    ref.upload_stack = {};
 
+    // index array elements by fid
+    for (i in ref.upload_stack) {
+      fobj = ref.upload_stack[i];
+      fid = fobj.fid;
+      old_stack[fid] = fobj;
+    }
+    ref.upload_stack = [];
+    if (file) {
+      filefid = (file.fid ? file.fid : file.id);
+    }
+    i = 0;
+
+    // Loop through all 'processed' objects in the wrapper object.
+    // Keep data in the upload stack (possibly reordered) for all those objects,
+    // except for the object that corresponds to the 'file' function argument.
+    // (This implies that the wrapper object must already be updated to have
+    // the 'processed' class added/removed, before this function is called.)
     ref.wrapper_obj.find('.processed').each(function() {
       fid = $(this).attr('id');
 
-      // If no file is secified, the function is called after sorting
-      // There are no new values so the file object is not needed
-      // We only need to change the order of the stack 
-      if (!file) {
-        ref.upload_stack[fid] = old_upload_stack[fid];
+      if (fid !== filefid) {
+        // Do not change data for this file (only change order, possibly)
+        ref.upload_stack[i] = old_stack[fid];
+        total_size += parseInt(old_stack[fid]['filesize']);
       }
       else {
-        ref.upload_stack[fid] = {filename:file.filename || file.name, fid:fid};
+        // Add this file to the data (or update its data)
+        // (Note: file.size = int?)
+        // Note: for files which are already saved in an existing node, several
+        // more properties (like filemime, timestamp) are stored in
+        // the upload_stack_obj value. These will now be removed upon e.g.
+        // ticking the 'list' checkbox, and not be submitted back to the server.
+        // This doesn't seem to have any adverse effect.
+        ref.upload_stack[i] = {fid:fid, filename:file.filename || file.name, filesize:file.size, thumb:file.thumb};
         total_size += parseInt(file.size);
         for (var name in ref.instance.elements) {
           input_field = $('#edit-' + name + '_' + fid);
           if (input_field.size() !== 0) {
-            ref.upload_stack[fid][name] = (input_field.attr('type') == 'checkbox') ? input_field.attr('checked') : input_field.val();
+            ref.upload_stack[i][name] = (input_field.attr('type') == 'checkbox') ? input_field.attr('checked') : input_field.val();
           };
         };
       };
+      i++;
     });
+
     ref.upload_stack_size = total_size;
     ref.upload_stack_length = ref.objectLength(ref.upload_stack);
     ref.upload_stack_obj.val(ref.toJson(ref.upload_stack));
@@ -810,13 +878,14 @@ function SWFU(id, settings) {
             file_tr.remove();
             clearInterval(intv);
 
-            // Reset the successfull upload queue
+            // Reset the successful upload queue
             var stats = ref.swfu.getStats();
             stats.successful_uploads--;
             ref.swfu.setStats(stats);
 
             if (file_tr) {
-              // Update the hidden input field
+              // Update the hidden input field.
+              // (Note: passing file arg doesn't currently do anything)
               ref.updateStack(file);
             };
           };
@@ -850,10 +919,18 @@ function SWFU(id, settings) {
         return '"'+ v.replace(/\n/g, '\\n') +'"';
       case 'object':
         var output = '';
-        for(i in v) {
-          output += (output ? ',' : '') + '"' + i + '":' + ref.toJson(v[i]);
+        if (Object.prototype.toString.call(v) === '[object Array]') {
+          for(i in v) {
+            output += (output ? ',' : '') + ref.toJson(v[i]);
+          }
+          return '[' + output + ']';
+        }
+        else {
+          for(i in v) {
+            output += (output ? ',' : '') + '"' + i + '":' + ref.toJson(v[i]);
+          }
+          return '{' + output + '}';
         }
-        return '{' + output + '}';
       default:
         return 'null';
     };

=== modified file 'sites/all/modules/swfupload/swfupload.css'
--- swfupload.css	2010-10-19 00:39:29 +0000
+++ swfupload.css	2011-08-08 02:10:09 +0000
@@ -149,6 +149,10 @@ table.swfupload td:hover .toggle-editabl
   visibility: visible;
 }
 
+table.swfupload td .toggle-editable:hover {
+  cursor: pointer;
+}
+
 table.swfupload td .editable-enabled .toggle-editable {
   display: none;
 }

=== modified file 'sites/all/modules/swfupload/swfupload.module'
--- swfupload.module	2011-02-04 00:33:35 +0000
+++ swfupload.module	2011-04-01 02:30:45 +0000
@@ -162,6 +162,15 @@ function swfupload_add_js($element) {
         $flash_url = base_path() . str_replace('.js', '.swf', array_shift($swfupload_library->scripts['2.2.0.1']));
       }
 
+      $files = array();
+      if (!empty($element['#value'])) {
+        // We need to create an array in JSON notation, not an object (because
+        // Chrome/Opera may lose ordering of the elements in an object).
+        // Therefore create an array with numeric 0-based keys.
+        foreach ($element['#value'] as $file) {
+          $files[] = $file;
+        }
+      }
       $settings['swfupload_settings'][$element['#id']] = array(
         'module_path' => $path,
         'flash_url' => $flash_url,
@@ -181,7 +190,7 @@ function swfupload_add_js($element) {
         'file_types_description' => ($element['#description'] ? $element['#description'] : ''),
         'file_upload_limit' => $limit,
         'custom_settings' => array(
-          'upload_stack_value' => (!empty($element['#value'])) ? swfupload_to_js($element['#value']) : '[]',
+          'upload_stack_value' => (!empty($files)) ? swfupload_to_js($files) : '[]',
           'max_queue_size' => ($field['widget']['max_filesize_per_node'] ? $field['widget']['max_filesize_per_node'] : 0),
         ),
       );

=== modified file 'sites/all/modules/swfupload/swfupload_widget.inc'
--- swfupload_widget.inc	2010-12-28 04:15:47 +0000
+++ swfupload_widget.inc	2011-08-09 01:24:49 +0000
@@ -69,6 +69,8 @@ function swfupload_widget_validate(&$ele
  */
 function swfupload_widget_value($element, $edit = FALSE) {
   if (is_string($edit)) {
+    // This is the value of the hidden input element, which was constructed
+    // by the client JS (after e.g. uploading files).
     $edit = json_decode($edit, TRUE);
   }
 

