You are here

img_assist.module in Image Assist 5.3

Image Assist module

Implements a javascript-driven user interface to upload images to a Drupal site and select a previously uploaded image for displaying inline in a content.

File

img_assist.module
View source
<?php

/**
 * @file
 * Image Assist module
 *
 * Implements a javascript-driven user interface to upload images to a Drupal
 * site and select a previously uploaded image for displaying inline in a
 * content.
 */

/**
 * Implementation of hook_help().
 */
function img_assist_help($section) {
  switch ($section) {
    case 'admin/settings/img_assist':
      return t('If this site was moved or is planned to move to another domain or sub-directory, it might be needed to <a href="!empty-cache">empty the filter cache</a> to correct image paths that are pointing to the old address.  Note that this will only work for images that have been inserted using filter tags.', array(
        '!empty-cache' => url('img_assist/cache/clear'),
      ));
    case 'img_assist/template':
      return '<div class="%image-class"><a href="%link">%image</a><div class="caption">%caption</div></div>';
  }
}

/**
 * Implementation of hook_menu().
 */
function img_assist_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $admin_access = user_access('administer site configuration');
    $ia_access = user_access('access img_assist');
    $items[] = array(
      'path' => 'img_assist/cache/clear',
      'title' => t('Empty cache'),
      'callback' => 'img_assist_cache_clear',
      'access' => $admin_access,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'img_assist/load',
      'title' => t('Image assist'),
      'callback' => 'img_assist_loader',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );

    // Page callbacks called internally by img_assist/load.
    $items[] = array(
      'path' => 'img_assist/header',
      'title' => t('Image assist header'),
      'callback' => 'img_assist_header',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'img_assist/thumbs',
      'title' => t('Image assist thumbnails'),
      'callback' => 'img_assist_thumbs',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'img_assist/upload',
      'title' => t('Image assist upload'),
      'callback' => 'img_assist_upload',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'img_assist/properties',
      'title' => t('Image assist properties'),
      'callback' => 'img_assist_properties',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );

    // Popup images page.
    $items[] = array(
      'path' => 'img_assist/popup',
      'title' => t('Popup image'),
      'callback' => 'img_assist_popup',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );

    // Insert callback (only for inserting HTML, not filter tag).
    $items[] = array(
      'path' => 'img_assist/insert_html',
      'title' => t('Insert callback'),
      'callback' => 'img_assist_insert_html',
      'access' => $ia_access,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/settings/img_assist',
      'title' => t('Image assist'),
      'description' => t('Change settings for the Image assist module.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => 'img_assist_admin_settings',
      'access' => $admin_access,
    );
  }
  else {

    // Ensure Drupal.settings.basePath on all pages (including popup window).
    drupal_add_js(array(
      'basePath' => base_path(),
    ), 'setting');
    $path = drupal_get_path('module', 'img_assist');
    if (arg(0) == 'img_assist') {

      // Suppress Administration menu.
      module_invoke('admin_menu', 'suppress');
      drupal_add_css($path . '/img_assist_popup.css', 'module', 'all', FALSE);
    }
    else {
      drupal_add_js($path . '/img_assist.js');
      if (variable_get('img_assist_page_styling', 'yes') == 'yes') {
        drupal_add_css($path . '/img_assist.css');
      }
    }
  }
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function img_assist_perm() {
  return array(
    'access img_assist',
    'access all images',
    'access advanced options',
    'use original size',
  );
}

/**
 * Implementation of hook_elements().
 */
function img_assist_elements() {
  $type['textarea'] = array(
    '#process' => array(
      'img_assist_textarea' => array(),
    ),
  );
  return $type;
}

/**
 * Add JavaScript settings for generating the image link underneath textareas.
 */
function img_assist_textarea($element) {
  static $initialized = FALSE;
  if (!user_access('access img_assist')) {
    return $element;
  }
  $link = variable_get('img_assist_link', 'icon');
  if ($link == 'icon' || $link == 'text') {
    if (_img_assist_textarea_match($element['#id']) && _img_assist_page_match() && !strstr($_GET['q'], 'img_assist')) {
      if (!$initialized) {

        // Add settings.
        $settings['link'] = $link;
        $settings['link_text'] = t('Add image');

        // D5 only.
        if ($link == 'icon') {
          $settings['icon'] = drupal_get_path('module', 'img_assist') . '/add-image.jpg';
        }
        drupal_add_js(array(
          'img_assist' => $settings,
        ), 'setting');
        $initialized = TRUE;
      }

      // Attach behavior.
      // @todo Some browsers do not support underscores in CSS classes.
      if (!isset($element['#attributes']['class'])) {
        $element['#attributes']['class'] = 'img_assist';
      }
      else {
        $element['#attributes']['class'] .= ' img_assist';
      }
    }
  }
  return $element;
}

/**
 * Implementation of hook_block().
 *
 * Generates a block that references the other places the current image is used.
 * The block is only visible when looking at the full view of an image.
 */
function img_assist_block($op = 'list', $delta = 0) {
  if ($op == 'list') {
    $blocks[0]['info'] = t('Image reference');
    return $blocks;
  }
  else {
    if ($op == 'view') {
      switch ($delta) {
        case 0:

          // Since blocks aren't passed node objects (which makes sense) we need
          // to determine if we are viewing a node and grab its nid.
          if (arg(0) == 'node' && is_numeric(arg(1))) {
            $block['subject'] = t('This image appears in...');
            $block['content'] = img_assist_get_references(arg(1));
            return $block;
          }
          break;
      }
    }
  }
}

/**
 * Implementation of hook_settings().
 */
