You are here

lazyloader.module in Image Lazyloader 7.2

Same filename and directory in other branches
  1. 8 lazyloader.module
  2. 7 lazyloader.module

Lazyloader Module

@author: Daniel Honrade http://drupal.org/user/351112

Note: Obviously, this will not work unless the javascript is on.

File

lazyloader.module
View source
<?php

/**
 * @file
 * Lazyloader Module
 *
 * @author: Daniel Honrade http://drupal.org/user/351112
 *
 * Note: Obviously, this will not work unless the javascript is on.
 *
 */
define("LAZYLOADER_ENABLED", TRUE);
define("LAZYLOADER_DISTANCE", 250);
define("LAZYLOADER_ICON", 7);
define("LAZYLOADER_CUSTOM_ICON_PATH", '');
define("LAZYLOADER_PLACEHOLDER", '');
define("LAZYLOADER_PATHS", "media/*/format-form\nadmin/*\nnode/add/*\nnode/*/edit");
define("LAZYLOADER_EXCLUDED_FILENAMES", '');
define("LAZYLOADER_PAGE_EXCLUDE_OPTION", 'exclude');
define("LAZYLOADER_CONTENT_TYPE_EXCLUDE_OPTION", 'exclude');
define("LAZYLOADER_LOAD_IMAGE_DELAY", 50);
define("LAZYLOADER_DEBOUNCE", TRUE);
define("LAZYLOADER_UNLOAD", FALSE);
define("LAZYLOADER_DEBUGGING", FALSE);

/**
 * Implements hook_menu().
 *
 */
function lazyloader_menu() {
  $items = array();
  $items['admin/config/media/lazyloader'] = array(
    'title' => 'Image Lazyloader',
    'page callback' => 'drupal_get_form',
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer lazyloader',
    ),
    'page arguments' => array(
      'lazyloader_admin_configure',
      NULL,
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'lazyloader.admin.inc',
    'description' => 'Configure Lazyloader',
  );
  $items['admin/config/media/lazyloader/configure'] = array(
    'title' => 'Configure',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'description' => 'Configure Lazyloader settings',
  );
  $items['admin/config/media/lazyloader/exclude'] = array(
    'title' => 'Exclude options',
    'page callback' => 'drupal_get_form',
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer lazyloader',
    ),
    'page arguments' => array(
      'lazyloader_admin_exclude',
      NULL,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'lazyloader.admin.inc',
    'description' => 'Configure Lazyloader inclusion/exclusion settings',
  );
  return $items;
}

/**
 * Implements hook_perm().
 *
 */
