You are here

comment_upload.module in Comment Upload 6

Same filename and directory in other branches
  1. 5 comment_upload.module

Provides file attachment functionality for comments.

Written by Heine Deelstra. Copyright (c) 2008 by Ustima (http://ustima.com).

This module is licensed under GPL v2. See LICENSE.txt for more information.

File

comment_upload.module
View source
<?php

/**
 * @file
 * Provides file attachment functionality for comments.
 *
 * Written by Heine Deelstra. Copyright (c) 2008 by Ustima (http://ustima.com).
 *
 * This module is licensed under GPL v2. See LICENSE.txt for more information.
 */

/**
 * @todo views integration
 * @todo Single file attachments.
 * @todo React to content type changes
 */

/**
 * Implementation of hook_menu().
 */
function comment_upload_menu() {
  $items = array();
  $items['comment-upload/js'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'comment_upload_js',
    'access arguments' => array(
      'upload files to comments',
    ),
  );
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function comment_upload_perm() {
  return array(
    'upload files to comments',
    'view files uploaded to comments',
  );
}
function comment_upload_theme() {
  return array(
    'comment_upload_attachments' => array(
      'template' => 'comment-upload-attachments',
      'arguments' => array(
        'files' => NULL,
        'display_images' => FALSE,
        'preset' => NULL,
      ),
    ),
    'comment_upload_form_current' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'comment_upload_form_new' => array(
      'arguments' => array(
        'form' => NULL,
      ),
    ),
  );
}

/**
 * Add an Attachments for comments setting to the content type settings forms.
 *
 * Implementation of hook_form_alter().
 */
function comment_upload_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
    $form['comment']['comment_upload'] = array(
      '#type' => 'radios',
      '#title' => t('Attachments on comments'),
      '#default_value' => variable_get('comment_upload_' . $form['#node_type']->type, 0),
      '#options' => array(
        t('Disabled'),
        t('Enabled'),
      ),
      '#weight' => 20,
    );
    $image_options = array(
      'none' => t('Display as attachment'),
      'inline' => t('Display as full image'),
    );
    if (module_exists('imagecache')) {
      $presets = imagecache_presets();
      foreach ($presets as $preset_id => $preset) {
        $image_options[$preset_id] = t('Display via imagecache preset !preset', array(
          '!preset' => $preset['presetname'],
        ));
      }
    }
    $form['comment']['comment_upload_images'] = array(
      '#type' => 'select',
      '#title' => t('Image attachments on comments'),
      '#default_value' => variable_get('comment_upload_images_' . $form['#node_type']->type, 'none'),
      '#options' => $image_options,
      '#weight' => 20,
    );
  }
  elseif ($form_id == 'comment_form') {
    comment_upload_alter_comment_form($form, $form_state);
  }
}

/**
 * Alter the comment form to support AHAH uploads.
 *
 * Note; not a hook implementation.
 */
function comment_upload_alter_comment_form(&$form, $form_state) {
  if (!user_access('upload files to comments')) {
    return;
  }

  // Check whether attachments are enabled for comments on this content type.
  $node = node_load($form['nid']['#value']);
  if (!variable_get('comment_upload_' . $node->type, 0)) {
    return;
  }
  $files = array();
  $cid = $form['cid']['#value'];

  // Rebuild indicates whether we have a pristine form (FALSE) or one that has been trough validation -> submission once.
  if (empty($form_state['rebuild'])) {
    if ($cid) {

      // Attempt to load files for an existing comment.
      $files = comment_upload_load_files($cid);
    }
  }
  else {

    // Using the Attach button without JS does not generate a preview.
    // Rape the comment form.
    // Comment_form was not build to rebuild a form and fetch values from $form_state.
    // To preserve changes made by the user, we build the part of the form we just received,
    // mapping $_POST values to #default_values.
    // Because rebuild is TRUE, $_POST has been validated. Nevertheless this is insane.
    $copy_form = $form;
    $copy_form['#post'] = $_POST;
    unset($copy_form['#post']['op']);
    unset($copy_form['#after_build']);
    $build_form = form_builder('comment_form', $copy_form, $state);
    comment_upload_value_to_default($build_form, $form);
    form_clean_id(NULL, TRUE);
    if (isset($form_state['storage']['comment_upload_storage'])) {
      $files = $form_state['storage']['comment_upload_storage'];
      if (count($files) > 1) {
        uasort($files, 'comment_upload_sort_files');
      }
    }
  }
  $form['#comment_upload_storage'] = $files;
  $form['attachments'] = array(
    '#type' => 'fieldset',
    '#title' => t('File attachments'),
    '#collapsible' => TRUE,
    '#collapsed' => count($files) == 0,
    '#description' => t('Changes made to the attachments are not permanent until you save this post.'),
    '#prefix' => '<div class="attachments">',
    '#suffix' => '</div>',
  );

  // Wrapper for fieldset contents (used by ahah.js).
  $form['attachments']['wrapper'] = array(
    '#prefix' => '<div id="attach-wrapper">',
    '#suffix' => '</div>',
  );
  $form['attachments']['wrapper'] += comment_upload_upload_form($files);
  $form['#attributes']['enctype'] = 'multipart/form-data';

  // Comment_form dynamically adds buttons such as preview / save in the
  // formbuilder. As the attachment fieldset contains an AHAH element, the
  // #cache property of the form will be set to TRUE and the formbuilder will
  // no longer be called. Therefore, comment_upload needs to implement preview
  // functionality as well.
  $form['#validate'][] = 'comment_upload_comment_form_validate';
}