function img_assist_admin_settings() {
  require_once drupal_get_path('module', 'img_assist') . '/includes/img_assist.token.inc';

  // Access settings.
  $form['access'] = array(
    '#type' => 'fieldset',
    '#title' => t('Access settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['access']['img_assist_paths_type'] = array(
    '#type' => 'radios',
    '#title' => t('Display Image assist on paths'),
    '#default_value' => variable_get('img_assist_paths_type', 2),
    '#options' => array(
      t('on specific paths'),
      t('not on specific paths'),
      t('all paths'),
    ),
  );
  $form['access']['img_assist_paths'] = array(
    '#type' => 'textarea',
    '#title' => t('Paths'),
    '#default_value' => variable_get('img_assist_paths', "node/*\ncomment/*"),
    '#cols' => 40,
    '#rows' => 5,
    '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array(
      '%blog' => 'blog',
      '%blog-wildcard' => 'blog/*',
      '%front' => '<front>',
    )),
  );
  $form['access']['img_assist_textareas_type'] = array(
    '#type' => 'radios',
    '#title' => t('Display Image assist on text areas'),
    '#default_value' => variable_get('img_assist_textareas_type', 2),
    '#options' => array(
      t('Show on every textarea except the listed textareas.'),
      t('Show on only the listed textareas.'),
      t('Show on all textareas.'),
    ),
  );
  $form['access']['img_assist_textareas'] = array(
    '#type' => 'textarea',
    '#title' => t('Text areas'),
    '#default_value' => variable_get('img_assist_textareas', "edit-body\nedit-comment"),
    '#cols' => 40,
    '#rows' => 5,
    '#description' => t("Enter one text area form-id per line. Form-id's are used by Drupal to typify them, which allows themers and coders to modify certain form fields, but not all. Find form-id's using this method: view the source of the webpage, then search for the string that's just above the text area and you'll see the form-id nearby. The '*' character is a wildcard. For example, you can specify all CCK fields as %cck-example.", array(
      '%cck-example' => 'edit-field-*',
    )),
  );
  $form['access']['img_assist_link'] = array(
    '#type' => 'select',
    '#title' => t('Textarea image link'),
    '#default_value' => variable_get('img_assist_link', 'icon'),
    '#options' => array(
      'icon' => t('Show icon'),
      'text' => t('Show text link'),
      'none' => t('Do not show a link'),
    ),
    '#description' => t('Choose what to show under the textareas for which Image assist is enabled.'),
  );
  if (module_exists('taxonomy')) {
    $vocs = array(
      0 => '<' . t('none') . '>',
    );
    foreach (taxonomy_get_vocabularies() as $vid => $voc) {
      $vocs[$vid] = $voc->name;
    }
    if (count($vocs) > 1) {
      $form['access']['img_assist_vocabs'] = array(
        '#type' => 'select',
        '#multiple' => TRUE,
        '#title' => t('Select the vocabularies to use for Image assist'),
        '#default_value' => variable_get('img_assist_vocabs', array()),
        '#options' => $vocs,
        '#description' => t('Select the vocabularies you want to be able to filter thumbnails by. This setting changes the behavior of Image assist at startup from loading all image thumbnails to displaying a list of image names until a filter is chosen.'),
      );
    }
  }

  // Image settings.
  $form['image'] = array(
    '#type' => 'fieldset',
    '#title' => t('Image generation settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['image']['img_assist_preview_count'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum number of thumbnails per page'),
    '#default_value' => variable_get('img_assist_preview_count', 8),
    '#size' => 6,
    '#maxlength' => 6,
    '#description' => t('Enter the number of images to display in the thumbnail browser. If there are more images, next and previous links will be displayed.'),
  );
  $form['image']['img_assist_max_size'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum inline image size allowed'),
    '#default_value' => variable_get('img_assist_max_size', '640x640'),
    '#size' => 9,
    '#maxlength' => 9,
    '#description' => t('Enter the number of maximum image dimensions to display with Image assist. This is a way to prevent users from breaking your layouts. This is applied when the filter tag is processed, so it will affect existing images. If an existing image exceeds these dimensions, a smaller derivative of the image will be substituted (or a smaller version will be created if you have allowed Image assist to create its own derivatives).'),
  );
  if (function_exists('image_get_sizes')) {
    $max_size = explode('x', variable_get('img_assist_max_size', '640x640'));
    $oversize_count = 0;
    foreach (image_get_sizes() as $key => $size) {
      $dimensions = $size['width'] . 'x' . $size['height'];
      if (!empty($size['width']) && $size['width'] <= $max_size[0] || !empty($size['height']) && $size['height'] <= $max_size[1]) {
        $derivatives[$dimensions] = $size['label'];
      }
      elseif ($key == IMAGE_THUMBNAIL) {

        // Thumbnail option is shown even if it is larger than maximum size.
        $derivatives[$dimensions] = $size['label'];
      }
      else {
        $oversize_count++;
      }
      $allsizes[$key] = $size['label'];
    }
    $form['image']['img_assist_popup_label'] = array(
      '#type' => 'select',
      '#title' => t('Popup size'),
      '#default_value' => variable_get('img_assist_popup_label', IMAGE_PREVIEW),
      '#options' => $allsizes,
      '#description' => t('Select the size of the image that is popped up.'),
    );
    $oversize_alert = $oversize_count ? '<br /><strong>' . format_plural($oversize_count, '1 image size is not being shown because it exceeds the the maximum inline image size setting (see above).', '@count image sizes are not being shown because they exceed the the maximum inline image size setting (see above).') . '</strong>' : '';
    $form['image']['img_assist_default_label'] = array(
      '#type' => 'select',
      '#title' => t('Default size for inline images'),
      '#default_value' => variable_get('img_assist_default_label', '100x100'),
      '#options' => $derivatives,
      '#description' => t('Select a derivative to be used by default for inline images.') . $oversize_alert,
    );
  }
  $form['image']['img_assist_create_derivatives'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Creation of image derivatives'),
    '#default_value' => variable_get('img_assist_create_derivatives', array()),
    '#options' => array(
      'properties' => t('Create 200x200 images for the image properties window (useful if the thumbnail size is small).'),
      'custom_advanced' => t('Allow users with %access permission to create custom size inline images.', array(
        '%access' => 'access advanced options',
      )),
      'custom_all' => t('Allow all users to create custom size inline images.'),
    ),
    '#description' => t('These options allow Image assist to generate its custom image sizes (in the same manner as image.module) when a user would prefer a different size from the default image sizes defined in the image.module settings.'),
  );

  // Other properties.
  $form['properties'] = array(
    '#type' => 'fieldset',
    '#title' => t('Image property dialog settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['properties']['img_assist_default_link_behavior'] = array(
    '#type' => 'select',
    '#title' => t('Default link behavior'),
    '#default_value' => variable_get('img_assist_default_link_behavior', 'none'),
    '#options' => array(
      'none' => t('Not a link'),
      'node' => t('Link to image page'),
      'popup' => t('Open in popup window'),
      'url' => t('Go to URL'),
    ),
    '#description' => t('The link behavior can be overridden when inserting images by users with the proper permissions, but these defaults will still be used for everyone else.'),
  );
  $form['properties']['img_assist_default_link_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Default URL'),
    '#default_value' => variable_get('img_assist_default_link_url', 'http://'),
    '#size' => 30,
    '#maxlength' => 255,
    '#description' => t('The default URL is used when Go to URL is choosen as the link behavior.'),
  );
  $form['properties']['img_assist_default_insert_mode'] = array(
    '#type' => 'select',
    '#title' => t('Default insert mode'),
    '#default_value' => variable_get('img_assist_default_insert_mode', 'none'),
    '#options' => array(
      'filtertag' => t('Filter Tag'),
      'html' => t('HTML Code'),
    ),
    '#description' => t('The insert behavior can be overridden by users with the %permission permission when inserting images.  <strong>Warning:</strong> If images are inserted as HTML, Image Assist is not able to correct a link or image URL afterwards.  Please also note that users will not be able to edit already inserted images when using HTML code and the TinyMCE plugin.', array(
      '%permission' => t('access advanced options'),
    )),
  );
  $form['properties']['img_assist_load_title'] = array(
    '#type' => 'radios',
    '#title' => t('Preset caption title'),
    '#default_value' => variable_get('img_assist_load_title', 1),
    '#options' => array(
      t('Disabled'),
      t('Enabled'),
    ),
    '#description' => t('If enabled, the title from the image will be loaded as the bolded caption by default.'),
  );
  $token_installed = module_exists('token');
  $token_instructions = !$token_installed ? t('Requires the !token module.', array(
    '!token' => l('Token', 'http://drupal.org/project/token'),
  )) : t('See below for a list of available replacement patterns.');
  $form['properties']['img_assist_title_pattern'] = array(
    '#type' => 'textfield',
    '#title' => t('Caption title pattern'),
    '#default_value' => variable_get('img_assist_title_pattern', '[title]'),
    '#size' => 60,
    '#maxlength' => 255,
    '#description' => t('The pattern to generate the bolded caption title from.') . ' ' . $token_instructions,
    '#disabled' => !$token_installed,
  );
  $form['properties']['img_assist_load_description'] = array(
    '#type' => 'radios',
    '#title' => t('Preset caption text'),
    '#default_value' => variable_get('img_assist_load_description', 1),
    '#options' => array(
      t('Disabled'),
      t('Enabled'),
    ),
    '#description' => t('If enabled, the body text from the image will be loaded as the caption by default.'),
  );
  $form['properties']['img_assist_description_pattern'] = array(
    '#type' => 'textfield',
    '#title' => t('Caption text pattern'),
    '#default_value' => variable_get('img_assist_description_pattern', '[body]'),
    '#size' => 60,
    '#maxlength' => 255,
    '#description' => t('The pattern to generate the caption text from.') . ' ' . $token_instructions,
    '#disabled' => !$token_installed,
  );
  if ($token_installed) {
    $form['properties']['token_help'] = array(
      '#title' => t('Replacement patterns'),
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['properties']['token_help'][] = array(
      '#value' => theme('token_help', 'node'),
    );
  }
  if (module_exists('content')) {
    $options = array();
    $info = _content_type_info();
    foreach ($info['content types']['image']['fields'] as $field) {
      $options[$field['field_name']] = t($field['widget']['label']) . ' (' . $field['field_name'] . ')';
    }
    $form['properties']['img_assist_display_properties'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Image properties shown'),
      '#default_value' => variable_get('img_assist_display_properties', array()),
      '#options' => $options,
      '#description' => t('All selected CCK fields from the Image node will be displayed in the Image Assist pop-up window.'),
    );
    if (empty($options)) {
      $form['properties']['img_assist_display_properties']['#description'] .= '<br />' . t('<strong>Note:</strong> The <a href="!content-type">Image content-type</a> does not contain any CCK fields currently.', array(
        '!content-type' => url('admin/content/node-type/image/fields'),
      ));
    }
  }

  // Image display settings.
  $form['display'] = array(
    '#type' => 'fieldset',
    '#title' => t('Image display settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['display']['img_assist_page_styling'] = array(
    '#type' => 'select',
    '#title' => t('Include img_assist.css on all pages for styling inline images?'),
    '#default_value' => variable_get('img_assist_page_styling', 'yes'),
    '#options' => array(
      'yes' => t('yes'),
      'no' => t('no'),
    ),
    '#description' => t('Advanced users can customize their theme\'s CSS file so that inclusion of the img_assist.css file will not be necessary. See notes at the bottom of img_assist.css for details.'),
  );
  return system_settings_form($form);
}

/**
 * Validate Image Assist settings.
 */
function img_assist_admin_settings_validate($form_id, $form_values) {

  // img_assist_max_size must contain a value for width and height.
  if (!preg_match('/\\d+x\\d+/', $form_values['img_assist_max_size'])) {
    form_set_error('img_assist_max_size', t('Allowed maximum inline image size has to indicate width and height, for example %example.', array(
      '%example' => '200x300',
    )));
  }
}

/**
 * Implementation of hook_filter().
 */
function img_assist_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return array(
        0 => t('Inline images'),
      );
    case 'description':
      return t('Add images to your posts with Image assist.');

    //    case 'no cache':
    //      return TRUE;
    case 'process':
      $processed = FALSE;
      foreach (img_assist_get_macros($text) as $unexpanded_macro => $macro) {
        $expanded_macro = img_assist_render_image($macro);
        $text = str_replace($unexpanded_macro, $expanded_macro, $text);
        $processed = TRUE;
      }
      return $processed ? theme('img_assist_filter', $text) : $text;
    default:
      return $text;
  }
}

/**
 * Implementation of hook_filter_tips().
 */
function img_assist_filter_tips($delta, $format, $long = FALSE) {
  return t('Images can be added to this post.');
}

/**
 * Implementation of hook_nodeapi().
 *
 * - Clear input filter cache.
 * - Keep track of where images are used.
 * - Catch nids of recently uploaded images.
 * 
 * @todo Remove usage of global variable.
 */
function img_assist_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'update':
      if ($node->type == 'image') {

        // Clear the input filter cache to force all node content to be rebuilt.
        // This is to make sure all image paths are up to date.
        cache_clear_all(NULL, 'cache_filter');
      }

    // break is intentionally left out.
    case 'insert':

      // Update the image map.
      img_assist_map_save($node);

      // Store nid globally if this node is an image uploaded with img_assist.
      if ($node->type == 'image' && arg(0) == 'img_assist') {
        global $_img_assist_saved_image;
        $_img_assist_saved_image = $node->nid;
      }
      break;
    case 'delete':
      img_assist_map_delete($node);
      break;
  }
}

