Wouldn't it be great to be able to upload files via the ctools content_type config modals? Yeah!

This is tricky because xhttp requests can't be multipart-form/data, so jQuery.form runs them through an iframe, which works great except that it complicates responses in JSON or pure js. See the "File Uploads" section within the code-samples on the jQuery.form homepage for more in-depth background:

http://malsup.com/jquery/form/#code-samples

As per the suggestion there, this patch forces the iframe method whenever a file-upload form element is present, and uses the textarea wrapper around the response.

This patch shows a working (if not especially awesome) implementation by making the following changes:

1) Changes Drupal.CTools.Modal.submitAjaxForm to detect for a multipart form. If so, enforce the iframe method, include a different callback handler to process the textarea-wrapped response, and append a little ?ctools_multipart to the ajax url so that...

2) ajax.inc now looks for $_GET['ctools_mulipart'] and returns textare-wrapped json, without setting any headers.

3) Quickly added a file-upload to the custom content_type. It doesn't meaningfully process the file, but you'll see that it is present in $_FILES. This code should be dumped, but I include it for demonstration purposes.

Comments

joshk’s picture

StatusFileSize
new4.33 KB
joshk’s picture

StatusFileSize
new3.89 KB

Updated patch as per some suggestions from Dmitrig01. Cleaner in modal.js.

dmitrig01’s picture

Removed one more line:

  var object = $(this);
  try {
    url.replace('/nojs/', '/ajax/');
    var ajaxSettings = {};
    if ($(this).attr('enctype') == 'multipart/form-data') {
      url = url + '?ctools_multipart=1';
      ajaxSettings.success = Drupal.CTools.AJAX.iFrameJsonRespond;
      ajaxSettings.iframe = true;
    }
    else {
      ajaxSettings.success = Drupal.CTools.AJAX.respond;
      ajaxSettings.iframe = false;
    }
    $(this).ajaxSubmit({
      type: "POST",
      url: url,
      data: '',
      global: true,
      error: function() { 
	      alert("An error occurred while attempting to process " + url); 
	    },
      complete: function() {
        object.removeClass('ctools-ajaxing');
        $('.ctools-ajaxing', object).removeClass('ctools-ajaxing');
      },
      dataType: 'json',
    } + ajaxSettings);
  }
merlinofchaos’s picture

Status: Active » Needs review
StatusFileSize
new3.13 KB

Here's an updated patch. The original patch made some changes that I didn't like, plus actually could introduce bugs (introducing a new variable without using 'var' explodes on some browsers, for example).

It directly added "?" to the URL which breaks when clean URLs are off, so I moved the component to the data, which means that it now checks $_REQUEST. I believe these items should be merged properly.

I didn't test a file upload; the test included modified the 'custom' type which I didn't want to accidentally commit, so I did not patch that part. So I'm putting the patch here in the hopes that someone else will test this and make sure it continues to work.

merlinofchaos’s picture

StatusFileSize
new3.24 KB

Whoops, last patch contained a leftover debug msg.

merlinofchaos’s picture

Status: Needs review » Fixed

Well, I went ahead and committed htis.

populist’s picture

Status: Fixed » Needs review
StatusFileSize
new740 bytes

I think we were rolling a little loose with adding objects (was seeing ajaxOptions contain two objects) and was seeing the page hang when trying to upload files.

      ajaxOptions = {
        success: Drupal.CTools.AJAX.iFrameJsonRespond,
        iframe: true,
        data: {'ctools_multipart': '1'}
      } + ajaxOptions;

I renamed the additive object and added a call to Jquery.extend to the end which got it working for me.

       jQuery.extend(ajaxOptions, ajaxIframeOptions);
joshk’s picture

We should revisit this in light of the beta4 release. Since it currently doesn't work, and RC1 is coming real soon now, I'm giving it a bump.

merlinofchaos’s picture

I had totally missed that htis had a new patch. Josh, can you confirm for me that populist's patch works?

populist’s picture

Version: 6.x-1.x-dev » 6.x-1.0-beta4
StatusFileSize
new775 bytes

the new version of ctools broke the passing of data through the data attribute of the ajax submit options. the ctools_multipart variable previous defined (see below) is nowhere to be seen in ctools_ajax_render().

ajaxIframeOptions = {
         success: Drupal.CTools.AJAX.iFrameJsonRespond,
         iframe: true,
        data: {'ctools_multipart': '1'}
}

my solution is to pass back the ctools_multipart value using that same form (which ctools_ajax_render()) like so:

$(this).append('<input type="hidden" name="ctools_multipart" value="1">');

i rerolled my old patch (which is still necessary to merge the javascript objects) and posted it all together. works in my two test cases.

markus_petrux’s picture

Status: Needs review » Needs work

I think the file upload issue was solved in CCK using this in the AHAH callback:

  // Using drupal_json() breaks filefield's file upload, because the jQuery
  // Form plugin handles file uploads in a way that is not compatible with
  // 'text/javascript' response type.
  $GLOBALS['devel_shutdown'] =  FALSE;
  print drupal_to_js(array('status' => TRUE, 'data' => $output));
  exit;

Note that this also disables devel_shutdown.

If populist's patch needs to get in, then I would suggest using $.extend() rather than jQuery.extend().

merlinofchaos’s picture

Committed, with the $.extend change.

merlinofchaos’s picture

Status: Needs work » Fixed

#13 suggests I committed this, so 'needs work' is wrong status.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

eugenmayer’s picture

Category: feature » bug
Status: Closed (fixed) » Active

Can anybody confirm this is working for him in IE Browsers? I cant. Simple "only one file" upload method, wont work.
Not work is probably the wrong description. The file gets uploaded, but the request result is somehow a unknown filetype for the IE ( unkown Mime ) instead of being json.

Bit of researching told be that it is quiet a bad idea calling form.submit() in a IE, because this will include other security checks, making those json call fail.

I expect this http://drupal.org/node/947532 to be a similar issue or rather the same

eugenmayer’s picture

Title: Allow file uploads through ctools modals » Documentation how to use ctools modal dialog for file uploads
Category: bug » feature

well finally gound out that it all comes down to a missing

form['#attributes']['enctype'] = 'multipart/form-data';

See the other issue for detailed explaination. Should we include that in the ctools docs somehow? Debugging this is a reayl painfull work...

merlinofchaos’s picture

That's actually a general form api issue. You can't upload files to forms, CTools or not, without that. Perhaps this could be stressed in the CTools documentation, but I'm not certain where.

amitaibu’s picture

@EugenMayer,
There's an example module I did that uses CTools' ajax for file upload in #940286: Code example for "File" form element in ajax form, that might help you.

eugenmayer’s picture

you can upload files without setting this @merlin, it actually really affects the ajax part right now, due the jquery selector.
@19 well its fixed for me already, i was just thinking about saving other peoples time searching for this.

amitaibu’s picture

fyi, I have stumbled upon a case where $_POST was empty in IE when submitting a modal when $form_state['has_file_element'] was set to true -- #1158928: Set $form_state['has_file_element'] only when file element is accessible

yesct’s picture

populist’s picture

Status: Active » Closed (fixed)

I am going to close this issue since the primary purpose was already solved. If this is still an issue, feel free to open a new one in the queue!