/**
 * Implementation of hook_file_download().
 */
function comment_upload_file_download($filepath) {
  $filepath = file_create_path($filepath);
  $result = db_query("SELECT f.*, cu.nid FROM {files} f INNER JOIN {comment_upload} cu ON f.fid = cu.fid WHERE filepath = '%s'", $filepath);
  if ($file = db_fetch_object($result)) {
    if (user_access('view files uploaded to comments') && ($node = node_load($file->nid)) && node_access('view', $node)) {
      return array(
        'Content-Type: ' . mime_header_encode($file->filemime),
        'Content-Length: ' . $file->filesize,
      );
    }
    else {
      return -1;
    }
  }
}

/*
 * Implements hook_project_issue_json_alter().
 */
function comment_upload_project_issue_json_alter(&$issue_json) {
  $result = comment_upload_fetch_all($issue_json['id'], FALSE);
  while ($row = db_fetch_object($result)) {
    $issue_json['attachments'][$row->cid]['contributorId'] = $row->uid;
    $issue_json['attachments'][$row->cid]['commentId'] = $row->cid;
    $issue_json['attachments'][$row->cid]['urls'][$row->fid] = file_create_url($row->filepath);
  }
}

/**
 * Retrieve all files attached to a given node.
 *
 * @param $nid
 *   A node ID.
 * @param $include_unpublished
 *   If TRUE, return all attached files; if FALSE, only return files attached to published comments.
 * @return resource
 *   A database result resource or FALSE if the query fails.
 */
function comment_upload_fetch_all($nid, $include_unpublished = FALSE) {
  $order_by = 'ORDER BY cu.cid ASC, fid ASC';
  $q = "SELECT cu.fid, cu.nid, cu.cid, f.filepath, c.status, c.thread, u.uid, u.name  FROM {comment_upload} cu INNER JOIN {files} f ON cu.fid = f.fid INNER JOIN {comments} c ON cu.cid = c.cid INNER JOIN {users} u ON c.uid = u.uid WHERE cu.nid = %d";
  if ($include_unpublished) {
    return db_query("{$q} {$order_by}", $nid);
  }
  else {
    return db_query("{$q} AND c.status = %d {$order_by}", $nid, COMMENT_PUBLISHED);
  }
}

/*
 * Listen to node deletion and delete files from comments on that node.
 *
 * (comment_nodeapi does not call comment APIs when deleting).
 *
 * Implementation of hook_nodeapi().
 */
function comment_upload_nodeapi(&$node, $op, $arg = 0) {
  if ($op == 'delete') {
    $result = comment_upload_fetch_all($node->nid, TRUE);
    while ($row = db_fetch_array($result)) {

      // comment_upload_delete_file just needs a filepath and a fid.
      comment_upload_delete_file($row);
    }
  }
}

/**
 * Implementation of hook_comment().
 */
function comment_upload_comment(&$a1, $op) {
  switch ($op) {
    case 'insert':
    case 'update':
      comment_upload_save($a1);
      break;
    case 'delete':
      comment_upload_comment_delete($a1);
      break;
    case 'view':
      comment_upload_comment_view($a1);
      break;
  }
}

/**
 * Traverse a build form and copy #value to corresponding #default_values in an unbuild form.
 *
 * @param array $build_form
 * @param array $form
 */