/**
 * Menu callback; clears relevant caches, then redirects to the previous page.
 *
 * @see devel_cache_clear()
 */
function img_assist_cache_clear() {

  // clear core tables
  $core = array(
    'cache_filter',
    'cache_page',
  );
  foreach ($core as $table) {
    cache_clear_all('*', $table, TRUE);
  }
  drupal_set_message('Cache cleared.');
  drupal_goto('admin/settings/img_assist');
}

/**
 * @defgroup img_assist_pages Image Assist Pages
 * @{
 * All but img_assist_loader() are in frames.
 */

/**
 * Output main img_assist interface HTML.
 * 
 * @todo Remove hard-coded TinyMCE integration.
 */
function img_assist_loader() {
  $path = drupal_get_path('module', 'img_assist');
  $caller = arg(2) ? arg(2) : 'textarea';
  drupal_add_js($path . '/img_assist_popup.js');
  if (module_exists('wysiwyg') && ($editor = wysiwyg_get_editor($caller))) {
    if ($editor['name'] == 'tinymce') {
      drupal_add_js($editor['library path'] . '/tiny_mce_popup.js');
    }
  }
  else {
    $caller = 'textarea';
  }
  drupal_add_js($path . '/img_assist_' . $caller . '.js');
  $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">' . "\n";
  $output .= "<html>\n";
  $output .= "<head>\n";
  $output .= '<title>' . t('Add image') . "</title>\n";
  $output .= drupal_get_js();
  $output .= "</head>\n\n";
  $output .= '<frameset rows="38, *" onload="initLoader()" frameborder="0" border="0" framespacing="0">' . "\n";
  $output .= '<frame name="img_assist_header" src="" class="img_assist_header" noresize="noresize" />' . "\n";
  $output .= '<frame name="img_assist_main" src="" class="img_assist_main" noresize="noresize" />' . "\n";
  $output .= "</frameset>\n";
  $output .= "</html>\n";
  echo $output;
  exit;
}
function img_assist_header($mode) {

  // Mode may be 'uploading', 'properties' or 'browse'.
  $output = drupal_get_form('img_assist_header_form', $mode);
  echo theme('img_assist_page', $output, array(
    'id' => 'img_assist_header',
    'onload' => 'parent.initHeader();',
    'class' => 'img_assist',
  ));
  exit;
}
function img_assist_header_form($mode) {
  global $user;

  // Upload image.
  if ($mode == 'uploading') {
    $form[] = array(
      '#value' => '<div id="header-uploading">',
    );
    $form[] = array(
      '#value' => '<strong>' . t('Upload: ') . '</strong>' . t('Fill in the form below to upload a new image.'),
    );
    $form[] = array(
      '#value' => '</div><div id="header-startover">',
    );
    $form['startover'] = array(
      '#type' => 'button',
      '#value' => t('Start Over'),
      '#button_type' => 'button',
      '#attributes' => array(
        'onclick' => 'parent.onClickStartOver();',
      ),
    );
    $form[] = array(
      '#value' => '</div>',
    );
  }
  elseif ($mode == 'properties') {
    $form[] = array(
      '#value' => '<div id="header-properties">',
    );
    $form[] = array(
      '#value' => '<strong>' . t('Properties: ') . '</strong>' . t('Change how the image is displayed.'),
    );
    $form[] = array(
      '#value' => '</div><div id="header-startover">',
    );
    $form['startover'] = array(
      '#type' => 'button',
      '#value' => t('Start Over'),
      '#button_type' => 'button',
      '#attributes' => array(
        'onclick' => 'parent.onClickStartOver()',
      ),
    );
    $form[] = array(
      '#value' => '</div>',
    );
  }
  else {
    $form[] = array(
      '#value' => '<div id="header-browse">',
    );
    $form[] = array(
      '#value' => '<strong>' . t('Browse Images: ') . '</strong>',
    );

    // Get my images and count.
    $result = db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type='image' AND n.uid= %d", $user->uid);
    $count = $result ? db_result($result, 0) : 0;
    $options['myimages'] = t('My Images') . " ({$count})";

    // Get all images and count.
    // Count all published images and the user's unpublished images.
    if (user_access('access all images')) {
      $result = db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type='image' AND (n.uid = %d OR n.status = 1)", $user->uid);
      $count = $result ? db_result($result, 0) : 0;
      $options['allimages'] = t('All Images') . " ({$count})";
    }

    // Get category list.
    if (module_exists('taxonomy')) {
      $vocabs = (array) variable_get('img_assist_vocabs', array());
      foreach ($vocabs as $vid) {
        $vocab = taxonomy_get_vocabulary($vid);
        $terms = taxonomy_get_tree($vid);
        if ($terms) {
          foreach ($terms as $key => $value) {
            $tid = $value->tid;
            $name = $value->name;

            // For this term, count all published images and the user's
            // unpublished images.
            if (user_access('access all images')) {
              $result = db_query("SELECT COUNT(n.nid) FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND (n.uid = %d OR n.status = 1)", $tid, $user->uid);
            }
            else {
              $result = db_query("SELECT COUNT(n.nid) FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND n.uid = %d", $tid, $user->uid);
            }
            $count = $result ? db_result($result, 0) : 0;
            if ($count) {
              $options[$vocab->name][$tid] = $name . " ({$count})";
            }
          }
        }
      }
    }
    $form['browse'] = array(
      '#type' => 'select',
      '#default_value' => 'myimages',
      '#options' => $options,
      '#attributes' => array(
        'onchange' => 'parent.onChangeBrowseBy(this)',
      ),
    );
    if (user_access('create images')) {
      $form['upload'] = array(
        '#type' => 'button',
        '#prefix' => ' ' . t('or') . ' ',
        '#value' => t('Upload'),
        '#suffix' => ' ' . t('a new image'),
        '#button_type' => 'button',
        '#attributes' => array(
          'onclick' => 'parent.onClickUpload()',
        ),
      );
    }
    $form[] = array(
      '#value' => '</div><div id="header-cancel">',
    );
    $form['cancel'] = array(
      '#type' => 'button',
      '#value' => t('Cancel'),
      '#button_type' => 'button',
      '#attributes' => array(
        'onclick' => 'parent.cancelAction()',
      ),
    );
    $form[] = array(
      '#value' => '</div>',
    );
  }
  return $form;
}

/**
 * Interface for adding images. Uses the regular image node form.
 */
function img_assist_upload() {
  global $user;
  if (module_exists('image') && user_access('create images')) {

    // On other img_assist_pages I've added the javascript using the body onload
    // attribute, but for this page will also need the collapse functions and
    // setting the body onload interferes with this. To solve this, I'm forced
    // use the $(document).ready call. I should probably switch all the pages to
    // this format to be more Drupal friendly, but at the same time I don't know
    // if it really matters. If a user doesn't have Javascript, she can't use
    // img_assist at all.
    $output = "<script type=\"text/javascript\"><!-- \n";
    $output .= "  if (Drupal.jsEnabled) { \n";
    $output .= "    \$(document).ready(parent.initUpload);\n";
    $output .= "  } \n";
    $output .= "--></script>\n";

    // Define an empty node and fetch an image node form
    $node = array(
      'uid' => $user->uid,
      'name' => $user->name,
      'type' => 'image',
    );
    $output .= drupal_get_form('image_node_form', $node);
  }
  else {
    if (!module_exists('image')) {
      $output = t('The image module must be enabled to use Image assist.');
    }
    else {
      $output = t('Your account does not have image uploading privileges.');
    }
  }
  echo theme('img_assist_page', $output, array(
    'id' => 'img_assist_upload',
    'class' => 'img_assist',
  ));
  exit;
}

/**
 * Implementation of hook_form_alter().
 * 
 * Add a submit callback to image_node_form which alters the redirect.
 */
function img_assist_form_alter($form_id, &$form) {
  if ($form_id == 'image_node_form' && arg(0) == 'img_assist') {
    if (!is_array($form['#submit'])) {
      $form['#submit'] = array();
    }
    $form['#submit'] += array(
      'img_assist_node_form_submit' => array(),
    );
  }
}

/**
 * Submit callback for image_node_form.
 * 
 * Change the redirect from node/$nid to img_assist/properties/$nid.
 */
function img_assist_node_form_submit($form_id, $form_values) {

  // Get the nid of the newly created image (caught by img_assist_nodeapi).
  global $_img_assist_saved_image;
  drupal_goto('img_assist/properties/' . $_img_assist_saved_image);
}

/**
 * Load the thumbnail display pane.
 *
 * Grabs all images from image.module and loads the thumbnails.
 */
