You are here

better_formats.module in Better Formats 6

Enhances Drupal's core input format settings.

Allows setting of defaults per role and content type, controls format display options, works with CCK fields.

File

better_formats.module
View source
<?php

/**
 * @file
 * Enhances Drupal's core input format settings.
 *
 * Allows setting of defaults per role and content type,
 * controls format display options, works with CCK fields.
 */

/**
 * Implementation of hook_help().
 */
function better_formats_help($path, $arg) {
  switch ($path) {
    case 'admin/help/better_formats':
      $output = '<p>' . t('See the module README.txt file in the better_formats module directory for help.') . '</p>';
      break;
    default:
      $output = '';
  }
  return $output;
}

/**
 * Implementation of hook_perm().
 */
function better_formats_perm() {
  return array(
    'show format selection for nodes',
    'show format selection for comments',
    'show format selection for blocks',
    'show format tips',
    'show more format tips link',
    'collapse format fieldset by default',
    'collapsible format selection',
  );
}

/**
 * Implementation of hook_menu().
 */
function better_formats_menu() {
  $items = array();
  $items['admin/settings/filters/settings'] = array(
    'title' => 'Settings',
    'description' => 'Manage input formats',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'better_formats_settings_admin_form',
    ),
    'access arguments' => array(
      'administer filters',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 3,
    'file' => 'better_formats_settings.admin.inc',
  );
  $items['admin/settings/filters/defaults'] = array(
    'title' => 'Defaults',
    'description' => 'Manage input formats',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'better_formats_defaults_admin_form',
    ),
    'access arguments' => array(
      'administer filters',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
    'file' => 'better_formats_defaults.admin.inc',
  );
  return $items;
}

/**
 * Implementation of hook_theme().
 */
function better_formats_theme() {
  return array(
    'better_formats_defaults_admin_form' => array(
      'template' => 'better-formats-defaults-admin-form',
      'file' => 'better_formats_defaults.admin.inc',
      'arguments' => array(
        'form' => NULL,
      ),
    ),
    'better_formats_filter_tips_more_info' => array(
      'arguments' => array(),
    ),
  );
}

/**
 * Implementation of hook_form_alter().
 */
function better_formats_form_alter(&$form, $form_state, $form_id) {

  // Alter new node and comment forms.
  // Using $form['#id'] instead of $form_id because $form_id is in the form of
  // 'TYPE_node_form' which varies with the content type while $form['#id']
  // is always 'node-form'.
  switch ($form['#id']) {
    case 'comment-form':
    case 'panels-comment-form':
      better_formats_set_comment_format($form);
      break;
    case 'node-form':
      better_formats_set_node_format($form);
      break;
    case 'block-add-block-form':
    case 'block-admin-configure':
      better_formats_set_block_format($form);
      break;
  }

  // Alter role add/delete and node type forms.
  switch ($form_id) {
    case 'node_type_form':
      if (variable_get('better_formats_per_node_type', FALSE)) {
        better_formats_node_type_form($form, $form_state);
      }
      break;
    case 'user_admin_new_role':
      if (!in_array('better_formats_new_role', $form['#submit'])) {
        $form['#submit'][] = 'better_formats_new_role';
      }
      break;
    case 'user_admin_role':
      if (isset($form_state['post']['op']) && $form_state['post']['op'] == 'Delete role') {
        $form['#submit'][] = 'better_formats_delete_role';
      }
      break;
  }
}

/**
 * FAPI form to add to the content type edit form.
 *
 * @see better_formats_node_type_form_validate()
 * @see better_formats_node_type_form_submit()
 */
