I have a multivalue image field, and using FileField Sources, I've added a link that displays a ctools modal window that allows a user to search Apache Solr for images. The results are displayed in a table in the form. Each row in the table has a link that when clicked, should write the path to the returned image to the image field. Here's what I have so far:

    /**
     * Drupal form to be put in a modal.
     */
    function imgsearch_form($form, $form_state) {
      $form = array();
    
      $form['search_terms'] = array(
        '#type' => 'textfield',
        '#title' => t('Search text'),
        '#description' => t('Enter the search terms'),
      );
    
      $form['replace_div'] = array(
        '#prefix' => '<div id="imgsearch-replace-div">',
        '#suffix' => '</div>',
        '#weight' => 6,
      );
    
      $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Submit'),
      );
    
      return $form;
    }
    
    /**
     * Drupal form submit handler.
     */
    function imgsearch_form_submit(&$form, &$form_state) {
      // Generate the new link using the submitted text value.
      $link = _nb_alters_make_link($form_state['values']['new_link_text']);
    
      // Search Solr for images.
      $images = nb_alters_search($form_state['values']['search_terms']);
    
      if (is_array($images) && count($images > 0)) {
        // Theme the results as a table.
        $header = array(t('Image'), t('Content'), t('Add to field'));
        $rows = array();
        foreach ($images as $image) {
          // Create image style derivative for each image.
          $imagestyle = array(
            'style_name' => 'thumbnail',
            'path' => $image['filepath'],
            'width' => '',
            'height' => '',
            'alt' => '',
            'title' => $image['filename'],
          );
          $styled_image = theme('image_style', $imagestyle);
    
          $rows[] = array(
            'image' => $styled_image,
            'name' => $image['filename'],
            'add' => ctools_ajax_text_button("select", "imgsearch/nojs/imgadd/" . $fieldname, t('Select')),
          );
        }
    
        $output = theme('table', array('header' => $header, 'rows' => $rows, array('class' => array('imgsearch-table'))));
      }
      else {
        $output = '<div class="no-results>No images found</div>';
      }
    
      // Tell the browser to replace the old link with the new one.
      $form_state['ajax_commands'][] = ajax_command_replace('#imgsearch-replace-div', $output);
    }
    
    /**
     * Implementation of hook_menu.
     */
    function nb_alters_menu() {
      $items = array();
    
      $items['imgsearch/%ctools_js/imgadd/%'] = array(
        'title' => 'Add Image',
        'page callback' => 'nb_alters_add_image',
        'page arguments' => array(1, 3),
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
      );
    
      return $items;
    }
    
    /**
     *  Menu callback. Add the selected image to field_images
     */
    function nb_alters_add_image($js, $fieldname) {
      if (!$js) {
        // We don't support degrading this from js because we're not
        // using the server to remember the state of the table.
        return MENU_ACCESS_DENIED;
      }
      ctools_include('ajax');
      ctools_include('modal');
    
      $commands = array();
      $commands[] = ajax_command_html("#edit-field-images-und-3-imgsearch-file-url", "filepath");
    
      // Tell the browser to close the modal.
      $form_state['ajax_commands'][] = ctools_modal_command_dismiss();
    
      print ajax_render($commands);
      exit;
    }

The problem I'm having is when I click the "add" link, the form goes back to its original state (terms field and button, no results) and doesn't close. My menu callback is getting called, but neither of the desired results (writing the data to the field or closing the modal) is taking place

Can anyone tell what I'm doing wrong and what else I need to do to write the path to the image field and close the modal?

Thanks.

Comments

wonder95’s picture

After an IRC conversation with merlinofchaos where he pointed out my pretty obvious code errors, I've re-written my ajax function like so:

function nb_alters_add_image($js, $fieldname) {
  if (!$js) {
    // We don't support degrading this from js because we're not
    // using the server to remember the state of the table.
    return MENU_ACCESS_DENIED;
  }
  ctools_include('ajax');
  ctools_include('modal');

  $imagepath = 'http://mybucket.s3.amazonaws.com/styles/thumbnail/s3/images/2010/July/MainPhoto.jpg';

  $ajax_commands = array();
  $ajax_commands[] = ajax_command_html("#edit-field-images-und-2-imgsearch-file-url", $imagepath);

  // Tell the browser to close the modal.
  $ajax_commands[] = ctools_modal_command_dismiss();

  print ajax_render($ajax_commands);
}

This works in that it closes the modal and writes a value (both hardcoded for the moment just to get this part working), but the problem is that it adds a

after the input element instead of writing the data to the textfield itself. Is there a different command I should be using to write the image path to the text field?
wonder95’s picture

Status: Active » Closed (fixed)

For all those waiting in breathless anticipation, here's how I finally got this to work.

First, I created a custom jquery command in the Drupal.ajax.prototypes.commands space:

(function($, Drupal)
{
    // Our function name is prototyped as part of the Drupal.ajax namespace, adding to the commands:
    Drupal.ajax.prototype.commands.insertImagePath = function(ajax, response, status)
    {
        // The value we passed in our Ajax callback function will be available inside the
        // response object. Since we defined it as selectedValue in our callback, it will be
        // available in response.imageurl. 
        $(response.selector).val(response.imageurl);
    };
}(jQuery, Drupal));

Then, I added that command to the $ajax_commands array that is passed to ajx_render():

  $filename = $cache->fids[$fid];
  $imageurl = $filename .' [fid:' . $fid . ']';
  $selector = $cache->fieldname;

  $ajax_commands = array();
  // Tell the browser to close the modal.
  $ajax_commands[] = ctools_modal_command_dismiss();
  // Add our custom insertImagePath command to the commands array.
  $ajax_commands[] = array
  (
    // The command will be used in our JavaScript file (see next section)
    'command' => 'insertImagePath',
    // We pass the field name and the image URL returned from the modal window.
    'selector' => $selector,
    'imageurl' => $imageurl,
  );

and Voila!, the appropriate text is written to the image field, where it can be attached,

roppa_uk’s picture

Do you have the full working code for this? I'm trying to do something similar. Thanks!

wonder95’s picture

I'm planning on doing a blog post on this and other stuff, so I'll post the URL when it's posted.

wonder95’s picture

@roppa_uk, see here for details on working code.

malcolmp’s picture

Thanks. That was a very helpful example.