function img_assist_thumbs() {
  global $user;
  if (module_exists('image')) {
    $browse = arg(2);
    if ($browse == 'myimages') {
      $myimagesonly = TRUE;
      $tid = 0;
    }
    elseif ($browse == 'allimages') {
      $myimagesonly = FALSE;
      $tid = 0;
    }
    else {
      $myimagesonly = FALSE;
      $tid = $browse;
    }
    $output = '<div align="center">';

    // Show by term id.
    if ($tid) {

      // For this term, show all published images and the user's unpublished images.
      if (user_access('access all images')) {
        $query = "SELECT n.nid FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND (n.uid = %d OR n.status = 1) ORDER BY n.sticky DESC, n.created DESC";
        $params = array(
          $tid,
          $user->uid,
        );
      }
      else {
        $query = "SELECT n.nid FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND n.uid = %d ORDER BY n.sticky DESC, n.created DESC";
        $params = array(
          $tid,
          $user->uid,
        );
      }
    }
    else {

      // Show all published images and the user's unpublished images.
      if (user_access('access all images') && !$myimagesonly) {
        $query = "SELECT n.nid FROM {node} n WHERE n.type='image' AND (n.uid = %d OR n.status = 1) ORDER BY n.sticky DESC, n.created DESC";
        $params = array(
          $user->uid,
        );
      }
      else {
        $query = "SELECT n.nid FROM {node} n WHERE n.type='image' AND n.uid= %d ORDER BY n.sticky DESC, n.created DESC";
        $params = array(
          $user->uid,
        );
      }
    }
    $num_rows = FALSE;
    $show_amount = variable_get('img_assist_preview_count', 10);
    $result = pager_query($query, $show_amount, $element = 0, $count_query = NULL, $params);
    while ($row = db_fetch_object($result)) {
      $node = node_load(array(
        'nid' => $row->nid,
      ));
      $image = img_assist_display($node, IMAGE_THUMBNAIL);
      $output .= l($image, 'img_assist/properties/' . $node->nid, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = TRUE) . "\n";
      $num_rows = TRUE;
    }
    if (!$num_rows) {
      $output .= t('No images were found. Please upload a new image or browse images by a different category.');
    }
    $output .= theme('pager', NULL, $show_amount);
    $output .= '</div>';
  }
  else {
    $output = t('The Image module must be enabled to use Image assist.');
  }
  echo theme('img_assist_page', $output, array(
    'id' => 'img_assist_thumbs',
    'onload' => 'parent.initThumbs();',
    'class' => 'img_assist',
  ));
  exit;
}

/**
 * Load the image properties pane.
 */
function img_assist_properties() {
  $nid = arg(2);

  // Update is put into a hidden field so the javascript can see it.
  $update = arg(3) ? 1 : 0;
  if (is_numeric($nid) && ($node = node_load($nid)) && $node->type == 'image' && node_access('view', $node)) {
    $output = drupal_get_form('img_assist_properties_form', $node, $update);
  }
  else {
    $output = t('Image ID not found');
  }
  echo theme('img_assist_page', $output, array(
    'id' => 'img_assist_properties',
    'onload' => 'parent.initProperties();',
    'class' => 'img_assist',
  ));
  exit;
}

/**
 * Convert a node field value to text for usage in a textfield.
 */
function img_assist_sanitize($text) {
  return check_plain(trim(preg_replace("/[\r\n]+/", ' ', strip_tags($text))));
}

/**
 * Construct the image properties form.
 */
function img_assist_properties_form($node, $update) {
  require_once drupal_get_path('module', 'img_assist') . '/includes/img_assist.token.inc';
  $image_info = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL]));
  $image_info['aspect_ratio'] = $image_info['height'] / $image_info['width'];

  // Select (or generate) a preview image.
  $img_assist_create_derivatives = variable_get('img_assist_create_derivatives', array());
  if (!empty($img_assist_create_derivatives['properties'])) {
    $properties_size['label'] = t('Properties');
    $properties_size['key'] = 'img_assist_properties';
    $properties_size['width'] = 200;
    $properties_size['height'] = 200;
  }
  else {
    $properties_size['key'] = IMAGE_THUMBNAIL;
  }
  $properties_image = img_assist_display($node, $properties_size);

  // Get actual image size.
  $properties_size = image_get_info(file_create_path($node->images[$properties_size['key']]));

  // Create an array of image derivative choices
  //
  // The name for each option is actually the size in pixels, not the derivative
  // name. This is necessary so that
  // - the Javascript that process this page and inserts code to your textarea
  //   or editor will know the size to make the image placeholder (in a WYSIWYG
  //   editor)
  // - the code that processes the img_assist filter tags can work with standard
  //   sizes and custom sizes in the same way.
  // The WYSIWYG placeholder, however, is the most important reason to keep the
  // img_assist tags this way. This way users can even resize images in the
  // editor, and if they aren't allow to create custom sizes the filter will
  // pick the existing derivative that is closest to the size of the WYSIWYG
  // placeholder. For users not familiar with pixel sizes or names like
  // 'thumbnail' and 'preview', this is a nice visual way to size images.
  // The size selection dropdown could even be hidden using the stylesheet,
  // making the insertion of images even more of a visual process. And for
  // administrators and those with the proper permissions, images don't have to
  // snap to the nearest standard size. You can create any arbitrary size you
  // choose.
  $max_size = explode('x', variable_get('img_assist_max_size', '640x640'));
  foreach (image_get_sizes(NULL, $image_info['aspect_ratio']) as $key => $size) {

    // Sizes are strings, may contain '' for 0; convert to integers.
    settype($size['width'], 'int');
    settype($size['height'], 'int');
    $added_to_derivatives = FALSE;
    if ($key == IMAGE_ORIGINAL) {
      if (user_access('use original size') && $image_info['width'] <= $max_size[0] && $image_info['height'] <= $max_size[1]) {
        $derivatives[$image_info['width'] . 'x' . $image_info['height']] = $size['label'];
        $added_to_derivatives = TRUE;
      }
    }
    elseif ($size['width'] <= $max_size[0] && $size['height'] <= $max_size[1]) {
      $derivatives[$size['width'] . 'x' . $size['height']] = $size['label'];
      $added_to_derivatives = TRUE;
    }
    if (!$added_to_derivatives) {

      // The thumbnail option will be shown even if it is larger than the
      // maximum size.
      if ($key == IMAGE_THUMBNAIL) {
        $derivatives[$size['width'] . 'x' . $size['height']] = $size['label'];
      }
    }
  }

  // Add a choice for 'other' if the user has the proper permission to create
  // custom sizes.
  if (!empty($img_assist_create_derivatives['custom_advanced']) && user_access('access advanced options')) {
    $derivatives['other'] = t('Other');
  }

  // Use 'preview' size by default.
  $default_size = image_get_info(file_create_path($node->images[IMAGE_PREVIEW]));
  $default_width = $default_size['width'];
  $default_height = $default_size['height'];

  // Calculate the aspect ratio to keep in a hidden field
  //
  // When 'other' is chosen, the custom size will always follow the aspect ratio.
  // It doesn't really matter what this value is here because the actual custom
  // image will be created when the  filter tag is processed. The size, of course,
  // is a bounding box. If it a user stretches an image placeholder out of
  // proportion in the WYSIWYG editor, the image will never be out of proportion
  // on the processed page.
  $aspect_ratio = $default_height > 0 ? round($default_width / $default_height, 6) : 1;

  // Create the form.
  $form[] = array(
    '#value' => '<div id="properties">',
  );
  $form[] = array(
    '#value' => '<table width="100%" border="0" cellspacing="0" cellpadding="0">',
  );
  $form[] = array(
    '#value' => '<tr><td valign="top" rowspan="3" id="preview">',
  );
  $form[] = array(
    '#value' => $properties_image,
  );
  $form[] = array(
    '#value' => '<span id="caption" style="width: ' . $properties_size['width'] . 'px;">' . check_plain($node->title) . '</span>',
  );

  // Image node properties fieldset.
  $form['properties'] = array(
    '#type' => 'fieldset',
    '#title' => t('Image properties'),
  );
  $form['properties'][] = array(
    '#value' => '<div class="field field-type-text"><div class="field-label">' . t('Size') . ': </div><div class="field-items"><div class="field-item">' . strtr('@widthx@height px', array(
      '@width' => $image_info['width'],
      '@height' => $image_info['height'],
    )) . '</div></div></div>',
  );
  $rendered = node_build_content($node);
  foreach (array_filter(variable_get('img_assist_display_properties', array())) as $field) {
    if (isset($node->content[$field])) {
      $form['properties'][] = array(
        '#value' => drupal_render($node->content[$field]),
      );
    }
  }
  $form[] = array(
    '#value' => '</td><td width="100%" colspan="2">',
  );
  $token_installed = module_exists('token');
  if (variable_get('img_assist_load_title', 1)) {
    $title = img_assist_sanitize($token_installed ? token_replace(variable_get('img_assist_title_pattern', '[title]'), 'node', $node) : $node->title);
  }
  if (variable_get('img_assist_load_description', 1)) {
    $description = img_assist_sanitize($token_installed ? token_replace(variable_get('img_assist_description_pattern', '[body]'), 'node', $node) : $node->body);
  }
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Title (optional)'),
    '#default_value' => isset($title) ? $title : '',
    '#size' => 50,
    '#maxlength' => 255,
    '#description' => NULL,
    '#attributes' => array(
      'onblur' => 'parent.updateCaption()',
    ),
  );
  $form['desc'] = array(
    '#type' => 'textfield',
    '#title' => t('Description (optional)'),
    '#default_value' => isset($description) ? $description : '',
    '#size' => 50,
    '#maxlength' => 255,
    '#description' => NULL,
    '#attributes' => array(
      'onblur' => 'parent.updateCaption()',
    ),
  );

  // Size.
  $form[] = array(
    '#value' => '</td></tr><tr><td width="90%">',
  );
  $form[] = array(
    '#value' => '<div class="form-item" id="edit-size">',
  );
  $form[] = array(
    '#value' => '<label for="edit-size-label">' . t('Size: (max @maxsize)', array(
      '@maxsize' => variable_get('img_assist_max_size', '640x640'),
    )) . '</label>',
  );
  $form['size_label'] = array(
    '#type' => 'select',
    '#default_value' => variable_get('img_assist_default_label', '100x100'),
    '#options' => $derivatives,
    '#attributes' => array(
      'onchange' => 'parent.onChangeSizeLabel()',
    ),
  );
  $form[] = array(
    '#value' => '<div class="form-item" id="size-other">',
  );
  $form['width'] = array(
    '#type' => 'textfield',
    '#default_value' => $default_width,
    '#size' => 4,
    '#maxlength' => 4,
    '#attributes' => array(
      'onblur' => 'parent.onChangeWidth()',
    ),
  );
  $form[] = array(
    '#value' => ' x ',
  );
  $form['height'] = array(
    '#type' => 'textfield',
    '#default_value' => $default_height,
    '#size' => 4,
    '#maxlength' => 4,
    '#attributes' => array(
      'onblur' => 'parent.onChangeHeight()',
    ),
  );
  $form[] = array(
    '#value' => '</div></div>',
  );
  $form[] = array(
    '#value' => '</td><td>',
  );

  // Alignment.
  $form['align'] = array(
    '#type' => 'select',
    '#title' => t('Alignment'),
    '#default_value' => variable_get('img_assist_default_alignment', 'left'),
    '#options' => array(
      'left' => t('left'),
      'right' => t('right'),
      'none' => t('none'),
      'center' => t('center'),
    ),
    '#prefix' => '<div id="alignment">',
    '#suffix' => '</div>',
  );
  $form[] = array(
    '#value' => '</td></tr><tr><td colspan="2">',
  );

  // Link.
  if (user_access('access advanced options')) {
    $form[] = array(
      '#value' => '<div class="form-item" id="link-group">',
    );
    $form['link'] = array(
      '#type' => 'select',
      '#title' => t('Link'),
      '#default_value' => variable_get('img_assist_default_link_behavior', 'none'),
      '#options' => array(
        'none' => t('Not a link'),
        'node' => t('Link to image page'),
        'popup' => t('Open in popup window'),
        'url' => t('Go to URL'),
      ),
      '#attributes' => array(
        'onchange' => 'parent.onChangeLink()',
      ),
    );
    $form['url'] = array(
      '#type' => 'textfield',
      '#default_value' => variable_get('img_assist_default_link_url', 'http://'),
      '#size' => 25,
      '#maxlength' => 255,
      '#description' => NULL,
    );
    $form['link_options_visible'] = array(
      '#type' => 'hidden',
      '#value' => 1,
    );
    $form[] = array(
      '#value' => '</div>',
    );
  }
  else {
    $form['link'] = array(
      '#type' => 'hidden',
      '#value' => variable_get('img_assist_default_link_behavior', 'none'),
    );
    $form['url'] = array(
      '#type' => 'hidden',
      '#value' => variable_get('img_assist_default_link_url', 'http://'),
    );
    $form['link_options_visible'] = array(
      '#type' => 'hidden',
      '#value' => 0,
    );
  }

  // Default link url is needed for JS to indicate if an url has been entered.
  $form['default_url'] = array(
    '#type' => 'hidden',
    '#value' => variable_get('img_assist_default_link_url', 'http://'),
  );

  // Insert Mode (HTML or Filter Tag).
  if (user_access('access advanced options')) {
    $form[] = array(
      '#value' => '<div id="insertmode">',
    );
    $form['insertmode'] = array(
      '#type' => 'select',
      '#title' => t('Insert mode'),
      '#default_value' => variable_get('img_assist_default_insert_mode', 'filtertag'),
      '#options' => array(
        'filtertag' => t('Filter Tag'),
        'html' => t('HTML Code'),
      ),
    );
    $form[] = array(
      '#value' => '</div>',
    );
  }
  else {
    $form['insertmode'] = array(
      '#type' => 'hidden',
      '#value' => variable_get('img_assist_default_insert_mode', 'filtertag'),
    );
  }

  // Hidden Fields.
  $form['nid'] = array(
    '#type' => 'hidden',
    '#value' => $node->nid,
  );
  $form['update'] = array(
    '#type' => 'hidden',
    '#value' => $update,
  );
  $form['aspect'] = array(
    '#type' => 'hidden',
    '#value' => $aspect_ratio,
  );

  // Buttons.
  $form['buttons'] = array(
    '#prefix' => '<div id="buttons">',
    '#suffix' => '</div>',
  );
  $form['#attributes']['onsubmit'] = 'return parent.insertImage();';
  $form['buttons']['insert'] = array(
    '#type' => 'submit',
    '#value' => $update ? t('Update') : t('Insert'),
    '#attributes' => array(
      'style' => 'float: left;',
    ),
  );
  $form['buttons']['cancel'] = array(
    '#type' => 'button',
    '#value' => t('Cancel'),
    '#button_type' => 'button',
    '#attributes' => array(
      'onclick' => 'return parent.cancelAction();',
      'style' => 'float: right;',
    ),
  );
  $form[] = array(
    '#value' => '</td></tr></table></div>',
  );
  $form['#attributes']['name'] = 'img_assist';
  return $form;
}
function img_assist_properties_form_validate($form_id, $form_values) {
  $html = img_assist_render_image($form_values);
  img_assist_set_htmlcode($html);
  drupal_goto('img_assist/insert_html');
}