function better_formats_node_type_form(&$form, $form_state) {

  // Add JS to enhance form.
  drupal_add_js(drupal_get_path('module', 'better_formats') . '/better_formats_node_type_form.js');
  $node_type = $form['#node_type']->type;

  // Build array of all formats for allowed checkboxes.
  $formats = filter_formats();
  foreach ($formats as $format) {
    $format_boxes[$format->format] = $format->name;
  }
  $key = 'better_formats';
  $form[$key] = array(
    '#type' => 'fieldset',
    '#title' => t('Input format settings'),
    '#access' => user_access('administer filters'),
    '#collapsible' => TRUE,
    // Setting collapsed to false because the wieght will not be hidden otherwise
    // the fieldset will be collapsed via JS if enabled.
    '#collapsed' => FALSE,
    '#attributes' => array(
      'class' => 'input-format-settings',
    ),
  );
  $allowed_key = $key . '_allowed';
  $form[$key][$allowed_key] = array(
    '#type' => 'checkboxes',
    '#title' => t('Allowed formats'),
    '#default_value' => variable_get($allowed_key . '_' . $node_type, array()),
    '#options' => $format_boxes,
    '#description' => t('Limit the formats users have to choose from even if they have permission to use that format. This will NOT allow a user to use a format they do not have access rights to use. It will only hide additional formats they do have access rights to. If no boxes are checked, all formats that the user has permission to use will be allowed.'),
    '#attributes' => array(
      'class' => 'bf-allowed-formats',
    ),
  );
  $dform = array(
    '#tree' => TRUE,
    '#theme' => 'better_formats_defaults_admin_form',
  );
  module_load_include('admin.inc', 'better_formats', 'better_formats_defaults');
  $nform = better_formats_get_role_default_fields('node', $node_type);
  $cform = better_formats_get_role_default_fields('comment', $node_type);
  $form[$key]['better_formats_defaults'] = array_merge($dform, $nform, $cform);

  // Attach our validate and submit handlers.
  $form['#validate'][] = 'better_formats_node_type_form_validate';
  $form['#submit'][] = 'better_formats_node_type_form_submit';
}

/**
 * Handles validation of the addition to the content type edit form.
 *
 * @see better_formats_node_type_form()
 * @see better_formats_node_type_form_submit()
 */
function better_formats_node_type_form_validate($form, &$form_state) {
  module_load_include('admin.inc', 'better_formats', 'better_formats_defaults');
  better_formats_defaults_admin_form_validate($form, $form_state);
}

/**
 * Handles submission of the addition to the content type edit form.
 *
 * @see better_formats_node_type_form()
 * @see better_formats_node_type_form_validate()
 */
function better_formats_node_type_form_submit($form, &$form_state) {
  $node_type = trim($form_state['values']['type']);

  // Remove current db entries.
  $sql = "DELETE FROM {better_formats_defaults}\n          WHERE type='comment/%s' OR type='node/%s'";
  db_query($sql, $node_type, $node_type);

  // Insert defualt values into DB.
  $sql = "INSERT INTO {better_formats_defaults}\n          VALUES (%d, '%s', %d, %d, %d)";
  foreach ($form_state['values']['better_formats_defaults'] as $key => $values) {
    if (strpos($key, 'node-') === 0 || strpos($key, 'comment-') === 0) {
      list($type, $rid) = explode('-', $key);
      db_query($sql, $rid, $type . '/' . $node_type, $values['format'], 2, $values['weight']);
    }
  }

  // Node module automatically stores all settings in variable table.
  // BF saves format defaults to its own table so delete the unneeded variable.
  variable_del('better_formats_defaults_' . $node_type);
}

/**
 * Creates base format default entry for a newly created role from role from.
 *
 * @see better_formats_form_alter()
 */
function better_formats_new_role($form, &$form_state) {

  // Get the ID for the role just created.
  $sql = "SELECT rid\n          FROM {role}\n          ORDER BY rid DESC";
  $row = db_fetch_object(db_query_range($sql, 0, 1));
  better_formats_create_role($row->rid);
}

/**
 * Creates base format default entry for a newly created role.
 *
 * @see better_formats_new_role()
 */
function better_formats_create_role($rid) {

  // Create format default stubs for a role.
  $types = array(
    'node',
    'comment',
    'block',
  );
  foreach ($types as $type) {
    $values = array(
      $rid,
      $type,
      0,
      1,
      25,
    );
    drupal_write_record('better_formats_defaults', $values);
  }
}

/**
 * Deletes role format default entries for roles being deleted.
 *
 * @see better_formats_form_alter()
 */
function better_formats_delete_role($form, &$form_state) {

  // Delete role from format manager table.
  $sql = "DELETE FROM {better_formats_defaults}\n          WHERE rid = %d";
  db_query($sql, $form['rid']['#value']);
}

/**
 * Ensure that all roles have Better Format entries in the database.
 */
function better_formats_check_roles() {

  // Get all roles that do not have BF entries.
  $sql = "SELECT r.rid\n          FROM {role} r\n          LEFT JOIN {better_formats_defaults} bf\n            ON r.rid = bf.rid\n          WHERE bf.type_weight IS NULL";
  $result = db_query($sql);
  while ($role = db_fetch_object($result)) {

    // Add BF entries.
    better_formats_create_role($role->rid);
  }
}

