You are here

linkicon.module in Link Icon 7

Same filename and directory in other branches
  1. 8 linkicon.module

A link field formatter to create icon classes based on predefined titles.

File

linkicon.module
View source
<?php

/**
 * @file
 * A link field formatter to create icon classes based on predefined titles.
 */

/**
 * Defines linkicon defaults.
 */
function linkicon_defaults() {
  return array(
    'linkicon_prefix' => 'icon',
    'linkicon_icon_class' => '',
    'linkicon_wrapper_class' => '',
    'linkicon_global_title' => '',
    'linkicon_size' => '',
    'linkicon_no_text' => '',
    'linkicon_position' => '',
    'linkicon_load' => 0,
    'linkicon_vertical' => 0,
    'linkicon_tooltip' => 0,
    'linkicon_maxlength' => '',
    'linkicon_style' => '',
    'linkicon_color' => '',
    'linkicon_font' => '',
    'linkicon_bundle' => '',
  );
}

/**
 * Returns simplified linkicon settings without `linkicon_` prefix.
 */
function linkicon_simplify_settings(array $configs = array()) {
  $settings = array();
  foreach (array_merge(linkicon_defaults(), $configs) as $key => $value) {
    $settings[str_replace('linkicon_', '', $key)] = $value;
  }
  return $settings;
}

/**
 * Implements hook_theme().
 */