/**
 * Store image tag or HTML in session.
 *
 * Used for saving HTML code so it can be inserted instead of the filter tags.
 *
 * @param string $htmlcode
 *   A filter tag or HTML code. If omitted, session variable is emptied.
 *
 * @return string
 *   A previously stored value in the user session.
 */
function img_assist_set_htmlcode($htmlcode = NULL) {
  if (isset($htmlcode)) {
    $_SESSION['htmlcode'] = urlencode($htmlcode);
  }
  else {
    $html = urldecode($_SESSION['htmlcode']);
    $_SESSION['htmlcode'] = '';
    return $html;
  }
}
function img_assist_insert_html() {
  $output = drupal_get_form('img_assist_insert_html_form');
  echo theme('img_assist_page', $output, array(
    'id' => 'img_assist_insert_html',
    'onload' => 'parent.insertImage();',
    'class' => 'img_assist',
  ));
}
function img_assist_insert_html_form() {
  $htmlcode = img_assist_set_htmlcode();
  $form[] = array(
    '#id' => 'finalhtmlcode',
    '#type' => 'hidden',
    '#value' => $htmlcode,
  );
  $form['insertmode'] = array(
    '#type' => 'hidden',
    '#value' => 'html2',
  );
  return $form;
}

/**
 * @} End of "defgroup img_assist_pages".
 */

/**
 * @defgroup img_assist_image Image Assist Image Generation
 * @{
 * Functions used in image.module vs. img_assist.module (simplified):
 *
 * image.module:
 * - image_display()
 *   - is called for galleries, image nodes, image blocks, etc
 *     (everytime in image is shown)
 *   - returns <span ...><img ...></span>
 *   - can be passed a specific standard size only
 *   - may call _image_build_derivatives()
 *   - calls theme_image() to create the <img> tag
 * _image_build_derivatives()
 *   - rebuilds all standard image sizes for a particular node
 *
 * img_assist.module: (more complicated, but more flexible)
 * - image_display()
 *   - is called for thumbnails browsing, inline images, etc (everytime in image is shown)
 *   - returns <span ...><img ...></span>
 *   - can be passed EITHER a specific standard size only OR a custom size
 *   - may call _image_build_derivatives()
 *   - calls theme_image() to create the <img> tag
 * _image_build_derivatives()
 *   - rebuilds only a specfic image size (standard or custom size)
 */

/**
 * Create an IMG tag for an image.
 * 
 * This is nearly identical to image_display, but
 * - it uses a more efficient regenerate images routine
 * - the size attribute can be a custom size OR a standard size
 */
function img_assist_display(&$node, $size = NULL, $attributes = array()) {

  // Custom size should include values for label, width, and height.
  if (is_array($size) && !empty($size['key']) && !empty($size['width']) && !empty($size['height'])) {
    $label = $size['key'];
  }
  elseif ($size) {

    // Size can be an array without the width and/or height.
    if (is_array($size)) {

      // Size is no longer an array.
      $size = $size['key'];
    }
    $label = $size;
  }
  else {
    $label = IMAGE_THUMBNAIL;
  }

  // Regenerate images if necessary.
  $regen = FALSE;
  if (!isset($node->images[$label])) {
    $regen = TRUE;
  }
  elseif (!is_file(file_create_path($node->images[$label]))) {
    $regen = TRUE;
  }
  elseif (filemtime(file_create_path($node->images[$label])) < variable_get('image_updated', 0)) {
    $regen = TRUE;
  }
  else {

    // If $size is not an array, try to find the corresponding predefined size.
    // _image_build_derivatives() blindly assigns the *original* image file to
    // all derivative image sizes that are smaller than the original image size.
    // Without re-assigning the actual derivative size definition, img_assist
    // would assume that this derivative size does not exist, delete the
    // *original* file and subsequently fail to generate derivative images.
    // Also, when one predefined size has changed, the derivative sizes need to
    // be updated.
    if (!is_array($size)) {
      foreach (image_get_sizes() as $std_size) {
        if (isset($std_size['key']) && $std_size['key'] == $label) {
          $size = $std_size;
          break;
        }
      }
    }
    if (is_array($size)) {
      $info = image_get_info(file_create_path($node->images[$label]));
      if ($info['width'] != $size['width'] && $info['height'] != $size['height']) {
        $regen = TRUE;
      }
    }
  }
  if ($regen) {
    _img_assist_build_derivatives($node, $size);
  }
  return image_display($node, $label);
}

/**
 * Generate a image derivative
 *
 * @see _image_build_derivatives() in image.module
 * 
 * @param $node
 * @param $size
 *   An array containing the keys 'label', 'width', 'height'.
 */