/**
 * Implementation of hook_node_type().
 */
function better_formats_node_type($op, $info) {
  if ($op === 'delete') {

    // Delete per node type settings on node type delete.
    $sql = "DELETE FROM {better_formats_defaults}\n            WHERE type IN ('node/%s', 'comment/%s')";
    db_query($sql, $info->type, $info->type);

    // Delete node type variables.
    variable_del('better_formats_allowed_' . $info->type);
  }
}

/**
 * Implementation of hook_elements().
 *
 * Adds a process function to CCK's text module FAPI elements.
 */
function better_formats_elements() {
  return array(
    'text_textfield' => array(
      '#process' => array(
        'better_formats_text_process',
      ),
    ),
    'text_textarea' => array(
      '#process' => array(
        'better_formats_text_process',
      ),
    ),
  );
}

/**
 * Processes a CCK text elements.
 *
 * Resets the filter area with bettter_formats default.
 * This function is used to affect CCK text module fields not core fields.
 *
 * @see text_textfield_process()
 * @see text_textarea_process()
 */
function better_formats_text_process($element, $edit, $form_state, $form) {
  $field = $form['#field_info'][$element['#field_name']];
  if (!empty($field['text_processing'])) {

    // Get core default for new or selected format for existing.
    $filter_key = count($element['#columns']) == 2 ? $element['#columns'][1] : 'format';
    $format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : $element['#default_value'][$filter_key];
    $parents = array_merge($element['#parents'], array(
      $filter_key,
    ));
    $default = better_formats_get_default_format('node', $form['type']['#value']);

    // Overwrite format default if new node.
    if (!isset($form_state['values']['nid']) || empty($format)) {
      $format = $default;
    }
    $format = filter_resolve_format($format);

    // Set default format for cck textarea.
    $element['#value'][$filter_key] = $format;

    // Set filter selection form.
    $element[$filter_key] = better_formats_filter_form($format, $default, 'node', $form['type']['#value'], 1, $parents);
  }
  return $element;
}

/**
 * Processes formats for core node body fields.
 *
 * @see better_formats_form_alter()
 */
function better_formats_set_node_format(&$form) {

  // Set core body field.
  if (isset($form['body_field'])) {

    // Get default for new entries.
    $default = better_formats_get_default_format('node', $form['type']['#value']);
    if (empty($form['nid']['#value']) && !isset($form['#parameters'][1]['node_preview'])) {

      // Set format to default for new entries.
      $format = $default;
    }
    else {

      // Get existing format for core body field.
      $format = better_formats_get_current_format($form['body_field']['format']);
    }

    // Overwrite the filter form with our own.
    $form['body_field']['format'] = better_formats_filter_form($format, $default, 'node', $form['type']['#value']);
  }
}

/**
 * Processes formats for core node comment form.
 *
 * @see better_formats_form_alter()
 */
function better_formats_set_comment_format(&$form) {
  if (isset($form['comment_filter']['format'])) {
    $node = node_load($form['nid']['#value']);

    // Get BF default format.
    $default = better_formats_get_default_format('comment', $node->type);
    if (empty($form['cid']['#value'])) {

      // Set format to default for new entries.
      $format = $default;
    }
    else {

      // Get existing format for comment.
      $format = better_formats_get_current_format($form['comment_filter']['format']);
    }

    // Overwrite the filter form with our own.
    $form['comment_filter']['format'] = better_formats_filter_form($format, $default, 'comment', $node->type);
  }
}

/**
 * Processes formats for core block form.
 *
 * @see better_formats_form_alter()
 */
function better_formats_set_block_format(&$form) {
  if (isset($form['block_settings']['body_field']['format'])) {

    // Get BF default format.
    $default = better_formats_get_default_format('block');
    if (empty($form['delta']['#value'])) {

      // Set format to default for new entries.
      $format = $default;
    }
    else {

      // Get existing format for block.
      $format = better_formats_get_current_format($form['block_settings']['body_field']['format']);
    }

    // Overwrite the filter form with our own.
    $form['block_settings']['body_field']['format'] = better_formats_filter_form($format, $default, 'block');
  }
}

