You are here

resp_img.module in Responsive images and styles 8

Same filename and directory in other branches
  1. 7.2 resp_img.module
  2. 7 resp_img.module

File

resp_img.module
View source
<?php

define('RESP_IMG_CLASS', 'resp-img-picture');
define('RESP_IMG_SEPARATOR', '__');
define('RESP_IMG_SOURCE_TYPE_THEME', 'theme');
define('RESP_IMG_SOURCE_TYPE_MODULE', 'module');
define('RESP_IMG_SOURCE_TYPE_CUSTOM', 'custom');
define('RESP_IMG_GROUP', 'group');

/**
 * Add javascript for older browser support
 */
function resp_img_add_js() {
  static $added = FALSE;
  if (!$added) {
    $added = TRUE;
    drupal_add_js(drupal_get_path('module', 'resp_img') . '/picturefill/matchmedia.js', array(
      'type' => 'file',
      'weight' => -10,
      'group' => JS_DEFAULT,
    ));
    drupal_add_js(drupal_get_path('module', 'resp_img') . '/picturefill/picturefill.js', array(
      'type' => 'file',
      'weight' => -10,
      'group' => JS_DEFAULT,
    ));
    drupal_add_css(drupal_get_path('module', 'resp_img') . '/css/resp_img.css', array(
      'type' => 'file',
      'weight' => -10,
    ));
  }
}

/**
 * Implements hook_theme().
 */
function resp_img_theme() {
  return array(
    'picture' => array(
      'variables' => array(
        'style_name' => NULL,
        'path' => NULL,
        'width' => NULL,
        'height' => NULL,
        'alt' => '',
        'title' => NULL,
        'attributes' => array(),
        'breakpoints' => array(),
      ),
    ),
    'picture_formatter' => array(
      'variables' => array(
        'item' => NULL,
        'path' => NULL,
        'image_style' => NULL,
        'breakpoints' => array(),
      ),
    ),
  );
}

/**
 * Implements hook_preprocess_field().
 */
function resp_img_field_attach_view_alter(&$output, $context) {
  foreach (element_children($output) as $field_name) {
    $element =& $output[$field_name];
    if ($element['#field_type'] == 'image') {
      $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
      if (isset($instance['display'][$context['view_mode']])) {
        $settings = $instance['display'][$context['view_mode']]['settings'];
      }
      else {
        $settings = $instance['display']['default']['settings'];
      }
      $breakpoint_styles = array();
      if (isset($settings['resp_img_responsive']) && $settings['resp_img_responsive']) {
        foreach ($settings['resp_img'] as $breakpoint_name => $multipliers) {
          if (is_array($multipliers)) {
            foreach ($multipliers as $multiplier => $image_style) {
              if (!empty($settings['resp_img'][$breakpoint_name][$multiplier])) {
                if (!isset($breakpoint_styles[$breakpoint_name])) {
                  $breakpoint_styles[$breakpoint_name] = array();
                }
                $breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
              }
            }
          }
        }
      }

      // Change the formatter so it uses ours.
      $element['#formatter'] = 'picture';

      // Change the formatter on all items as well.
      $num_fields = count($element['#items']);
      if (!empty($breakpoint_styles)) {
        for ($delta = 0; $delta < $num_fields; $delta++) {
          $element[$delta]['#theme'] = 'picture_formatter';
          $element[$delta]['#breakpoints'] = $breakpoint_styles;
        }
      }
      else {
        for ($delta = 0; $delta < $num_fields; $delta++) {
          $element[$delta]['#theme'] = 'picture_formatter';
          $element[$delta]['#breakpoints'] = 'all';
        }
      }
    }
  }
}
function theme_picture_formatter($variables) {
  if (!isset($variables['breakpoints']) || empty($variables['breakpoints'])) {
    return theme('image_formatter', $variables);
  }
  resp_img_add_js();
  $item = $variables['item'];

  // Do not output an empty 'title' attribute.
  if (isset($item['title']) && drupal_strlen($item['title']) == 0) {
    unset($item['title']);
  }
  $item['style_name'] = $variables['image_style'];
  $item['breakpoints'] = $variables['breakpoints'];
  $output = theme('picture', $item);
  if (isset($variables['path']['path'])) {
    $path = $variables['path']['path'];
    $options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
    $options['html'] = TRUE;
    $output = l($output, $path, $options);
  }
  return $output;
}