function linkicon_theme($existing, $type, $theme, $path) {
  $common = array(
    'render element' => 'element',
    'file' => 'linkicon.theme.inc',
  );
  return array(
    'linkicon' => $common,
    'linkicon_item' => $common,
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function linkicon_field_formatter_info() {
  return array(
    'linkicon' => array(
      'label' => t('Link icon, based on title'),
      'field types' => array(
        'link_field',
        'text',
      ),
      'settings' => linkicon_defaults(),
    ),
  );
}

/**
 * Implements hook_field_formatter_prepare_view().
 */
function linkicon_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {

  // Unlike D8, we need to loop first to reach our settings.
  foreach ($items as $entity_id => $entity_items) {
    if (isset($instances[$entity_id]['settings']['title']) && $instances[$entity_id]['settings']['title'] == 'predefined' && isset($instances[$entity_id]['settings']['title_predefined']) && $instances[$entity_id]['settings']['title_predefined']) {
      $title_predefined = linkicon_extract_allowed_values($instances[$entity_id]['settings']['title_predefined']);
      $title_tooltip = linkicon_extract_allowed_values($instances[$entity_id]['settings']['title_predefined'], TRUE);
      foreach ($entity_items as $delta => $value) {
        $items[$entity_id][$delta]['display_title'] = $title_predefined[$value['title']];
        if (isset($title_tooltip[$value['title']])) {
          $items[$entity_id][$delta]['tooltip'] = $title_tooltip[$value['title']];
        }
      }
    }
  }
}

/**
 * Implements hook_field_formatter_view().
 */
function linkicon_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if (empty($items) || $display['type'] != 'linkicon') {
    return $element;
  }
  $path = drupal_get_path('module', 'linkicon');
  $field_type = $field['type'];
  $field_name = $instance['field_name'];
  list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
  $config = linkicon_simplify_settings($display['settings']);
  $prefix_class = check_plain($config['prefix']);
  $contents = array();
  foreach ($items as $delta => $item) {

    // The A tag attributes.
    $attributes = array();
    $attributes['class'][] = 'linkicon__item';

    // Linkicon requires both link text and URL available with proper
    // validation during input, no need extra checks.
    $icon_name = $field_type == 'link_field' ? $item['title'] : check_plain(strip_tags($item['value']));
    $display_title = isset($item['display_title']) ? $item['display_title'] : $icon_name;
    $tooltip = isset($item['tooltip']) ? $item['tooltip'] : $display_title;
    $icon_class = drupal_clean_css_identifier(drupal_strtolower($prefix_class . '-' . $icon_name));

    // This is similar as widget setting Static title, only available at
    // Display for more flexible options by view modes.
    if (!empty($config['global_title']) && empty($config['no_text'])) {
      $display_title = $config['global_title'];
    }

    // Sanitize $display_title before use since html is TRUE for the link.
    $item['html'] = TRUE;

    // Tokenized text is sanitized by default.
    $display_title = token_replace($display_title, array(
      $entity_type => $entity,
    ));
    $character_maxlength = isset($config['maxlength']) && $config['maxlength'] ? $config['maxlength'] : 60;
    $icon_element = array(
      '#theme' => 'linkicon_item',
      '#title' => truncate_utf8($display_title, $character_maxlength, TRUE, TRUE),
      '#icon_name' => check_plain($icon_name),
      '#settings' => $config,
    );
    $item['title'] = drupal_render($icon_element);

    // Link module stores classes as spaced string.
    if (!empty($item['attributes']['class'])) {
      $attributes['class'] = array_merge(array(
        $item['attributes']['class'],
      ), $attributes['class']);
    }

    // Unlike D8 link module, D7 link expect a spaced string, so feed it.
    $item['attributes']['class'] = implode(" ", $attributes['class']);

    // Our pure CSS3 tooltip depends on data-title.
    if ($config['tooltip']) {
      $tooltip = token_replace($tooltip, array(
        $entity_type => $entity,
      ));
      $item['attributes']['data-title'] = truncate_utf8($tooltip, $character_maxlength, TRUE, TRUE);
    }

    // We are done for the item, pass it over to link to do its job.
    $contents[$delta] = array(
      '#theme' => 'link_formatter_link_default',
      '#element' => $item,
      '#field' => $instance,
      '#display' => $display,
    );
  }

  // Build own wrapper for greater control.
  $config['id'] = drupal_clean_css_identifier("linkicon-{$entity_type}-{$bundle}-{$field_name}-{$id}");
  $element[0] = array(
    '#theme' => 'linkicon',
    '#items' => $contents,
    '#config' => $config,
  );

  // Attached our assets if so configured.
  if (!empty($config['load'])) {
    $element[0]['#attached']['css'][] = array(
      'data' => $path . '/css/linkicon.css',
    );
    if ($config['font'] && empty($config['bundle'])) {
      $element[0]['#attached']['css'][] = array(
        'data' => strip_tags($config['font']),
      );
    }
  }
  return $element;
}

/**
 * Extracts link title textarea values into array for link title select options.
 */
function linkicon_extract_allowed_values($values, $is_tooltip = FALSE) {
  $allowed_values = array();
  if ($values) {
    $list = explode("\n", strip_tags($values));
    foreach ($list as $value) {
      if (strpos($value, "|") !== FALSE) {
        list($key, $title, $tooltip) = array_pad(array_map('trim', explode("|", $value, 3)), 3, NULL);
        $allowed_values[$key] = $is_tooltip && !empty($tooltip) ? $tooltip : $title;
      }
      else {
        $allowed_values[$value] = $value;
      }
    }
  }
  return $allowed_values;
}

/**
 * Implements hook_element_info_alter().
 */
function linkicon_element_info_alter(&$types) {
  $types['link_field']['#process'][] = 'linkicon_field_process';
}

/**
 * Implements hook_field_info_alter().
 */
function linkicon_field_info_alter(&$info) {
  if (isset($info['link_field'])) {
    $info['link_field']['settings']['title_predefined'] = '';
    $info['link_field']['instance_settings']['title_predefined'] = '';
  }
}

/**
 * Overrides link_field_process() to use a select box.
 */
function linkicon_field_process($element, $form_state, $complete_form) {
  $instance = field_widget_instance($element, $form_state);
  $settings = $instance['settings'];
  if (isset($settings['title_predefined']) && $settings['title_predefined'] && $settings['title'] == 'predefined') {
    $element['title']['#type'] = 'select';
    $element['title']['#options'] = linkicon_extract_allowed_values($settings['title_predefined']);
    $element['title']['#empty_option'] = t('- Select -');
    $element['title']['#default_value'] = isset($element['#value']['title']) ? $element['#value']['title'] : '';

    // Remove irrelevant description.
    unset($element['title']['#description']);
    $element['#element_validate'] = array(
      '_linkicon_element_validate_link_title',
    );
  }
  return $element;
}

/**
 * Validate predefined link title.
 *
 * Since Link title is not required, we make sure that it is not empty if the
 * URL field is not. In the opposite, link.module does validation.
 *
 * @todo: error field receives no error class.
 */
function _linkicon_element_validate_link_title($element, &$form_state, $form) {
  if (empty($element['#value']['title']) && !empty($element['#value']['url'])) {
    form_set_error($element['#value']['title'], t('Title must be filled in if URL is provided.'));
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function linkicon_form_field_ui_display_overview_form_alter(&$form, &$form_state) {
  $path = drupal_get_path('module', 'linkicon');

  // Needed for preview.
  $form['#attached']['css'][] = $path . '/css/linkicon.css';
  $form['#attached']['css'][] = $path . '/css/linkicon.field_ui.css';
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function linkicon_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  form_load_include($form_state, 'inc', 'linkicon', 'includes/linkicon.admin');
  $elements = _linkicon_field_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
  return $elements;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function linkicon_field_formatter_settings_summary($field, $instance, $view_mode) {
  module_load_include('inc', 'linkicon', 'includes/linkicon.admin');
  $summary = _linkicon_field_formatter_settings_summary($field, $instance, $view_mode);
  return implode('<br />', $summary);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function linkicon_form_field_ui_field_edit_form_alter(&$form, $form_state) {
  form_load_include($form_state, 'inc', 'linkicon', 'includes/linkicon.admin');
  _linkicon_form_field_ui_field_edit_form_alter($form, $form_state);
}

/**
 * Alters the existing link field widget settings form elements.
 */
function linkicon_field_widget_settings_form_alter(&$form, $settings) {
  form_load_include($form_state, 'inc', 'linkicon', 'includes/linkicon.admin');
  _linkicon_field_widget_settings_form_alter($form, $settings);
}

/**
 * Validate path to icon font CSS file.
 */
function _linkicon_element_validate_font_path($element, &$form_state, $form) {
  if (!empty($element['#value']) && !is_file($element['#value'])) {
    form_set_error($element['#name'], t("<strong>@css_font_path</strong> doesn't exist.", array(
      '@css_font_path' => $element['#value'],
    )));
  }
}

/**
 * Implements hook_help().
 */
function linkicon_help($path, $arg) {
  if ($path == 'admin/help#linkicon') {
    $output = file_get_contents(dirname(__FILE__) . '/README.md');
    return function_exists('_filter_markdown') ? _filter_markdown($output, NULL) : '<pre>' . $output . '</pre>';
  }
  return '';
}