function lazyloader_permission() {
  return array(
    'administer lazyloader' => array(
      'title' => t('Administer Lazyloader'),
      'description' => t('Perform administration tasks for Lazyloader.'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function lazyloader_theme($existing, $type, $theme, $path) {
  $info = array();
  if (isset($existing['image']['variables'])) {
    $info['lazyloader_image'] = array(
      'variables' => $existing['image']['variables'],
      'function' => 'theme_lazyloader_image',
    );
  }
  return $info;
}

/**
 * Implements hook_theme_registry_alter().
 */
function lazyloader_theme_registry_alter(&$theme_registry) {
  if (variable_get('lazyloader_enabled', LAZYLOADER_ENABLED)) {
    $theme_registry['image']['function'] = 'theme_lazyloader_image';
  }
  return $theme_registry;
}

/**
 * Returns HTML for an image.
 *
 * @param $variables
 *   An associative array containing:
 *   - path: Either the path of the image file (relative to base_path()) or a
 *     full URL.
 *   - width: The width of the image (if known).
 *   - height: The height of the image (if known).
 *   - alt: The alternative text for text-based browsers. HTML 4 and XHTML 1.0
 *     always require an alt attribute. The HTML 5 draft allows the alt
 *     attribute to be omitted in some cases. Therefore, this variable defaults
 *     to an empty string, but can be set to NULL for the attribute to be
 *     omitted. Usually, neither omission nor an empty string satisfies
 *     accessibility requirements, so it is strongly encouraged for code calling
 *     theme('image') to pass a meaningful value for this variable.
 *     - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
 *     - http://www.w3.org/TR/xhtml1/dtds.html
 *     - http://dev.w3.org/html5/spec/Overview.html#alt
 *   - title: The title text is displayed when the image is hovered in some
 *     popular browsers.
 *   - attributes: Associative array of attributes to be placed in the img tag.
 * @return string
 *  HTML for a lazyloaded image
 */
function theme_lazyloader_image($variables) {
  $theme_image = theme_image($variables);

  // Use theme_image if lazyloader is not enabled.
  if ($variables['theme_hook_original'] !== 'lazyloader_image') {
    if (!_lazy_loader_enabled() || _lazyloader_excluded_by_filename($variables) || _lazyloader_excluded_by_image_style($variables)) {
      return $theme_image;
    }
  }
  static $rdwimages_enabled, $image_placeholder_src;
  $attributes = $variables['attributes'];

  // Set the data source and placeholder image.
  $attributes['data-echo'] = file_create_url($variables['path']);
  $attributes['data-icon'] = _lazyloader_icon_path();
  if (!isset($image_placeholder_src)) {

    // Path to dummy placeholder image, to be replaced by actual image.
    $image_placeholder = trim(variable_get('lazyloader_placeholder', LAZYLOADER_PLACEHOLDER));
    $image_placeholder_src = $image_placeholder ? base_path() . $image_placeholder : file_create_url(drupal_get_path('module', 'lazyloader') . '/image_placeholder.gif');
  }

  // Integrate with Responsive Webdesign module.
  if (!isset($rdwimages_enabled)) {
    global $_rwdimages_set;
    $rdwimages_enabled = module_exists('rdwimages') && $_rwdimages_set['enabled'];
  }
  if ($rdwimages_enabled) {
    $attributes['class'] = isset($attributes['class']) ? $attributes['class'] + array(
      'rwdimage',
    ) : array(
      'rdwimage',
    );
  }

  // Add noscript as a fallback.
  $noscript = "<noscript>{$theme_image}</noscript>";
  $arguments = array(
    'path' => $image_placeholder_src,
    'attributes' => $attributes,
  );
  foreach (array(
    'width',
    'height',
    'alt',
    'title',
  ) as $key) {
    if (isset($variables[$key])) {
      $arguments[$key] = $variables[$key];
    }
  }

  // Get the icon width and height for use in the javascript.
  $icon_path = substr(_lazyloader_icon_path(), strlen(base_path()));

  // The path will be empty if the user configured the option to show no icon.
  list($icon_width, $icon_height) = !empty($icon_path) ? getimagesize($icon_path) : array(
    0,
    0,
  );
  $settings['lazyloader'] = array(
    'throttle' => variable_get('lazyloader_load_image_delay', LAZYLOADER_LOAD_IMAGE_DELAY),
    'offset' => variable_get('lazyloader_distance', LAZYLOADER_DISTANCE),
    'debounce' => variable_get('lazyloader_debounce', LAZYLOADER_DEBOUNCE),
    'unload' => variable_get('lazyloader_unload', LAZYLOADER_UNLOAD),
    'icon' => _lazyloader_icon_path(),
    'offsetX' => $icon_width > 0 ? floor($icon_width / 2) : 0,
    'offsetY' => $icon_height > 0 ? floor($icon_height / 2) : 0,
  );
  drupal_add_js($settings, array(
    'type' => 'setting',
  ));

  // Load the Echo library.
  $variant = variable_get('lazyloader_debugging', LAZYLOADER_DEBUGGING) ? NULL : 'minified';
  libraries_load_files(libraries_load('echo', $variant));

  // Render the image.
  return theme_image($arguments) . $noscript;
}

/**
 * Helper function to determine whether the lazyloader is enabled in a page.
 *
 * @return bool
 */
function _lazy_loader_enabled() {

  // Bail if lazyloader is disabled entirely.
  if (!variable_get('lazyloader_enabled', LAZYLOADER_ENABLED)) {
    return FALSE;
  }

  // This method gets called quite often, so let's cache all the heavy stuff.
  static $enabled;
  if (isset($enabled)) {
    return $enabled;
  }

  // Convert path to lowercase. This allows comparison of the same path
  // with different case. Ex: /Page, /page, /PAGE.
  $pages = drupal_strtolower(variable_get('lazyloader_paths', LAZYLOADER_PATHS));

  // Convert the Drupal path to lowercase
  $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));

  // Compare the lowercase internal and lowercase path alias (if any).
  $path_match = drupal_match_path($path, $pages);
  if ($path != $_GET['q']) {
    $path_match = $path_match || drupal_match_path($_GET['q'], $pages);
  }
  $path_exclude = variable_get('lazyloader_page_exclude_option', LAZYLOADER_PAGE_EXCLUDE_OPTION);
  $enabled = $path_exclude === 'exclude' ? !$path_match : $path_match;

  // Only check content types if Lazyloader is not disabled already.
  if ($enabled && ($node = menu_get_object())) {
    $types = _lazyloader_filter_selected_values(variable_get('lazyloader_content_types', array()));
    if (!empty($types)) {
      $type = node_type_get_type($node);
      $type_match = in_array($type->type, $types);
      $enabled = $type_match;
    }
  }
  return $enabled;
}

/**
 * Helper function to determine if an image should be excluded by filename.
 */
function _lazyloader_excluded_by_filename($variables) {
  $excluded_files = preg_split("/\\r\\n|\\r|\\n/", variable_get('lazyloader_excluded_filenames', LAZYLOADER_EXCLUDED_FILENAMES));
  $parts = explode('/', $variables['path']);
  $parts = explode('?', array_pop($parts));
  $filename = array_shift($parts);
  return (bool) in_array($filename, $excluded_files);
}

/**
 * Helper function to determine if an image should be excluded by image style.
 */
function _lazyloader_excluded_by_image_style($variables) {
  $excluded_styles = _lazyloader_filter_selected_values(variable_get('lazyloader_image_styles', array()));

  // If no image styles are selected we have nothing to exclude.
  if (empty($excluded_styles)) {
    return FALSE;
  }
  $styles = implode('|', array_keys(image_styles()));

  // Make sure the image is actually a derived image.
  if (preg_match('/styles\\/[' . $styles . ']/', $variables['path'])) {
    return (bool) (!in_array($variables['style_name'], $excluded_styles));
  }
  else {

    // Not a derived image, nothing to do here.
    return FALSE;
  }
}

/**
 * Helper function to get the loading icon.
 */
function _lazyloader_icon_path() {
  $icon = variable_get('lazyloader_icon', LAZYLOADER_ICON);
  $custom_icon_path = variable_get('lazyloader_custom_icon_path', LAZYLOADER_CUSTOM_ICON_PATH);
  if (!empty($icon)) {
    $base = base_path();
    if ($icon == 9) {
      return "{$base}{$custom_icon_path}";
    }
    else {
      $path = drupal_get_path('module', 'lazyloader');
      return "{$base}{$path}/loader/loader-{$icon}.gif";
    }
  }
  return '';
}

/**
 * Implements hook_libraries_info().
 */
function lazyloader_libraries_info() {
  $libraries['echo'] = array(
    'name' => 'Echo',
    'vendor url' => 'http://toddmotto.com/labs/echo/',
    'download url' => 'https://github.com/toddmotto/echo/archive/master.zip',
    'path' => 'dist',
    'files' => array(
      'js' => array(
        'echo.js',
      ),
    ),
    'integration files' => array(
      'lazyloader' => array(
        'js' => array(
          'lazyloader.js',
        ),
      ),
    ),
    'variants' => array(
      'minified' => array(
        'files' => array(
          'js' => array(
            'echo.min.js',
          ),
        ),
      ),
    ),
  );
  return $libraries;
}

/**
 * Filters an array of selected checkbox values.
 */
function _lazyloader_filter_selected_values($values) {

  // Filter out deselected values.
  foreach ($values as $key => $value) {
    if (!$value) {
      unset($values[$key]);
    }
  }
  return $values;
}

Functions

Namesort descending Description
lazyloader_libraries_info Implements hook_libraries_info().
lazyloader_menu Implements hook_menu().
lazyloader_permission Implements hook_perm().
lazyloader_theme Implements hook_theme().
lazyloader_theme_registry_alter Implements hook_theme_registry_alter().
theme_lazyloader_image Returns HTML for an image.
_lazyloader_excluded_by_filename Helper function to determine if an image should be excluded by filename.
_lazyloader_excluded_by_image_style Helper function to determine if an image should be excluded by image style.
_lazyloader_filter_selected_values Filters an array of selected checkbox values.
_lazyloader_icon_path Helper function to get the loading icon.
_lazy_loader_enabled Helper function to determine whether the lazyloader is enabled in a page.

Constants