/**
 * Theme a picture element.
 */
function theme_picture($variables) {
  if (!isset($variables['attributes'])) {
    $variables['attributes'] = array();
  }
  if (!isset($variables['attributes']['class'])) {
    $variables['attributes']['class'] = array();
  }
  $variables['attributes']['class'][] = RESP_IMG_CLASS;

  // Make sure that width and height are proper values
  if (isset($variables['width']) && empty($variables['width'])) {
    unset($variables['width']);
    unset($variables['height']);
  }
  elseif (isset($variables['height']) && empty($variables['height'])) {
    unset($variables['width']);
    unset($variables['height']);
  }
  $images = array();
  $output = array();

  // User didn't map any breakpoints, use breakpoints
  if (!is_array($variables['breakpoints'])) {
    $default_breakpoint = resp_img_breakpoint_default();
    if ($default_breakpoint && strpos($variables['style_name'], $default_breakpoint)) {
      $breakpoints = breakpoints_breakpoint_load_all_active();
      $image_styles = image_styles();

      // loop over all breakpoints
      foreach ($breakpoints as $breakpoint) {

        // detect the default one
        if ($breakpoint->breakpoint == $default_breakpoint) {
          $images[] = array(
            'image' => theme_image_style($variables),
          );
        }
        else {
          $new_image = $variables;
          $new_image['style_name'] = str_replace($default_breakpoint, $breakpoint->breakpoint, $variables['style_name']);
          if (array_key_exists($new_image['style_name'], $image_styles)) {
            $images[] = array(
              'image' => theme_image_style($new_image),
              'media' => $breakpoint->breakpoint,
            );
          }
        }
      }
    }
  }
  else {

    // default image.
    $img = theme('image_style', $variables);
    $img = str_replace('<img', '', $img);
    $img = str_replace('/>', '', $img);
    $images[] = array(
      'image' => $img,
    );

    // all breakpoints and multipliers.
    foreach ($variables['breakpoints'] as $breakpoint_name => $multipliers) {
      $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint_name);
      if ($breakpoint) {
        $new_images = array();
        foreach ($multipliers as $multiplier => $image_style) {
          $new_image = $variables;
          $new_image['style_name'] = $image_style;
          $new_image['#multiplier'] = $multiplier;
          $new_images[] = $new_image;
        }
        $img = theme('image_style', $new_images[0]);
        $img = str_replace('<img', '', $img);
        $img = str_replace('/>', '', $img);
        if (count($new_images) == 1) {
          $images[] = array(
            'image' => $img,
            'media' => $breakpoint->breakpoint,
          );
        }
        else {
          $srcset = array();
          foreach ($new_images as $new_image) {
            $srcset[] = image_style_url($new_image['style_name'], $new_image['uri']) . ' ' . $new_image['#multiplier'];
          }
          $img = preg_replace('/src="[^"]*"/', '', $img);
          $images[] = array(
            'srcset' => implode(', ', $srcset),
            'media' => $breakpoint->breakpoint,
            'image' => $img,
          );
        }
      }
    }
  }
  if (!empty($images)) {
    $output[] = '<picture alt="' . check_plain($variables['alt']) . '" title="' . check_plain($variables['title']) . '">';

    // add variants to the output
    foreach ($images as $image) {
      if (isset($image['media']) && !empty($image['media'])) {
        if (!isset($image['srcset'])) {
          $output[] = '<!-- <source media="' . $image['media'] . '" ' . $image['image'] . '> -->';
          $output[] = '<source media="' . $image['media'] . '" ' . $image['image'] . '>';
        }
        else {
          $output[] = '<!-- <source class="' . RESP_IMG_CLASS . '" media="' . $image['media'] . '" srcset="' . $image['srcset'] . '" ' . $image['image'] . '> -->';
          $output[] = '<source class="' . RESP_IMG_CLASS . '" media="' . $image['media'] . '" srcset="' . $image['srcset'] . '" ' . $image['image'] . '>';
        }
      }
      else {
        $output[] = '<!-- <source ' . $image['image'] . '> -->';
        $output[] = '<source ' . $image['image'] . '>';
      }
    }

    // output the default image as fallback
    // $output .= '<img src="' . image_style_url($variables['style_name'], $variables['uri']) . '" alt="' . check_plain($variables['alt']) . '" />';
    $output[] = '<noscript><img ' . $images[0]['image'] . '/></noscript>';
    $output[] = '</picture>';
    return implode("\n", $output);
  }
}