/**
 * Returns the format for an existing node or comment.
 *
 * @param $form
 *  FAPI form array.
 * @return
 *  Format ID.
 *
 * @see better_formats_set_node_format()
 * @see better_formats_set_comment_format()
 */
function better_formats_get_current_format($form) {

  // Default format to site default in case of error.
  $format = FILTER_FORMAT_DEFAULT;
  foreach (element_children($form) as $key) {
    $element = $form[$key];
    if ($element['#type'] === 'radio' && isset($element['#default_value'])) {
      $format = $element['#default_value'];
      break;
    }
    if ($element['#type'] === 'value' && isset($element['#value'])) {
      $format = $element['#value'];
      break;
    }
  }
  return $format;
}

/**
 * Returns the default format for an new node or comment.
 *
 * @param $mode
 *  'node', 'comment', or 'block'. Describes the top level type of default.
 * @return
 *  Format ID.
 *
 * @see better_formats_set_node_format()
 * @see better_formats_set_comment_format()
 * @see better_formats_textarea_process()
 */
function better_formats_get_default_format($mode, $node_type = '') {
  static $format;

  // Default our type to the mode (node or comment).
  $type = $mode;

  // Check if per node type is enabled and set type accordingly.
  $per_node_type = variable_get('better_formats_per_node_type', FALSE);
  if ($per_node_type && $node_type) {
    $type = $mode . '/' . $node_type;
  }

  // Only pull from the DB if we have not already checked for this specific type.
  if (!isset($format[$type])) {
    global $user;
    $types = $type;
    $format = array();
    $roles = implode(',', array_keys($user->roles));

    // Prepare types for SQL.
    if ($mode !== 'block' && $per_node_type && $node_type) {
      $types .= "','" . $mode;
    }

    // Get user's lowest weight role default.
    $sql = "SELECT format\n            FROM {better_formats_defaults}\n            WHERE rid IN ({$roles}) AND type IN ('{$types}')\n            ORDER BY type_weight DESC, weight ASC";
    $row = db_fetch_object(db_query_range($sql, 0, 1));
    $format[$type] = filter_resolve_format($row->format);
  }
  return $format[$type];
}

/**
 * Better Formats version of filter_form().
 *
 * Copied from filter.module with slight modification to handle options for
 * hiding filter selection and/or tips.
 * The $node_type param was added to the signature to enable condition by
 * content type.
 *
 * @see filter_form()
 */