function _img_assist_build_derivatives(&$node, $size = NULL) {

  // Verify the image module and toolkit settings.
  if (!_image_check_settings()) {
    return FALSE;
  }
  $info = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL]));

  // Custom size.
  if (is_array($size) && !empty($size['key']) && !empty($size['width']) && !empty($size['height'])) {
    $sizes = array(
      $size['key'] => $size,
    );
  }
  elseif ($size) {

    // Size can be an array without the width and/or height.
    if (is_array($size)) {
      $size = $size['key'];
    }
    $sizes = image_get_sizes();
    $sizes = array(
      $size => $sizes[$size],
    );
  }
  else {
    $sizes = image_get_sizes();
  }
  foreach ($sizes as $key => $size) {
    $size['key'] = $key;
    _img_assist_remove($node, $size);
    if (is_array($size) && $size['label'] && $size['width'] && $size['height']) {
      if ($info['width'] > $size['width'] || $info['height'] > $size['height']) {
        $source = file_create_path($node->images[IMAGE_ORIGINAL]);
        $destination = _image_filename(basename($source), $key, FALSE);
        $destination_path = file_create_path($destination);
        if (!image_scale($source, $destination_path, $size['width'], $size['height'])) {
          drupal_set_message(t('Unable to create %label image', array(
            '%label' => $size['label'],
          )), 'error');
        }
        else {

          // Set default file permissions for webserver-generated files.
          @chmod($destination_path, 0664);
          $node->images[$key] = $destination;
          _image_insert($node, $key, $destination_path);
        }
      }
      else {
        $node->images[$key] = $node->images[IMAGE_ORIGINAL];
      }
    }
  }
}
function _img_assist_remove($node, $size) {
  $result = db_query("SELECT * FROM {files} WHERE nid = %d AND filename = '%s'", $node->nid, $size['key']);
  while ($file = db_fetch_object($result)) {

    // Never delete original image.
    if ($file->filepath != $node->images[IMAGE_ORIGINAL]) {

      // Delete image file.
      file_delete(file_create_path($file->filepath));

      // Delete file reference in database.
      db_query("DELETE FROM {files} WHERE nid = %d AND filename = '%s'", $node->nid, $size['key']);
    }
  }
}

/**
 * Return image HTML.
 */
function img_assist_render_image($attributes = array()) {
  global $user;
  if ($attributes['nid']) {
    $node = node_load($attributes['nid']);

    // Get image size.
    $width = (int) $attributes['width'];
    $height = (int) $attributes['height'];
    $default_sizes = image_get_sizes();
    if ($width || $height) {

      // Check to ensure that the dimensions don't exceed the max set in the
      // img_assist settings.
      $max_size = explode('x', variable_get('img_assist_max_size', '640x640'));
      $width = $width <= $max_size[0] ? $width : $max_size[0];
      $height = $height <= $max_size[1] ? $height : $max_size[1];

      // Get width and height of original size.
      $original_size = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL]));
      if ($width == $original_size['width'] && $height == $original_size['height']) {

        // Nothing to process, this is the original image size.
        $closest_std_size = IMAGE_ORIGINAL;
        $create_custom = FALSE;
      }
      else {

        // Get width and height of preview size.
        $preview_size = image_get_info(file_create_path($node->images[IMAGE_PREVIEW]));
        $preview_width = $preview_size['width'];
        $preview_height = $preview_size['height'];
        if ($preview_width && $preview_height) {

          // Get aspect ratio from preview image dimensions.
          $aspect_ratio = round($preview_width / $preview_height, 6);

          // Get new width and height for this inline image.
          // If height is either left out or larger than width then
          // Width is controlling factor.
          if (!$height || $width && round($width / $aspect_ratio) <= $height) {
            $height = round($width / $aspect_ratio);
          }
          else {
            $width = round($height * $aspect_ratio);
          }

          // Find out whether the given width/height is the same as (or extremely
          // close to) a default image derivative size; if so, we will use the
          // default size instead of generating a custom image.
          $diag_size_new = sqrt(pow($width, 2) + pow($height, 2));
          $closest_difference = 9999;
          foreach ($default_sizes as $key => $stdsize) {
            $width_std = $stdsize['width'];
            $height_std = $stdsize['height'];

            // Diagonal size calculations require a width or height.
            if (!$height_std && !$width_std) {

              // For the original image, we can fall back to actual dimensions
              // though. In fact, IMAGE_ORIGINAL can either have maximum
              // dimensions (so aspect ratio based calculations below will apply)
              // or the real dimensions (which must be considered as valid
              // "derivative size").
              // Note that this annuls the 'use original size' user permission.
              if ($key !== IMAGE_ORIGINAL) {
                continue;
              }
              else {
                $width_std = $original_size['width'];
                $height_std = $original_size['height'];
              }
            }

            // Calculate default width and height based on aspect ratio.
            // Width is controlling factor.
            if (!$height_std && ($width_std && round($width_std / $aspect_ratio) <= $height_std)) {
              $height_std = round($width_std / $aspect_ratio);
            }
            else {
              $width_std = round($height_std * $aspect_ratio);
            }

            // Calculate diagonal size of this default size.
            $diag_size_std = sqrt(pow($width_std, 2) + pow($height_std, 2));
            $difference = abs($diag_size_new - $diag_size_std);
            if ($difference < $closest_difference) {
              $closest_std_size = $key;
              $closest_difference = $difference;
            }
          }

          // If, for any reason, no default image derivative size has a width or
          // height, fall back to IMAGE_THUMBNAIL.
          if (!isset($closest_std_size)) {
            $closest_std_size = IMAGE_THUMBNAIL;
          }
          if ($closest_difference < 3) {
            $create_custom = FALSE;
          }
          else {
            $img_assist_create_derivatives = variable_get('img_assist_create_derivatives', array());

            // If all users are allowed to create custom sized images.
            if ($img_assist_create_derivatives['custom_all']) {
              $create_custom = TRUE;
            }
            elseif ($img_assist_create_derivatives['custom_advanced']) {

              // Note: The following line is NOT the right way to do this.
              // The user acount passed to user_access() should be the user who
              // CREATED this node, not the CURRENT user. I'm not sure how to
              // get the user who created the node, because this function
              // doesn't have access to the node object. I could probably figure
              // out some hack, but I think I'm going to completely rethink the
              // 'img_assist_create_derivatives' option. When I started it this
              // method made sense, but the more I've worked on this, the more
              // confusing it gets.
              if (user_access('access advanced options', $user)) {
                $create_custom = TRUE;
              }
              else {
                $create_custom = TRUE;
              }
            }
            else {
              $create_custom = FALSE;
            }
          }
        }
      }
      if ($create_custom) {
        $size['label'] = t('Custom');

        // Add width and height to make it possible to have multiple custom
        // sizes of the same image.
        $size['key'] = 'img_assist_custom-' . $width . 'x' . $height;
        $size['width'] = $width;
        $size['height'] = $height;
      }
      else {
        $size['key'] = $closest_std_size;
      }
    }
    else {
      $size = $default_sizes[IMAGE_THUMBNAIL];
      $size['key'] = IMAGE_THUMBNAIL;
    }
    return theme('img_assist_inline', $node, $size, $attributes);
  }
  elseif ($attributes['fid']) {
    $img = img_assist_load_image($attributes['fid'], FALSE);
    $image = array_shift($img);
    $width = $attributes['width'] ? $attributes['width'] : $image->width;
    $height = $attributes['height'] ? $attributes['height'] : $image->height;
    $src = file_create_url($image->filepath);
    $class = $attributes['class'] ? $attributes['class'] : 'image';
    $img_template = theme('img_assist_legacy');
    $img_template = strtr($img_template, array(
      '%caption' => $attributes['caption'],
      '%node-link' => url('node/' . $image->nid),
      '%nid' => $image->nid,
      '%img-link' => $image->filepath,
      '%alt' => check_plain($attributes['alt']),
      '%width' => $width,
      '%height' => $height,
      '%src' => $src,
      '%image-class' => $class,
    ));
    return $img_template;
  }
}
function img_assist_popup() {
  $nid = arg(2);
  if (is_numeric($nid) && ($node = node_load($nid)) && $node->type == 'image' && node_access('view', $node)) {
    drupal_set_title(check_plain($node->title));
    $size = variable_get('img_assist_popup_label', IMAGE_PREVIEW);
    $size = array(
      'key' => $size,
    );
    $content = img_assist_display($node, $size);
    $attributes = array(
      'id' => 'img_assist_popup',
    );
    echo theme('img_assist_popup', $content, $attributes);
    exit;
  }
  else {
    return drupal_access_denied();
  }
}

/**
 * @} End of "defgroup img_assist_image".
 */

/**
 * @defgroup img_assist_reference Image Assist Image Referencing Routines
 * @{
 */

/**
 * Update the map table
 *
 * Look for any images linked in this content and keep a reference of them.
 */
function img_assist_map_save($node) {
  $content = $node->body;

  // If  CCK is used, image macros can be found in fields other than the body.
  // Get all the fields that use text filtering and extract their content:
  if (function_exists('content_types')) {
    $type = content_types($node->type);
    if (!empty($type['fields'])) {
      foreach ($type['fields'] as $field) {

        // Distinguish between plain text fields and filtered fields:
        if (!empty($field['text_processing'])) {
          if (count($node->{$field['field_name']})) {
            foreach ($node->{$field['field_name']} as $field_instance) {
              $content .= $field_instance['value'];
            }
          }
        }
      }
    }
  }

  // Get all the macros from the content:
  $macros = (array) img_assist_get_macros($content);

  // Save the image references:
  db_query('DELETE FROM {img_assist_map} WHERE nid = %d', $node->nid);
  $nids = array();
  foreach ($macros as $m) {
    if (!isset($nids[$m['nid']]) && is_numeric($m['nid'])) {
      db_query('INSERT INTO {img_assist_map} (nid, iid) VALUES(%d, %d)', $node->nid, $m['nid']);
      $nids[$m['nid']] = $m['nid'];
    }
  }
}