function comment_upload_value_to_default($build_form, &$form) {
  if (!is_array($build_form)) {
    return;
  }
  foreach (element_children($build_form) as $key) {
    if (isset($form[$key]) && isset($build_form[$key]['#value'])) {
      $form[$key]['#default_value'] = $build_form[$key]['#value'];
    }
    comment_upload_value_to_default($build_form[$key], $form[$key]);
  }
}

/**
 * Build the section of the upload_form that holds the attachments table and upload element.
 *
 * @param array $files
 * @return array
 */
function comment_upload_upload_form($files = array()) {
  $form = array(
    '#theme' => 'comment_upload_form_new',
  );
  if (!empty($files) && is_array($files)) {
    $count = count($files);
    $form['files']['#theme'] = 'comment_upload_form_current';
    $form['files']['#tree'] = TRUE;
    foreach ($files as $key => $file) {
      $file = (object) $file;
      $form['files'][$key] = comment_upload_create_file_element($file, $count);
    }
  }
  $limits = _upload_file_limits($GLOBALS['user']);
  $form['new']['upload'] = array(
    '#type' => 'file',
    '#title' => t('Attach new file'),
    '#description' => ($limits['resolution'] ? t('Images are larger than %resolution will be resized. ', array(
      '%resolution' => $limits['resolution'],
    )) : '') . t('The maximum upload size is %filesize. Only files with the following extensions may be uploaded: %extensions. ', array(
      '%extensions' => $limits['extensions'],
      '%filesize' => format_size($limits['file_size']),
    )),
  );
  $form['new']['attach'] = array(
    '#type' => 'submit',
    '#value' => t('Attach'),
    '#name' => 'attach',
    '#ahah' => array(
      'path' => 'comment-upload/js',
      'wrapper' => 'attach-wrapper',
      'progress' => array(
        'type' => 'bar',
        'message' => t('Please wait...'),
      ),
    ),
    '#submit' => array(),
    '#validate' => array(
      'comment_upload_comment_form_validate',
    ),
  );
  return $form;
}

/**
 * Create the form elements for one file in the attachments table.
 *
 * @param object $file
 * @param integer $count
 * @return array
 */
function comment_upload_create_file_element($file, $count) {
  $element = array();
  $description = "<small>" . check_plain(file_create_url($file->filepath)) . "</small>";
  $element['description'] = array(
    '#type' => 'textfield',
    '#default_value' => !empty($file->description) ? $file->description : $file->filename,
    '#maxlength' => 256,
    '#description' => $description,
  );
  $element['size'] = array(
    '#value' => format_size($file->filesize),
  );
  $element['remove'] = array(
    '#type' => 'checkbox',
    '#default_value' => !empty($file->remove),
  );
  $element['list'] = array(
    '#type' => 'checkbox',
    '#default_value' => $file->list,
  );
  $element['weight'] = array(
    '#type' => 'weight',
    '#delta' => $count,
    '#default_value' => $file->weight,
  );
  $element['filename'] = array(
    '#type' => 'value',
    '#value' => $file->filename,
  );
  $element['filepath'] = array(
    '#type' => 'value',
    '#value' => $file->filepath,
  );
  $element['filemime'] = array(
    '#type' => 'value',
    '#value' => $file->filemime,
  );
  $element['filesize'] = array(
    '#type' => 'value',
    '#value' => $file->filesize,
  );
  $element['fid'] = array(
    '#type' => 'value',
    '#value' => $file->fid,
  );
  $element['new'] = array(
    '#type' => 'value',
    '#value' => FALSE,
  );
  return $element;
}

/**
 * Remove files when the comment is deleted.
 *
 * @param object $comment
 */
function comment_upload_comment_delete($comment) {
  $files = comment_upload_load_files($comment->cid);
  if (!empty($files)) {
    foreach ($files as $fid => $file) {
      comment_upload_delete_file($file);
    }
  }
}

/**
 * Add attachments to the comment on view or preview.
 *
 * @param object $comment
 */
function comment_upload_comment_view(&$comment) {
  $display_images = FALSE;
  $preset_name = '';
  if (isset($comment->files)) {
    $files = $comment->files;
  }
  else {
    $files = comment_upload_load_files($comment->cid);
  }
  if (isset($files) && count($files)) {
    if (user_access('view files uploaded to comments')) {
      $node = node_load($comment->nid);
      $display_setting = variable_get('comment_upload_images_' . $node->type, 'none');
      if ($display_setting != 'none') {
        $display_images = TRUE;
        if (is_numeric($display_setting)) {
          $imagecache_preset = imagecache_preset($display_setting);
          $preset_name = $imagecache_preset['presetname'];
        }
      }
      $comment->files = $files;
      $comment->comment .= theme('comment_upload_attachments', $files, $display_images, $preset_name);
    }
  }
}