function better_formats_filter_form($value = FILTER_FORMAT_DEFAULT, $default_format, $mode = 'node', $node_type = '', $weight = 1, $parents = array(
  'format',
)) {
  $value = filter_resolve_format($value);
  $formats = filter_formats();
  $show_selection = user_access('show format selection for ' . $mode . 's');
  $show_tips = user_access('show format tips');
  $show_tips_link = user_access('show more format tips link');
  $per_node_type = variable_get('better_formats_per_node_type', FALSE);
  $allowed_formats = variable_get('better_formats_allowed_' . $node_type, FALSE);

  // Check if there are node type restrictions on allowed formats.
  // If there are no retrictions set, we use the site globals as default.
  if ($per_node_type && $allowed_formats) {
    foreach ($formats as $key => $format) {
      if (!in_array($format->format, $allowed_formats)) {
        unset($formats[$key]);
      }
    }
  }

  // Ensure that our default value is allowed or change default to one that is.
  if (isset($formats[$value])) {

    // Use existing or BF default value if available.
    $default = $value;
  }
  else {
    if (isset($formats[$default_format])) {

      // Use currently set BF default as a fallback.
      $default = $default_format;
    }
    else {
      if (!empty($formats)) {

        // Current and default format are not allowed, so use first allowed format.
        reset($formats);
        $default = key($formats);
      }
      else {

        // Use core site default as a fallback if all else fails.
        $default = filter_resolve_format(FILTER_FORMAT_DEFAULT);
      }
    }
  }
  if (count($formats) > 1 && $show_selection) {
    $collapsed = user_access('collapse format fieldset by default');
    $collapsible = user_access('collapsible format selection');
    $fieldset_title = variable_get('better_formats_fieldset_title', '');
    if (module_exists('i18nstrings') && $fieldset_title) {
      $fieldset_title = i18nstrings('better_formats:fieldset_title', $fieldset_title);
    }
    else {
      $fieldset_title = $fieldset_title ? $fieldset_title : t('Input format');
    }
    $form = array(
      '#type' => 'fieldset',
      '#title' => check_plain($fieldset_title),
      '#collapsible' => $collapsible,
      '#collapsed' => $collapsed,
      '#weight' => $weight,
      '#element_validate' => array(
        'filter_form_validate',
      ),
    );

    // Multiple formats available: display radio buttons with tips.
    foreach ($formats as $format) {

      // Generate the parents as the autogenerator does, so we will have a
      // unique id for each radio button.
      $parents_for_id = array_merge($parents, array(
        $format->format,
      ));
      $form[$format->format] = array(
        '#type' => 'radio',
        '#title' => check_plain($format->name),
        '#default_value' => $default,
        '#return_value' => $format->format,
        '#parents' => $parents,
        '#id' => form_clean_id('edit-' . implode('-', $parents_for_id)),
      );
      if ($show_tips) {
        $form[$format->format]['#description'] = theme('filter_tips', _filter_tips($format->format, FALSE));
      }
      else {

        // Ensure expected filter_form() structure.
        // see http://drupal.org/node/344169
        $form[$format->format]['#description'] = '';
      }
    }
    if ($show_tips_link) {
      $extra = theme('better_formats_filter_tips_more_info');
      $form[] = array(
        '#value' => $extra,
      );
    }
    else {

      // Ensure expected filter_form() structure.
      // see http://drupal.org/node/344169
      $form[] = array(
        '#value' => '',
      );
    }
  }
  else {

    // Only one format available or hiding the form: use a hidden form item.
    $format = $formats[$default];
    $form[$format->format] = array(
      '#type' => 'value',
      '#value' => $format->format,
      '#parents' => $parents,
    );
    if ($show_tips) {
      $tips = _filter_tips($format->format, FALSE);
      $form['format']['guidelines'] = array(
        '#title' => t('Formatting guidelines'),
        '#value' => theme('filter_tips', $tips, FALSE),
      );
    }
    else {

      // Ensure expected filter_form() structure.
      // see http://drupal.org/node/344169
      $form['format']['guidelines'] = array(
        '#title' => t('Formatting guidelines'),
        '#value' => '',
      );
    }

    // Only show long tips link if there are guidelines to the format.
    if ($show_tips_link) {
      $extra = theme('better_formats_filter_tips_more_info');
      $form[] = array(
        '#value' => $extra,
      );
    }
    else {

      // Ensure expected filter_form() structure.
      // see http://drupal.org/node/344169
      $form[] = array(
        '#value' => '',
      );
    }
  }
  return $form;
}

/**
 * Theme function for fitler tips more info.
 *
 * This is copied from theme_fitler_tips_more_info() with small modifications.
 *
 * @return
 *  Filter tips more info HTML.
 */
function theme_better_formats_filter_tips_more_info() {
  $text = variable_get('better_formats_long_tips_link_text', '');
  if (module_exists('i18nstrings') && $text) {
    $text = i18nstrings('better_formats:tips_link', $text);
  }
  else {
    $text = $text ? $text : t('More information about formatting options');
  }
  return '<p>' . l($text, 'filter/tips') . '</p>';
}

Functions

Namesort descending Description
better_formats_check_roles Ensure that all roles have Better Format entries in the database.
better_formats_create_role Creates base format default entry for a newly created role.
better_formats_delete_role Deletes role format default entries for roles being deleted.
better_formats_elements Implementation of hook_elements().
better_formats_filter_form Better Formats version of filter_form().
better_formats_form_alter Implementation of hook_form_alter().
better_formats_get_current_format Returns the format for an existing node or comment.
better_formats_get_default_format Returns the default format for an new node or comment.
better_formats_help Implementation of hook_help().
better_formats_menu Implementation of hook_menu().
better_formats_new_role Creates base format default entry for a newly created role from role from.
better_formats_node_type Implementation of hook_node_type().
better_formats_node_type_form FAPI form to add to the content type edit form.
better_formats_node_type_form_submit Handles submission of the addition to the content type edit form.
better_formats_node_type_form_validate Handles validation of the addition to the content type edit form.
better_formats_perm Implementation of hook_perm().
better_formats_set_block_format Processes formats for core block form.
better_formats_set_comment_format Processes formats for core node comment form.
better_formats_set_node_format Processes formats for core node body fields.
better_formats_text_process Processes a CCK text elements.
better_formats_theme Implementation of hook_theme().
theme_better_formats_filter_tips_more_info Theme function for fitler tips more info.