lazy.module in Lazy-load 7
Same filename and directory in other branches
Module file for Lazy-load.
File
lazy.moduleView source
<?php
/**
* @file
* Module file for Lazy-load.
*/
/**
* Implements hook_menu().
*/
function lazy_menu() {
return array(
'admin/config/content/lazy' => array(
'title' => 'Lazy-load',
'description' => 'Configure how images and iframes are lazy-loaded.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'lazy_configuration_form',
),
'file' => 'lazy.admin.inc',
'access arguments' => array(
'administer filters',
),
),
);
}
/**
* Implements hook_init().
*/
function lazy_init() {
$library = lazy_is_library_installed();
}
/**
* Implements hook_help().
*/
function lazy_help($path, $arg) {
switch ($path) {
case 'admin/help#lazy':
$filepath = dirname(__FILE__) . '/README.md';
if (file_exists($filepath)) {
$readme = file_get_contents($filepath);
}
if (!isset($readme)) {
return NULL;
}
if (module_exists('markdown')) {
$filters = module_invoke('markdown', 'filter_info');
$info = $filters['filter_markdown'];
if (function_exists($info['process callback'])) {
$output = $info['process callback']($readme, NULL);
}
else {
$output = '<pre>' . $readme . '</pre>';
}
}
else {
$output = '<pre>' . $readme . '</pre>';
}
return $output;
}
}
/**
* Implements hook_filter_info().
*/
function lazy_filter_info() {
$filters['lazy_filter'] = array(
'title' => t('Lazy-load images and IFRAMEs via bLazy'),
'default settings' => _filter_lazy_defaults(),
'process callback' => '_filter_lazy_process',
'cache' => TRUE,
'tips callback' => '_filter_lazy_tips',
'weight' => 20,
);
return $filters;
}
/**
* Callback to return configuration defaults.
*/
function _filter_lazy_defaults() {
return array(
'lazy_filter_errorClass' => variable_get('lazy_filter_errorClass'),
'lazy_filter_loadInvisible' => variable_get('lazy_filter_loadInvisible'),
'lazy_filter_offset' => variable_get('lazy_filter_offset'),
'lazy_filter_saveViewportOffsetDelay' => variable_get('lazy_filter_saveViewportOffsetDelay'),
'lazy_filter_selector' => variable_get('lazy_filter_selector'),
'lazy_filter_alter_tag' => variable_get('lazy_filter_alter_tag'),
'lazy_filter_skipClass' => variable_get('lazy_filter_skipClass'),
'lazy_filter_src' => variable_get('lazy_filter_src'),
'lazy_filter_successClass' => variable_get('lazy_filter_successClass'),
'lazy_filter_validateDelay' => variable_get('lazy_filter_validateDelay'),
'lazy_filter_placeholderSrc' => variable_get('lazy_filter_placeholderSrc'),
);
}
/**
* Implements callback_filter_process().
*/
function _filter_lazy_process($text, $filter) {
$opt_skipClass = variable_get('lazy_filter_skipClass');
$opt_selector = ltrim(variable_get('lazy_filter_selector'), '.');
$opt_tags = variable_get('lazy_filter_alter_tag');
$opt_src = variable_get('lazy_filter_src') !== 'src' ? variable_get('lazy_filter_src') : 'data-filterlazy-src';
$opt_placeholderSrc = variable_get('lazy_filter_placeholderSrc');
$library_installed = variable_get('lazy_library_installed');
if ($library_installed && lazy_is_path_allowed()) {
$html_dom = filter_dom_load($text);
foreach ($opt_tags as $tag) {
$matches = $html_dom
->getElementsByTagName($tag);
foreach ($matches as $element) {
$classes = $element
->getAttribute('class');
$classes = $classes != '' ? explode(' ', $classes) : array();
if (!in_array($opt_skipClass, $classes, TRUE)) {
if (variable_get('lazy_prefer_native') && !$element
->hasAttribute('loading')) {
// Required attribute for enabling native lazy-loading.
$element
->setAttribute('loading', 'lazy');
}
elseif (!$element
->hasAttribute($opt_src)) {
$classes[] = $opt_selector;
$element
->setAttribute('class', implode(' ', $classes));
$src = $element
->getAttribute('src');
$element
->removeAttribute('src');
$element
->setAttribute($opt_src, $src);
$element
->setAttribute('src', $opt_placeholderSrc);
}
}
}
}
$text = filter_dom_serialize($html_dom);
}
return trim($text);
}
/**
* Implements callback_filter_tips().
*/
function _filter_lazy_tips($filter, $format, $long = FALSE) {
$tags = variable_get('lazy_filter_alter_tag');
$tags = implode(' ', $tags);
$tags = trim(str_replace(array(
'0',
), '', $tags));
switch ($tags) {
case 'img iframe':
return t('Both %img and %iframe elements are lazy-loaded.', array(
'%img' => '<img>',
'%iframe' => '<iframe>',
));
case 'img':
return t('%img elements are lazy-loaded.', array(
'%img' => '<img>',
'%iframe' => '<iframe>',
));
case 'iframe':
return t('%iframe elements are lazy-loaded.', array(
'%img' => '<img>',
'%iframe' => '<iframe>',
));
}
}
/**
* Is filter enabled for any of text-formats.
*/
function lazy_is_filter_enabled() {
$options = array(
':module' => 'lazy',
':name' => 'lazy_filter',
':status' => 1,
);
$enabled_formats = db_query('SELECT f.format, f.settings FROM {filter} f WHERE f.module = :module AND f.name = :name AND f.status = :status', $options)
->fetchAllKeyed();
return (bool) count($enabled_formats);
}
/**
* Is any of the image fields using the `Lazy-load image` formatter?
*/
function lazy_is_field_enabled() {
$lazy_enabled_fields = array();
$field_map = field_info_field_map();
foreach ($field_map as $field_name => $field) {
if ($field['type'] === 'image') {
foreach ($field['bundles'] as $entity_type => $bundle) {
$field_instance = field_info_instance($entity_type, $field_name, $bundle[0]);
foreach ($field_instance['display'] as $display_name => $display) {
if ($field_instance['display'][$display_name]['type'] === 'lazy') {
$lazy_enabled_fields[] = implode('-', array(
$field_instance['entity_type'],
$field_instance['field_name'],
$display_name,
));
}
}
}
}
}
return (bool) count($lazy_enabled_fields);
}
/**
* Is path allowed?
*
* @return bool
* Returns true if current path is not listed in disabled pages.
*/
function lazy_is_path_allowed() {
$pages = drupal_strtolower(variable_get('lazy_disabled_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).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $pages);
}
return !$page_match;
}
/**
* Is Blazy library installed.
*/
function lazy_is_library_installed() {
$blazy = libraries_detect('blazy');
$blazy_installed = variable_get('lazy_library_installed');
if ($blazy['installed'] !== $blazy_installed) {
variable_set('lazy_library_installed', $blazy['installed']);
}
return $blazy['installed'];
}
/**
* Implements hook_page_build().
*/
function lazy_page_build(&$page) {
if (!variable_get('lazy_prefer_native')) {
$path = drupal_get_path('module', 'lazy');
$page['page_bottom']['lazy'] = array(
'#attached' => array(),
);
$attached =& $page['page_bottom']['lazy']['#attached'];
$attached['js'][] = array(
'data' => array(
'lazy' => array(
'errorClass' => variable_get('lazy_filter_errorClass'),
'loadInvisible' => variable_get('lazy_filter_loadInvisible'),
'offset' => (int) variable_get('lazy_filter_offset'),
'saveViewportOffsetDelay' => (int) variable_get('lazy_filter_saveViewportOffsetDelay'),
'selector' => '.' . variable_get('lazy_filter_selector'),
'src' => variable_get('lazy_filter_src'),
'successClass' => variable_get('lazy_filter_successClass'),
'validateDelay' => (int) variable_get('lazy_filter_validateDelay'),
),
),
'type' => 'setting',
);
$attached['libraries_load'][] = array(
'blazy',
);
$attached['js'][$path . '/lazy.js'] = array(
'every_page' => TRUE,
);
}
}
/**
* Implements hook_libraries_info().
*/
function lazy_libraries_info() {
$libraries['blazy'] = array(
'name' => 'bLazy',
'vendor url' => 'https://github.com/dinbror/blazy/',
'download url' => 'https://github.com/dinbror/blazy/archive/master.zip',
'version callback' => 'lazy_library_get_version',
'version arguments' => array(
'file' => 'package.json',
),
'files' => array(
'js' => array(
'blazy.min.js' => array(
'group' => JS_LIBRARY,
'every_page' => TRUE,
),
),
),
'variants' => array(
'source' => array(
'files' => array(
'js' => array(
'blazy.js' => array(
'group' => JS_LIBRARY,
'every_page' => TRUE,
),
),
),
),
),
);
return $libraries;
}
/**
* Callback function to return version from provided JSON file.
*/
function lazy_library_get_version($library, $options) {
$file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file'];
if (empty($options['file']) || !file_exists($file)) {
return 'n/a';
}
$file_content = file_get_contents($file);
$json = json_decode($file_content, TRUE);
return $json['version'];
}
/**
* Implements hook_field_formatter_info().
*/
function lazy_field_formatter_info() {
return array(
'lazy' => array(
'label' => t('Lazy-load image'),
'field types' => array(
'image',
),
'settings' => array(
'image_style' => '',
'image_link' => '',
),
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function lazy_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$image_styles = image_style_options(FALSE, PASS_THROUGH);
$element['image_style'] = array(
'#title' => t('Image style'),
'#type' => 'select',
'#default_value' => $settings['image_style'],
'#empty_option' => t('None (original image)'),
'#options' => $image_styles,
);
$link_types = array(
'content' => t('Content'),
'file' => t('File'),
);
$element['image_link'] = array(
'#title' => t('Link image to'),
'#type' => 'select',
'#default_value' => $settings['image_link'],
'#empty_option' => t('Nothing'),
'#options' => $link_types,
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function lazy_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = array();
$image_styles = image_style_options(FALSE, PASS_THROUGH);
// Unset possible 'No defined styles' option.
unset($image_styles['']);
// Styles could be lost because of enabled/disabled modules that defines
// their styles in code.
if (isset($image_styles[$settings['image_style']])) {
$summary[] = t('Image style: @style', array(
'@style' => $image_styles[$settings['image_style']],
));
}
else {
$summary[] = t('Original image');
}
$link_types = array(
'content' => t('Linked to content'),
'file' => t('Linked to file'),
);
// Display this setting only if image is linked.
if (isset($link_types[$settings['image_link']])) {
$summary[] = $link_types[$settings['image_link']];
}
return implode('<br />', $summary);
}
/**
* Implements hook_field_formatter_view().
*/
function lazy_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
// Check if the formatter involves a link.
if ($display['settings']['image_link'] == 'content') {
$uri = entity_uri($entity_type, $entity);
}
elseif ($display['settings']['image_link'] == 'file') {
$link_file = TRUE;
}
// Check if the formatter is set to lazy-load.
// if ($display['type'] === 'lazy') {}
foreach ($items as $delta => $item) {
if (isset($link_file)) {
$uri = array(
'path' => file_create_url($item['uri']),
'options' => array(),
);
}
$element[$delta] = array(
'#theme' => 'lazy_image_formatter',
'#item' => $item,
'#image_style' => $display['settings']['image_style'],
'#path' => isset($uri) ? $uri : '',
);
}
return $element;
}
/**
* Implements hook_theme().
*/
function lazy_theme() {
return array(
'lazy_image' => array(
'variables' => array(
'style_name' => NULL,
'path' => NULL,
'width' => NULL,
'height' => NULL,
'alt' => '',
'title' => NULL,
'attributes' => array(),
),
),
'lazy_image_formatter' => array(
'variables' => array(
'item' => NULL,
'path' => NULL,
'image_style' => NULL,
),
),
);
}
/**
* 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.
*/
function theme_lazy_image($variables) {
$opt_skipClass = variable_get('lazy_filter_skipClass');
$opt_selector = ltrim(variable_get('lazy_filter_selector'), '.');
$opt_src = variable_get('lazy_filter_src') !== 'src' ? variable_get('lazy_filter_src') : 'data-filterlazy-src';
$opt_placeholderSrc = variable_get('lazy_filter_placeholderSrc');
if ($variables['style_name']) {
// Determine the dimensions of the styled image.
$dimensions = array(
'width' => $variables['width'],
'height' => $variables['height'],
);
image_style_transform_dimensions($variables['style_name'], $dimensions);
$variables['width'] = $dimensions['width'];
$variables['height'] = $dimensions['height'];
// Determine the URL for the styled image.
$variables['path'] = image_style_url($variables['style_name'], $variables['path']);
}
// Skip Blazy rendering if...
//
// library is not available OR
// viewing a page listed in disabled pages
$class = isset($variables['attributes']['class']) ? $variables['attributes']['class'] : array();
if (!variable_get('lazy_library_installed') || !lazy_is_path_allowed() || in_array($opt_skipClass, $class, TRUE)) {
return theme('image', $variables);
}
$attributes = $variables['attributes'];
if (variable_get('lazy_prefer_native')) {
// Required attribute for enabling native lazy-loading.
$attributes['loading'] = 'lazy';
$attributes['src'] = file_create_url($variables['path']);
}
else {
$attributes['src'] = $opt_placeholderSrc;
$attributes[$opt_src] = file_create_url($variables['path']);
$attributes['class'][] = $opt_selector;
}
foreach (array(
'width',
'height',
'alt',
'title',
) as $key) {
if (isset($variables[$key])) {
$attributes[$key] = $variables[$key];
}
}
return '<img' . drupal_attributes($attributes) . ' />';
}
/**
* Returns HTML for an image field formatter.
*
* @param $variables
* An associative array containing:
* - item: Associative array of image data, which may include "uri", "alt",
* "width", "height", "title" and "attributes".
* - image_style: An optional image style.
* - path: An array containing the link 'path' and link 'options'.
*
* @ingroup themeable
*/
function theme_lazy_image_formatter($variables) {
$item = $variables['item'];
$image = array(
'path' => $item['uri'],
);
if (array_key_exists('alt', $item)) {
$image['alt'] = $item['alt'];
}
if (isset($item['attributes'])) {
$image['attributes'] = $item['attributes'];
}
if (isset($item['width'], $item['height'])) {
$image['width'] = $item['width'];
$image['height'] = $item['height'];
}
// Do not output an empty 'title' attribute.
if (isset($item['title']) && drupal_strlen($item['title']) > 0) {
$image['title'] = $item['title'];
}
if ($variables['image_style']) {
$image['style_name'] = $variables['image_style'];
}
$output = theme('lazy_image', $image);
// The link path and link options are both optional, but for the options to be
// processed, the link path must at least be an empty string.
if (isset($variables['path']['path'])) {
$path = $variables['path']['path'];
$options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
// When displaying an image inside a link, the html option must be TRUE.
$options['html'] = TRUE;
$output = l($output, $path, $options);
}
return $output;
}