/**
 * Save the changes made to attachments.
 *
 * @param array $comment
 */
function comment_upload_save($comment) {
  if (!user_access('upload files to comments')) {
    return;
  }
  if (!isset($comment['files']) || !is_array($comment['files'])) {
    return;
  }
  foreach ($comment['files'] as $fid => $file) {
    if (!empty($file['remove'])) {
      comment_upload_delete_file($file);
    }
    if (!empty($file['new'])) {
      db_query("INSERT INTO {comment_upload} (fid, cid, nid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $fid, $comment['cid'], $comment['nid'], $file['list'], $file['description'], $file['weight']);
      $file = (object) $file;
      file_set_status($file, FILE_STATUS_PERMANENT);
    }
    else {
      db_query("UPDATE {comment_upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d", $file['list'], $file['description'], $file['weight'], $fid);
    }
  }
}

/**
 * React to the Attach button; update file information on AHAH request.
 */
function comment_upload_js() {
  $cached_form_state = array();
  $files = array();

  // Load the form from the Form API cache.
  if (empty($_POST) || !($cached_form = form_get_cache($_POST['form_build_id'], $cached_form_state)) || !isset($cached_form['#comment_upload_storage']) || !isset($cached_form['attachments'])) {
    form_set_error('form_token', t('Validation error, please try again. The file you attempted to upload may be too large. If this error persists, please contact the site administrator.'));
    $output = theme('status_messages');
    print drupal_to_js(array(
      'status' => TRUE,
      'data' => $output,
    ));
    exit;
  }
  $form_state = array(
    'values' => $_POST,
  );
  comment_upload_process_files($cached_form, $form_state);
  if (!empty($form_state['values']['files'])) {
    foreach ($form_state['values']['files'] as $fid => $file) {
      if (isset($cached_form['#comment_upload_storage'][$fid])) {
        $files[$fid] = $cached_form['#comment_upload_storage'][$fid];
      }
    }
  }
  $form = comment_upload_upload_form($files);
  unset($cached_form['attachments']['wrapper']['new']);
  $cached_form['attachments']['wrapper'] = array_merge($cached_form['attachments']['wrapper'], $form);
  $cached_form['attachments']['#collapsed'] = FALSE;
  form_set_cache($_POST['form_build_id'], $cached_form, $cached_form_state);
  foreach ($files as $fid => $file) {
    if (is_numeric($fid)) {
      $form['files'][$fid]['description']['#default_value'] = $form_state['values']['files'][$fid]['description'];
      $form['files'][$fid]['list']['#default_value'] = !empty($form_state['values']['files'][$fid]['list']);
      $form['files'][$fid]['remove']['#default_value'] = !empty($form_state['values']['files'][$fid]['remove']);
      $form['files'][$fid]['weight']['#default_value'] = $form_state['values']['files'][$fid]['weight'];
    }
  }

  // Render the form for output.
  $form += array(
    '#post' => $_POST,
    '#programmed' => FALSE,
    '#tree' => FALSE,
    '#parents' => array(),
  );

  // Normally, we would call drupal_alter($form_id, $form, $form_state).
  // However, drupal_alter() normally supports just one byref parameter. Using
  // the __drupal_alter_by_ref key, we can store any additional parameters
  // that need to be altered, and they'll be split out into additional params
  // for the hook_form_alter() implementations.
  $data =& $form;
  $form_state_empty = array();
  $data['__drupal_alter_by_ref'] = array(
    &$form_state_empty,
  );
  drupal_alter('form', $data, 'comment_upload_js');
  $form_state = array(
    'submitted' => FALSE,
  );
  $form = form_builder('comment_upload_js', $form, $form_state);
  $output = theme('status_messages') . drupal_render($form);

  // We send the updated file attachments form.
  // Don't call drupal_json(). ahah.js uses an iframe and
  // the header output by drupal_json() causes problems in some browsers.
  $GLOBALS['devel_shutdown'] = FALSE;
  echo drupal_to_js(array(
    'status' => TRUE,
    'data' => $output,
  ));
  exit;
}

/**
 * Process file uploads.
 *
 * @param array $form
 * @param array $form_state
 */
function comment_upload_process_files(&$form, &$form_state) {
  $limits = _upload_file_limits($GLOBALS['user']);
  $validators = array(
    'file_validate_extensions' => array(
      $limits['extensions'],
    ),
    'file_validate_image_resolution' => array(
      $limits['resolution'],
    ),
    'file_validate_size' => array(
      $limits['file_size'],
      $limits['user_size'],
    ),
  );

  // Save new file uploads.
  if (user_access('upload files to comments') && ($file = file_save_upload('upload', $validators, file_directory_path()))) {
    $file->list = variable_get('upload_list_default', 1);
    $file->description = $file->filename;
    $file->weight = 0;
    $file->remove = 0;
    if (!isset($form_state['values']['files'][$file->fid]['filepath'])) {
      $form_state['values']['files'][$file->fid] = (array) $file;
      $file->new = TRUE;
      $form['#comment_upload_storage'][$file->fid] = (array) $file;
    }
  }
  else {
    $errors = form_get_errors();
    if (!empty($errors)) {
      return 0;
    }
    else {

      // If no file has been entered, we have an empty upload element in files.
      unset($form_state['values']['files']['upload']);
    }
  }
  if (isset($form_state['values']['files'])) {
    foreach ($form_state['values']['files'] as $fid => $file) {
      $form_state['values']['files'][$fid]['new'] = !empty($form['#comment_upload_storage'][$fid]['new']) ? TRUE : FALSE;
    }
  }

  // Order the form according to the set file weight values.
  if (!empty($form_state['values']['files'])) {
    $microweight = 0.001;
    foreach ($form_state['values']['files'] as $fid => $file) {
      if (is_numeric($fid)) {
        $form_state['values']['files'][$fid]['#weight'] = $file['weight'] + $microweight;
        $microweight += 0.001;
      }
    }
    uasort($form_state['values']['files'], 'element_sort');
  }
}

/**
 * Additional submit handler for the comment form.
 *
 * @param array $form
 * @param array $form_state
 */
function comment_upload_comment_form_submit($form, &$form_state) {
  comment_upload_process_files($form, $form_state);
  unset($form_state['storage']);
}

/**
 * Submit handler for the preview and attach button.
 *
 * @param array $form
 * @param array $form_state
 */
function comment_upload_comment_form_validate($form, &$form_state) {
  if (empty($form_state['values']['op']) && (isset($form_state['clicked_button']) && $form_state['clicked_button']['#value'] != t('Attach'))) {
    return;
  }
  elseif (!empty($form_state['rebuild'])) {
    return;
  }
  comment_upload_process_files($form, $form_state);
  foreach ($form['#comment_upload_storage'] as $fid => $file) {
    if (is_numeric($fid)) {
      $form['#comment_upload_storage'][$fid]['description'] = $form_state['values']['files'][$fid]['description'];
      $form['#comment_upload_storage'][$fid]['list'] = $form_state['values']['files'][$fid]['list'];
      $form['#comment_upload_storage'][$fid]['remove'] = $form_state['values']['files'][$fid]['remove'];
      $form['#comment_upload_storage'][$fid]['weight'] = $form_state['values']['files'][$fid]['weight'];
      $form_state['storage']['comment_upload_storage'][$fid] = $form['#comment_upload_storage'][$fid];
    }
  }
  if (isset($form_state['values']['op']) && $form_state['values']['op'] == t('Preview') || isset($form_state['clicked_button']) && $form_state['clicked_button']['#value'] == t('Attach')) {
    $form_state['rebuild'] = TRUE;
  }
  elseif (!empty($form_state['submitted'])) {
    unset($form_state['storage']);
  }
  return;
}

/**
 * Load attachments that belong to the comment.
 *
 * @param integer $cid
 * @return array
 */
function comment_upload_load_files($cid) {
  $files = array();
  $result = db_query('SELECT * FROM {files} f INNER JOIN {comment_upload} cu ON f.fid = cu.fid WHERE cu.cid = %d ORDER BY cu.weight, f.fid', $cid);
  while ($file = db_fetch_array($result)) {
    $files[$file['fid']] = $file;
  }
  return $files;
}

/**
 * Delete a file and its associated records.
 *
 * @param array $file
 */
function comment_upload_delete_file($file) {
  file_delete($file['filepath']);
  db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']);
  db_query("DELETE FROM {comment_upload} WHERE fid = %d", $file['fid']);
}

/**
 * Sort on weight, if weights are equal compare fid.
 *
 * uasort callback.
 */
function comment_upload_sort_files($a, $b) {
  if ($a['weight'] == $b['weight']) {
    return $a['fid'] < $b['fid'] ? -1 : 1;
  }
  return $a['weight'] < $b['weight'] ? -1 : 1;
}

/**
 * Theme the attachments list in the upload form.
 *
 * Taken from upload.module.
 *
 * @ingroup themeable
 */
function theme_comment_upload_form_current($form) {
  $header = array(
    '',
    t('Delete'),
    t('List'),
    t('Description'),
    t('Weight'),
    t('Size'),
  );
  drupal_add_tabledrag('comment-upload-attachments', 'order', 'sibling', 'comment-upload-weight');
  foreach (element_children($form) as $key) {

    // Add class to group weight fields for drag and drop.
    $form[$key]['weight']['#attributes']['class'] = 'comment-upload-weight';
    $row = array(
      '',
    );
    $row[] = drupal_render($form[$key]['remove']);
    $row[] = drupal_render($form[$key]['list']);
    $row[] = drupal_render($form[$key]['description']);
    $row[] = drupal_render($form[$key]['weight']);
    $row[] = drupal_render($form[$key]['size']);
    $rows[] = array(
      'data' => $row,
      'class' => 'draggable',
    );
  }
  $output = theme('table', $header, $rows, array(
    'id' => 'comment-upload-attachments',
  ));
  $output .= drupal_render($form);
  return $output;
}

/**
 * Theme the upload a new attachment part of the upload form.
 *
 * Taken from upload.module.
 *
 * @ingroup themeable
 */
function theme_comment_upload_form_new($form) {
  drupal_add_tabledrag('comment-upload-attachments', 'order', 'sibling', 'comment-upload-weight');
  $output = drupal_render($form);
  return $output;
}
function template_preprocess_comment_upload_attachments(&$variables) {
  $row = 0;
  $variables['images'] = array();
  $variables['attachments'] = array();
  foreach ($variables['files'] as $fid => $file) {
    if ($file['list'] && empty($file['remove'])) {
      $text = $file['description'] ? $file['description'] : $file['filename'];
      if ($variables['display_images'] && strpos($file['filemime'], 'image/') === 0) {
        if ($variables['preset']) {
          $variables['images'][$fid]['image'] = theme('imagecache', $variables['preset'], file_create_path($file['filepath']), $text, $text);
        }
        else {
          $variables['images'][$fid]['image'] = theme('image', file_create_path($file['filepath']), $text, $text);
        }
        $variables['images'][$fid]['url'] = check_url(file_create_url($file['filepath']));
      }
      else {
        $variables['attachments'][$fid]['zebra'] = $row % 2 == 0 ? 'odd' : 'even';
        $variables['attachments'][$fid]['text'] = check_plain($text);
        $variables['attachments'][$fid]['url'] = check_url(file_create_url($file['filepath']));
        $variables['attachments'][$fid]['size'] = format_size($file['filesize']);
        $row++;
      }
    }
  }
}

Functions

Namesort descending Description
comment_upload_alter_comment_form Alter the comment form to support AHAH uploads.
comment_upload_comment Implementation of hook_comment().
comment_upload_comment_delete Remove files when the comment is deleted.
comment_upload_comment_form_submit Additional submit handler for the comment form.
comment_upload_comment_form_validate Submit handler for the preview and attach button.
comment_upload_comment_view Add attachments to the comment on view or preview.
comment_upload_create_file_element Create the form elements for one file in the attachments table.
comment_upload_delete_file Delete a file and its associated records.
comment_upload_fetch_all Retrieve all files attached to a given node.
comment_upload_file_download Implementation of hook_file_download().
comment_upload_form_alter Add an Attachments for comments setting to the content type settings forms.
comment_upload_js React to the Attach button; update file information on AHAH request.
comment_upload_load_files Load attachments that belong to the comment.
comment_upload_menu Implementation of hook_menu().
comment_upload_nodeapi
comment_upload_perm Implementation of hook_perm().
comment_upload_process_files Process file uploads.
comment_upload_project_issue_json_alter
comment_upload_save Save the changes made to attachments.
comment_upload_sort_files Sort on weight, if weights are equal compare fid.
comment_upload_theme
comment_upload_upload_form Build the section of the upload_form that holds the attachments table and upload element.
comment_upload_value_to_default Traverse a build form and copy #value to corresponding #default_values in an unbuild form.
template_preprocess_comment_upload_attachments
theme_comment_upload_form_current Theme the attachments list in the upload form.
theme_comment_upload_form_new Theme the upload a new attachment part of the upload form.