Zardoz

A compound field example for CCK 2 & Drupal 6

Posted in Drupal by Andrew on November 9, 2009

For anyone attempting to create a compound field (meaning a single CCK field that is made up of multiple sub-fields) in Drupal, but are lost in a sea of poorly documented hooks and functions so abstracted as to have lost nearly all meaning, like I was for the last two days, I offer you the following example module. This is tested to work on an Acquia Drupal 6.14 build with CCK version 6.x-2.5. By “work”, I mean that your form will have a compound field that saves data and is available to your $node object. There are no settings, no validation or sanitizing or views integration. This is provided as a starting point for your own custom module.

You’ll want to start with these four functions:

  1. compoundfield_field_settings(), to declare your database structure:
    /**
     * Implementation of hook_field_settings().
     */
    function compoundfield_field_settings($op, $field) {
      switch ($op) {
        case 'database columns':
          return array(
            'textfield' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => FALSE, 'views' => FALSE),
            'textarea' => array('type' => 'text', 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE),
            'select' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE, 'views' => FALSE),
          );
    
      }
    }
    
  2. compoundfield_process(), to declare the Form API structure (as you would any other Drupal form):
    /**
     * Process an individual element.
     *
     * Build the form element. When creating a form using FAPI #process,
     * note that $element['#value'] is already set.
     *
     * The $fields array is in $form['#field_info'][$element['#field_name']].
     */
    function compoundfield_process($element, $edit, $form_state, $form) {
      $element['textfield'] = array(
        '#type' => 'textfield',
        '#title' => t('Example Text Field'),
        '#maxlength' => '255',
        '#default_value' => isset($element['#value']['textfield']) ? $element['#value']['textfield'] : NULL,
      );
      $element['textarea'] = array(
        '#type' => 'textarea',
        '#title' => t('Example Textarea Field'),
        '#required' => FALSE,
        '#default_value' => isset($element['#value']['textarea']) ? $element['#value']['textarea'] : NULL,
      );
      $element['select'] = array(
        '#type' => 'select',
        '#title' => t('Example Select Field'),
        '#default_value' => isset($element['#value']['select']) ? $element['#value']['select'] : NULL,
        '#options' => array(
          '1' => t('Option 1'),
          '2' => t('Option 2'),
          '3' => t('Option 3'),
        ),
      );
      return $element;
    }
    
  3. theme_compoundfield() to theme the form HTML:
    /**
     * FAPI theme for an individual element.
     */
    function theme_compoundfield($element) {
      // If you want to add CSS (or JS) for this form, here's where you would:
      // drupal_add_css(drupal_get_path('module', 'compoundfield') .'/compoundfield.css');
      $output = '';
      $output .= '<div class="compoundfield">';
      $output .= theme('textfield', $element['textfield']);
      $output .= theme('textarea', $element['textarea']);
      $output .= theme('select', $element['select']);
      $output .= '</div>';
      return $output;
    }
    
  4. and theme_compoundfield_formatter_default() to theme the default view:
    /**
     * Theme function for 'default' example field formatter.
     *
     * $element['#item']: the sanitized $delta value for the item,
     * $element['#field_name']: the field name,
     * $element['#type_name']: the $node->type,
     * $element['#formatter']: the $formatter_name,
     * $element['#node']: the $node,
     * $element['#delta']: the delta of this item, like '0',
     *
     */
    function theme_compoundfield_formatter_default($element) {
      $output = '';
      $output .= '<div class="compoundfield-textfield">' . $element['#item']['textfield'] . '</div>';
      $output .= '<div class="compoundfield-textarea">' . $element['#item']['textarea'] . '</div>';
      $output .= '<div class="compoundfield-select">' . $element['#item']['select'] . '</div>';
      return $output;
    }
    

Suggestions, questions, and comments are all welcome. This code is mostly a combination of the link module, Karen Stevenson’s very helpful Lullabot article, and this article by Jennifer Hodgdon.

Tagged with: , ,

Minimizing TCP connections: Drupal’s Lightbox2 module

Posted in Drupal, browsers by Andrew on July 29, 2008

I’ve been trying to cut down on TCP connections per pageview for a Drupal 5 site which uses the Lightbox2 module. I noticed that the following images are loaded, even if none of the images on the page are lightboxed:

/sites/all/modules/lightbox2/images/loading.gif
/sites/all/modules/lightbox2/images/blank.gif
/sites/all/modules/lightbox2/images/prev.gif
/sites/all/modules/lightbox2/images/next.gif
/sites/all/modules/lightbox2/images/close.gif
/sites/all/modules/lightbox2/images/expand.gif
/sites/all/modules/lightbox2/images/pause.gif
/sites/all/modules/lightbox2/images/contract.gif
/sites/all/modules/lightbox2/images/play.gif

It’s possible that Firefox and IE (and/or Safari) behave differently in this case, where an image is called by the CSS background property but the containing element is set to display: none. I don’t see these as loaded in Firebug, but I do see them in “Page Info”, under Media, as well as in the HTTP access log.

Since I’m only using the loading.gif image for preloading (clicking the image itself or the overlay closes the lightbox), I want to keep from loading the rest. The solution here is to comment out the background property definitions in the lightbox2/css/lightbox.css file that call the remaining images. Having done that, the TCP connections needed for each non-cached pageview is reduced by 8.