/**
 * Delete references to a non-existant node.
 *
 * If a node is being deleted update the map table. The node can either be an
 * image node or a node containing one ore more images. Note: nodes that link
 * to image nodes that are deleted will still be broken.
 */
function img_assist_map_delete($node) {
  db_query('DELETE FROM {img_assist_map} WHERE nid = %d OR iid = %d', $node->nid, $node->nid);
}

/**
 * Load the image map for a given nid.
 */
function img_assist_map_load($nid) {
  $imagemap = array();
  $result = db_query('SELECT * FROM {files} f INNER JOIN {img_assist_map} i ON f.nid = i.iid WHERE f.nid = %d', $nid);
  while ($data = db_fetch_object($result)) {
    $imagemap[] = $data->nid;
  }
  return $imagemap;
}

/**
 * Return a list of node links for a given nid.
 */
function img_assist_get_references($nid, $limit = 10) {
  $and_clause = array();
  $images = img_assist_map_load($nid);
  foreach ($images as $id) {
    $and_clause[] = 'n.nid = ' . $id;
  }
  $and_clause = implode(' OR ', $and_clause);
  if ($images) {
    return node_title_list(db_query_range(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n WHERE n.status = 1 AND {$and_clause} ORDER BY n.nid DESC"), 0, (int) $limit));
  }
}

/**
 * @} End of "defgroup img_assist_reference".
 */

/**
 * @defgroup img_assist_macro Image Assist Filter macro parsing
 * @{
 */

/**
 * Return all img_assist macros as an array.
 */
function img_assist_get_macros($text) {
  $m = array();
  preg_match_all('/ \\[ ( [^\\[\\]]+ )* \\] /x', $text, $matches);

  // Don't process duplicates.
  $tag_match = (array) array_unique($matches[1]);
  foreach ($tag_match as $macro) {
    $current_macro = '[' . $macro . ']';
    $param = array_map('trim', explode('|', $macro));

    // The first macro param is assumed to be the function name.
    $func_name = array_shift($param);
    if ($func_name == 'img_assist') {
      $vars = array();
      foreach ($param as $p) {
        $pos = strpos($p, '=');
        $varname = trim(substr($p, 0, $pos));
        $varvalue = substr($p, $pos + 1);
        $vars[$varname] = trim($varvalue);
      }

      // The full unaltered filter string is the key for the array of filter
      // attributes.
      $m[$current_macro] = $vars;
    }
  }
  return $m;
}

/**
 * Determine if img_assist can render the current page.
 * @see block_list().
 *
 * @return
 *   TRUE if can render, FALSE if not allowed.
 */
function _img_assist_page_match() {
  $must_match = variable_get('img_assist_paths_type', 2);
  if ($must_match == 2) {
    return TRUE;
  }
  else {
    $paths = variable_get('img_assist_paths', "node/*\ncomment/*");
    $path = drupal_get_path_alias($_GET['q']);
    $regexp = '/^(' . preg_replace(array(
      '/(\\r\\n?|\\n)/',
      '/\\\\\\*/',
      '/(^|\\|)\\\\<front\\\\>($|\\|)/',
    ), array(
      '|',
      '.*',
      '\\1' . variable_get('site_frontpage', 'node') . '\\2',
    ), preg_quote($paths, '/')) . ')$/';
    $match = preg_match($regexp, $path);
    return $match != $must_match;
  }
}

/**
 * Determine if img_assist can render the current textarea.
 * @see block_list().
 *
 * @return
 *   TRUE if can render, FALSE if not allowed.
 */
function _img_assist_textarea_match($formid) {
  $must_match = variable_get('img_assist_textareas_type', 2);
  if ($must_match == 2) {
    return TRUE;
  }
  else {
    $formids = variable_get('img_assist_textareas', "edit-body\nedit-comment");
    $regexp = '/^(' . preg_replace(array(
      '/(\\r\\n?|\\n)/',
      '/\\\\\\*/',
    ), array(
      '|',
      '.*',
    ), preg_quote($formids, '/')) . ')$/';

    // Compare with the form id.
    $page_match = preg_match($regexp, $formid);

    // When $must_match has a value of 0, img_assist is displayed on
    // all pages except those listed in img_assist_textareas. When set to 1, it
    // is displayed only on those textareas listed in img_assist_textareas.
    $page_match = !($must_match xor $page_match);
    return $page_match;
  }
}

/**
 * @} End of "defgroup img_assist_macro".
 */

/**
 * @defgroup img_assist_theme Image Assist Theme functions
 * @{
 *
 * @ingroup themeable
 */
function theme_img_assist_inline($node, $size, $attributes) {
  $caption = '';
  if ($attributes['title'] && $attributes['desc']) {
    $caption = '<strong>' . $attributes['title'] . ': </strong>' . $attributes['desc'];
  }
  elseif ($attributes['title']) {
    $caption = '<strong>' . $attributes['title'] . '</strong>';
  }
  elseif ($attributes['desc']) {
    $caption = $attributes['desc'];
  }

  // Change the node title because img_assist_display() uses the node title for
  // alt and title.
  $node->title = strip_tags($caption);
  $img_tag = img_assist_display($node, $size);

  // Always define an alignment class, even if it is 'none'.
  $output = '<span class="inline inline-' . $attributes['align'] . '">';
  $link = $attributes['link'];
  $url = '';

  // Backwards compatibility: Also parse link/url in the format link=url,foo.
  if (strpos($link, ',') !== FALSE) {
    list($link, $url) = explode(',', $link, 2);
  }
  elseif (isset($attributes['url'])) {
    $url = $attributes['url'];
  }
  if ($link == 'node') {
    $output .= l($img_tag, 'node/' . $node->nid, array(), NULL, NULL, FALSE, TRUE);
  }
  elseif ($link == 'popup') {
    $popup_size = variable_get('img_assist_popup_label', IMAGE_PREVIEW);
    $info = image_get_info(file_create_path($node->images[$popup_size]));
    $width = $info['width'];
    $height = $info['height'];
    $popup_url = file_create_url($node->images[variable_get('img_assist_popup_label', IMAGE_PREVIEW)]);
    $output .= l($img_tag, $popup_url, array(
      'onclick' => "launch_popup({$node->nid}, {$width}, {$height}); return false;",
      'target' => '_blank',
    ), NULL, NULL, FALSE, TRUE);
  }
  elseif ($link == 'url') {
    $output .= l($img_tag, $url, array(), NULL, NULL, FALSE, TRUE);
  }
  else {
    $output .= $img_tag;
  }
  if ($caption) {
    if ($attributes['align'] != 'center') {
      $info = image_get_info(file_create_path($node->images[$size['key']]));

      // Reduce the caption width slightly so the variable width of the text
      // doesn't ever exceed image width.
      $width = $info['width'] - 2;
      $output .= '<span class="caption" style="width: ' . $width . 'px;">' . $caption . '</span>';
    }
    else {
      $output .= '<span class="caption">' . $caption . '</span>';
    }
  }
  $output .= '</span>';
  return $output;
}
function theme_img_assist_filter($text) {

  // The div tag added to the end of each node is necessary to clear the
  // floating properties of inline images immediately after a node's content.
  return $text . '<div class="image-clear"></div>';
}
function theme_img_assist_popup($content, $attributes = NULL) {
  $title = drupal_get_title();
  $output = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' . "\n";
  $output .= "<html>\n";
  $output .= "<head>\n";
  $output .= '<title>' . $title . "</title>\n";
  $output .= drupal_get_html_head();
  $output .= drupal_get_css();
  $output .= "</head>\n";
  $output .= '<body' . drupal_attributes($attributes) . ">\n";
  $output .= "<!-- begin content -->\n";
  $output .= l($content, '', array(
    'onclick' => 'javascript:window.close();',
  ), NULL, NULL, FALSE, TRUE);
  $output .= "<!-- end content -->\n";
  $output .= '</body>';
  $output .= '</html>';
  return $output;
}
function theme_img_assist_page($content, $attributes = NULL) {
  $title = drupal_get_title();
  $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
  $output .= '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">' . "\n";
  $output .= "<head>\n";
  $output .= '<title>' . $title . "</title>\n";

  // Note on CSS files from Benjamin Shell:
  // Stylesheets are a problem with image assist. Image assist works great as a
  // TinyMCE plugin, so I want it to LOOK like a TinyMCE plugin. However, it's
  // not always a TinyMCE plugin, so then it should like a themed Drupal page.
  // Advanced users will be able to customize everything, even TinyMCE, so I'm
  // more concerned about everyone else. TinyMCE looks great out-of-the-box so I
  // want image assist to look great as well. My solution to this problem is as
  // follows:
  // If this image assist window was loaded from TinyMCE, then include the
  // TinyMCE popups_css file (configurable with the initialization string on the
  // page that loaded TinyMCE). Otherwise, load drupal.css and the theme's
  // styles. This still leaves out sites that allow users to use the TinyMCE
  // plugin AND the Add Image link (visibility of this link is now a setting).
  // However, on my site I turned off the text link since I use TinyMCE. I think
  // it would confuse users to have an Add Images link AND a button on the
  // TinyMCE toolbar.
  //
  // Note that in both cases the img_assist.css file is loaded last. This
  // provides a way to make style changes to img_assist independently of how it
  // was loaded.
  $output .= drupal_get_html_head();
  $output .= drupal_get_js();
  $output .= "\n<script type=\"text/javascript\"><!-- \n";
  $output .= "  if (parent.tinyMCE && parent.tinyMCEPopup && parent.tinyMCEPopup.getParam('popups_css')) {\n";
  $output .= "    document.write('<link href=\"' + parent.tinyMCEPopup.getParam('popups_css') + '\" rel=\"stylesheet\" type=\"text/css\">');\n";
  $output .= "  } else {\n";
  foreach (drupal_add_css() as $media => $type) {
    $paths = array_merge($type['module'], $type['theme']);
    foreach (array_keys($paths) as $path) {

      // Don't import img_assist.css twice.
      if (!strstr($path, 'img_assist.css')) {
        $output .= "  document.write('<style type=\"text/css\" media=\"{$media}\">@import \"" . base_path() . $path . "\";<\\/style>');\n";
      }
    }
  }
  $output .= "  }\n";
  $output .= "--></script>\n";

  // Ensure that img_assist.js is imported last.
  $path = drupal_get_path('module', 'img_assist') . '/img_assist_popup.css';
  $output .= "<style type=\"text/css\" media=\"all\">@import \"" . base_path() . $path . "\";</style>\n";
  $output .= "</head>\n";
  $output .= '<body' . drupal_attributes($attributes) . ">\n";

  // Do not display status/error messages in popup header frame.
  if (!isset($attributes['id']) || $attributes['id'] != 'img_assist_header') {
    $output .= theme('status_messages');
  }
  $output .= "<!-- begin content -->\n";
  $output .= $content;
  $output .= "<!-- end content -->\n";
  $output .= '</body>';
  $output .= '</html>';
  return $output;
}

/**
 * @} End of "defgroup img_assist_theme".
 */

/**
 * Implementation of hook_wysiwyg_include_directory().
 */
function img_assist_wysiwyg_include_directory($type) {
  switch ($type) {
    case 'plugins':
      return $type;
  }
}

/**
 * @defgroup img_assist_legacy Image Assist Legacy functions
 * @{
 * Used for backwards compatibility with original img_assist module.
 */

/**
 * Load all images into a static array.
 */
function img_assist_load_images($tid = NULL, $uid = NULL) {
  static $image;
  if ($tid) {
    foreach ($tid as $key => $term) {
      if ($term == 0) {
        unset($tid[$key]);
      }
    }
    $image = NULL;
  }
  $where = '';
  if ($uid > 0) {
    $image = NULL;
    $where = 'AND n.uid = ' . db_escape_string($uid);
  }
  if (!$image) {
    $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, r.teaser, f.* FROM {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid INNER JOIN {files} f ON n.nid = f.nid AND n.type = 'image' " . $where . " ORDER BY n.changed DESC"));
    while ($node = db_fetch_object($result)) {
      $node->filepath = file_create_path($node->filepath);
      $dim = getimagesize($node->filepath, $info);
      $node->width = $dim[0];
      $node->height = $dim[1];
      $image[$node->nid][$node->filename] = $node;
      if ($tid) {
        $tid2 = array();
        foreach (taxonomy_node_get_terms($node->nid) as $term) {
          $tid2[] = $term->tid;
        }
        if (array_intersect($tid, $tid2) == $tid) {
          $img[$node->nid][$node->filename] = $node;
        }
      }
    }
    $image = $tid ? $img : $image;

    // Note: If we didn't use "LIKE 'image/%%'" here we could load other files.
    // Might be interesting to expand on this someday.
    if ($image) {
      $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, r.teaser, f.* FROM {files} f, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid WHERE f.nid = n.nid AND f.filemime LIKE 'image/%%' AND n.nid NOT IN (" . implode(array_keys($image), ', ') . ") " . $where . " ORDER BY n.changed DESC"));
      while ($node = db_fetch_object($result)) {
        $node->filepath = file_create_path($node->filepath);
        $dim = getimagesize($node->filepath, $info);
        $node->width = $dim[0];
        $node->height = $dim[1];
        $image[$node->nid][IMAGE_THUMBNAIL] = $node;
        $image[$node->nid][IMAGE_ORIGINAL] = $node;
        if ($tid) {
          $tid2 = array();
          foreach (taxonomy_node_get_terms($node->nid) as $term) {
            $tid2[] = $term->tid;
          }
          if (array_intersect($tid, $tid2) == $tid) {
            $img[$node->nid][IMAGE_THUMBNAIL] = $node;
            $img[$node->nid][IMAGE_ORIGINAL] = $node;
          }
        }
      }
      $image = $tid ? $img : $image;
    }
  }
  return $image;
}

/**
 * Load an image from the database.
 */
function img_assist_load_image($id, $derivatives = TRUE) {
  $node = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title, f.* FROM {files} f, {node} n WHERE f.nid = n.nid AND f.fid = %d'), $id));
  $node->filepath = file_create_path($node->filepath);
  if (!$derivatives) {
    $dim = getimagesize($node->filepath, $info);
    $node->width = $dim[0];
    $node->height = $dim[1];
    $image[$node->filename] = $node;
  }
  else {
    $image_module_image = FALSE;
    if (function_exists('image_get_sizes')) {
      foreach (image_get_sizes() as $size) {
        if ($size['label'] == $node->filename) {
          $image_module_image = TRUE;
          $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, r.teaser, f.* FROM {files} f, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid WHERE f.nid = n.nid AND n.nid = %d'), $node->nid);
          while ($node = db_fetch_object($result)) {
            $node->filepath = file_create_path($node->filepath);
            $dim = getimagesize($node->filepath, $info);
            $node->width = $dim[0];
            $node->height = $dim[1];
            $image[$node->filename] = $node;
          }
          break;
        }
      }
    }
    if (!$image_module_image) {
      $dim = getimagesize($node->filepath, $info);
      $node->width = $dim[0];
      $node->height = $dim[1];
      $image[IMAGE_THUMBNAIL] = $node;
      $image[IMAGE_ORIGINAL] = $node;
    }
  }
  return $image;
}

/**
 * Attach the thumbnail metadata to the image object.
 *
 * Unfortunately we have to query the database since the thumbnail can be named
 * something entirely different from the original image.
 */
function _img_assist_get_thumbnail(&$image) {
  static $thumbs = array();
  if ($thumbs[$image->nid] === NULL) {
    $thumbpath = file_create_path(db_result(db_query("SELECT filepath FROM {files} WHERE nid = %d AND filename = '%s'", $image->nid, IMAGE_THUMBNAIL)));

    // In old versions of image.module thumbs were named 'thumb_filename.ext'.
    if (!file_exists($thumbpath)) {
      $pos = strrpos($image->filepath, '/') + 1;
      $thumbpath = file_create_path(substr($image->filepath, 0, $pos) . 'thumb_' . substr($image->filepath, $pos));
    }
    $img->thumbpath = is_file($thumbpath) && preg_match('|^' . variable_get('file_directory_path', 'files') . '\\/' . variable_get('image_default_path', 'images') . '\\/|', $image->filepath) ? $thumbpath : $image->filepath;
    $dim = getimagesize($img->thumbpath, $info);
    $img->thumbwidth = $dim[0];
    $img->thumbheight = $dim[1];
    $thumbs[$image->nid] = $img;
  }
  if ($thumbs[$image->nid]) {
    foreach ($thumbs[$image->nid] as $key => $value) {
      $image->{$key} = $value;
    }
  }
}
function theme_img_assist_legacy() {
  return '<div class="%image-class"><a href="%node-link"><img src="%src" width="%width" height="%height" alt="%alt" /></a><div class="caption">%caption</div></div>';
}

/**
 * @} End of "defgroup img_assist_legacy".
 */

Functions

Namesort descending Description
img_assist_admin_settings Implementation of hook_settings().
img_assist_admin_settings_validate Validate Image Assist settings.
img_assist_block Implementation of hook_block().
img_assist_cache_clear Menu callback; clears relevant caches, then redirects to the previous page.
img_assist_display Create an IMG tag for an image.
img_assist_elements Implementation of hook_elements().
img_assist_filter Implementation of hook_filter().
img_assist_filter_tips Implementation of hook_filter_tips().
img_assist_form_alter Implementation of hook_form_alter().
img_assist_get_macros Return all img_assist macros as an array.
img_assist_get_references Return a list of node links for a given nid.
img_assist_header
img_assist_header_form
img_assist_help Implementation of hook_help().
img_assist_insert_html
img_assist_insert_html_form
img_assist_loader Output main img_assist interface HTML.
img_assist_load_image Load an image from the database.
img_assist_load_images Load all images into a static array.
img_assist_map_delete Delete references to a non-existant node.
img_assist_map_load Load the image map for a given nid.
img_assist_map_save Update the map table
img_assist_menu Implementation of hook_menu().
img_assist_nodeapi Implementation of hook_nodeapi().
img_assist_node_form_submit Submit callback for image_node_form.
img_assist_perm Implementation of hook_perm().
img_assist_popup
img_assist_properties Load the image properties pane.
img_assist_properties_form Construct the image properties form.
img_assist_properties_form_validate
img_assist_render_image Return image HTML.
img_assist_sanitize Convert a node field value to text for usage in a textfield.
img_assist_set_htmlcode Store image tag or HTML in session.
img_assist_textarea Add JavaScript settings for generating the image link underneath textareas.
img_assist_thumbs Load the thumbnail display pane.
img_assist_upload Interface for adding images. Uses the regular image node form.
img_assist_wysiwyg_include_directory Implementation of hook_wysiwyg_include_directory().
theme_img_assist_filter
theme_img_assist_inline
theme_img_assist_legacy
theme_img_assist_page
theme_img_assist_popup
_img_assist_build_derivatives Generate a image derivative
_img_assist_get_thumbnail Attach the thumbnail metadata to the image object.
_img_assist_page_match Determine if img_assist can render the current page.
_img_assist_remove
_img_assist_textarea_match Determine if img_assist can render the current textarea.