/**
 * Implements hook_field_formatter_info_alter().
 */
function resp_img_field_formatter_info_alter(&$info) {
  foreach ($info as $formatter_key => &$formatter) {
    if ($formatter_key == 'image') {
      if (!isset($formatter['settings']) || !is_array($formatter['settings'])) {
        $formatter['settings'] = array();
      }
      $formatter['settings'] += array(
        'resp_img_responsive' => FALSE,
        'resp_img' => array(),
      );
    }
  }
}

/**
 * Implements hook_field_formatter_settings_form_alter().
 */
function resp_img_field_formatter_settings_form_alter(&$element, &$form_state, $context) {
  if (isset($context['field']['type']) && $context['field']['type'] === 'image') {
    $settings = $context['instance']['display'][$context['view_mode']]['settings'];
    $theme_breakpoints = breakpoints_breakpoint_load_all_active();
    if (!empty($theme_breakpoints)) {
      $element['resp_img_responsive'] = array(
        '#type' => 'checkbox',
        '#title' => t('Go responsive'),
        '#default_value' => isset($settings['resp_img_responsive']) ? $settings['resp_img_responsive'] : FALSE,
        // @todo: needs better wording
        '#description' => t('If you enable this, you can select an image style for each defined breakpoint/breakpoint.<br />
          The image style at the top will be used as default/fallback.<br />
          If you leave all dropdowns empty the logic will try to use the default breakpoint.'),
      );
      $element['resp_img'] = array(
        '#type' => 'container',
        '#states' => array(
          'invisible' => array(
            'input[name="fields[field_image][settings_edit_form][settings][resp_img_responsive]"]' => array(
              'checked' => FALSE,
            ),
          ),
        ),
      );
      $image_styles = image_style_options(TRUE);
      foreach ($theme_breakpoints as $breakpoint_name => $breakpoint) {
        $label = $breakpoint->name . ' [' . $breakpoint->breakpoint . ']';
        $element['resp_img'][$breakpoint_name]['1x'] = array(
          '#title' => check_plain($label),
          '#type' => 'select',
          '#options' => $image_styles,
          '#default_value' => isset($settings['resp_img'][$breakpoint_name]['1x']) ? $settings['resp_img'][$breakpoint_name]['1x'] : '',
        );
        if (isset($breakpoint->multipliers) && !empty($breakpoint->multipliers)) {
          foreach ($breakpoint->multipliers as $multiplier => $value) {
            if ($multiplier != '1x' && $value) {
              $element['resp_img'][$breakpoint_name][$multiplier] = array(
                '#title' => check_plain($multiplier . ' ' . $label),
                '#type' => 'select',
                '#options' => $image_styles,
                '#default_value' => isset($settings['resp_img'][$breakpoint_name][$multiplier]) ? $settings['resp_img'][$breakpoint_name][$multiplier] : '',
              );
            }
          }
        }
      }
    }
  }
}

/**
 * Implements hook_field_formatter_settings_summary_alter().
 */
function resp_img_field_formatter_settings_summary_alter(&$summary, $context) {
  if (isset($context['field']['type']) && $context['field']['type'] === 'image') {
    $settings = $context['instance']['display'][$context['view_mode']]['settings'];
    if (isset($settings['resp_img_responsive']) && $settings['resp_img_responsive']) {
      $summary .= '<br />Responsive mode activated';
    }
  }
}