Commit ce557bdd authored by osman's avatar osman

Initial commit.

parents
# Lazy-load
This is a simple Drupal module to lazy-load all inline images and/or iframes defined by content authors in entity content, usually the text-format-enabled version of textarea fields. i.e. Node and Block body content.
The module currently depends on the [bLazy][1] image script.
There is another contributed module utilizing its namesake, [Blazy][2]. Make sure to check it out, especially if you need more advanced features and support for many features out of the box.
This module focuses on the only area Blazy module lacks of; **inline-images** and **inline-iframes**.
You can still use this module tandem with it, though that is not a requirement.
## Requirements
* **[Libraries API][4]** module
* **bLazy v1.8.2** script as a library item:
[Download bLazy][3] from https://github.com/dinbror/blazy
1) Extract the downloaded file, 2) rename *blazy-master* directory to *blazy*, 3) copy the folder into one of the following places that *Libraries API* module supports, `sites/all/libraries` (or site-specific libraries folder):
i.e.: `sites/all/libraries/blazy/blazy.min.js`
## Installation
Install the module as usual. More information can be found at https://www.drupal.org/docs/7/extend/installing-modules
## Usage
This modules makes a new text filter available for the text-formats: *Lazy-load*
Enable the *Lazy-load* filter for the desired text-formats. i.e. *Full HTML* or *Filtered HTML*
Check out the module configuration at `admin/config/content/lazy`. The default settings should work for most developers. Incase they are not, change the settings to suit your needs and submit the form.
This configuration is used globally for all the text-formats having *Lazy-load* filter enabled.
## Use Case
If you have numerous images and/or iframes in your content, it could become a challenge to update that content to make compatible for lazy-loading. In most cases those updates needs to be handled manually, because most of the time if not all, the body content (HTML) doesn't follow a pattern to update them programmatically.
This is the main reason I created this module, to avoid a need for altering body content manually while making them easy to lazy-load.
**The *Lazy-load* filter doesn't make any changes to existing content.** It only rewrites the `<img>` and/or `<iframe>` tags in already rendered output to have them compatible for bLazy script to lazy-load. Since the filtered output is cached, there should not be any changes in performance.
[1]: http://dinbror.dk/blazy/
[2]: https://www.drupal.org/project/blazy
[3]: https://github.com/dinbror/blazy/archive/master.zip
[4]: https://www.drupal.org/project/libraries
<?php
/**
* @file
* Configuration form for Lazy-load.
*/
/**
* Form callback for the Lazy-load configuration form.
*/
function lazy_configuration_form($form, $form_state) {
$defaults = variable_get('lazy_filter_defaults');
$form['info'] = array(
'#type' => 'item',
'#title' => t('Global settings'),
'#description' => t('The configuration options available on this form applies to all <a href="!path">text-formats</a> that have %filter filter enabled.', array(
'!path' => url('admin/config/content/formats'),
'%filter' => 'Lazy-load',
)),
);
$form['lazy_filter_alter_tag'] = array(
'#type' => 'select',
'#title' => t('Apply to'),
'#options' => array(
'img iframe' => t('Images & Iframes'),
'img' => t('Images only'),
'iframe' => t('IFrames only'),
),
'#default_value' => variable_get('lazy_filter_alter_tag', $defaults['lazy_filter_alter_tag']),
'#description' => t('Select the elements to be lazy-loaded.'),
);
$form['lazy_filter_loadInvisible'] = array(
'#type' => 'checkbox',
'#title' => t('loadInvisible'),
'#description' => t('If checked loads invisible (hidden) elements. Default is %val', array('%val' => ($defaults['lazy_filter_loadInvisible']) ? 'checked' : 'unchecked')),
'#default_value' => variable_get('lazy_filter_loadInvisible', $defaults['lazy_filter_loadInvisible']),
'#return_value' => TRUE,
);
$form['lazy_filter_offset'] = array(
'#type' => module_exists('elements') ? 'numberfield' : 'textfield',
'#title' => t('offset'),
'#description' => t('The offset controls how early you want the elements to be loaded before they’re visible. Default is %val, so %val pixel before an element is visible it’ll start loading.', array('%val' => $defaults['lazy_filter_offset'])),
'#default_value' => variable_get('lazy_filter_offset', $defaults['lazy_filter_offset']),
);
$form['lazy_filter_saveViewportOffsetDelay'] = array(
'#type' => module_exists('elements') ? 'numberfield' : 'textfield',
'#title' => t('saveViewportOffsetDelay'),
'#description' => t('Delay for how often it should call the saveViewportOffset function on resize. Default is %val', array('%val' => $defaults['lazy_filter_saveViewportOffsetDelay'])),
'#default_value' => variable_get('lazy_filter_saveViewportOffsetDelay', $defaults['lazy_filter_saveViewportOffsetDelay']),
);
$form['lazy_filter_validateDelay'] = array(
'#type' => module_exists('elements') ? 'numberfield' : 'textfield',
'#title' => t('validateDelay'),
'#description' => t('Delay for how often it should call the validate function on scroll/resize. Default is %val', array('%val' => $defaults['lazy_filter_validateDelay'])),
'#default_value' => variable_get('lazy_filter_validateDelay', $defaults['lazy_filter_validateDelay']),
);
$form['lazy_filter_selector'] = array(
'#type' => 'textfield',
'#title' => t('Selector class'),
'#description' => t('Element selector for elements that should lazy load. Do not include a leading period. Default is %val', array('%val' => $defaults['lazy_filter_selector'])),
'#default_value' => variable_get('lazy_filter_selector', $defaults['lazy_filter_selector']),
);
$form['lazy_filter_skipClass'] = array(
'#type' => 'textfield',
'#title' => t('skipClass'),
'#description' => t('Elements having this class name will be ignored. Default is %val', array('%val' => $defaults['lazy_filter_skipClass'])),
'#default_value' => variable_get('lazy_filter_skipClass', $defaults['lazy_filter_skipClass']),
);
$form['lazy_filter_errorClass'] = array(
'#type' => 'textfield',
'#title' => t('errorClass'),
'#description' => t('The classname an element will get if something goes wrong. Default is %val', array('%val' => $defaults['lazy_filter_errorClass'])),
'#default_value' => variable_get('lazy_filter_errorClass', $defaults['lazy_filter_errorClass']),
);
$form['lazy_filter_successClass'] = array(
'#type' => 'textfield',
'#title' => t('successClass'),
'#description' => t('The classname an element will get when loaded. Default is %val', array('%val' => $defaults['lazy_filter_successClass'])),
'#default_value' => variable_get('lazy_filter_successClass', $defaults['lazy_filter_successClass']),
);
$form['lazy_filter_src'] = array(
'#type' => 'textfield',
'#title' => t('src'),
'#description' => t('Attribute where the original element source will be assigned. Do not change this unless attribute is used for other purposes. Default is %val', array('%val' => $defaults['lazy_filter_src'])),
'#default_value' => variable_get('lazy_filter_src', $defaults['lazy_filter_src']),
);
$form['lazy_filter_placeholderSrc'] = array(
'#type' => 'textfield',
'#title' => t('Placeholder image URL'),
'#description' => t('Default is %val', array('%val' => $defaults['lazy_filter_placeholderSrc'])),
'#default_value' => variable_get('lazy_filter_placeholderSrc', $defaults['lazy_filter_placeholderSrc']),
);
return system_settings_form($form);
}
name = Lazy-load
description = "This module integrates bLazy script to lazy load inline images and/or iframes via input-filters."
core = 7.x
dependencies[] = drupal:filter
dependencies[] = libraries
package = "Input filters"
configure = admin/config/content/lazy
<?php
/**
* @file
* Install, update, and uninstall functions for the Lazy-load module.
*/
/**
* Implements hook_install().
*/
function lazy_install() {
$defaults = array(
'lazy_filter_errorClass' => 'b-error',
'lazy_filter_loadInvisible' => FALSE,
'lazy_filter_offset' => 100,
'lazy_filter_saveViewportOffsetDelay' => 50,
'lazy_filter_selector' => 'b-lazy',
'lazy_filter_alter_tag' => 'img iframe',
'lazy_filter_skipClass' => 'no-b-lazy',
'lazy_filter_src' => 'data-src',
'lazy_filter_successClass' => 'b-loaded',
'lazy_filter_validateDelay' => 25,
'lazy_filter_placeholderSrc' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
);
variable_set('lazy_filter_defaults', $defaults);
foreach ($defaults as $key => $value) {
variable_set($key, $value);
}
}
/**
* Implement hook_enable()
*/
function lazy_enable() {
$options = array(
'!config' => url('admin/config/content/lazy'),
'%filter' => 'Lazy-load',
'!path' => url('admin/config/content/formats'),
);
$message = t('<a href="!config">Lazy module</a> is installed. Make sure to enable %filter filter in desired <a href="!path">text-formats</a>.', $options);
drupal_set_message($message, 'warning');
}
/**
* Implements hook_uninstall().
*/
function lazy_uninstall() {
variable_del('lazy_filter_defaults');
variable_del('lazy_filter_errorClass');
variable_del('lazy_filter_loadInvisible');
variable_del('lazy_filter_offset');
variable_del('lazy_filter_saveViewportOffsetDelay');
variable_del('lazy_filter_selector');
variable_del('lazy_filter_alter_tag');
variable_del('lazy_filter_skipClass');
variable_del('lazy_filter_src');
variable_del('lazy_filter_successClass');
variable_del('lazy_filter_validateDelay');
variable_del('lazy_filter_placeholderSrc');
}
/**
* Implements hook_requirements().
*/
function lazy_requirements($phase) {
$requirements = array();
$t = get_t();
if ($phase == 'runtime') {
$blazy = libraries_detect('blazy');
$requirements['blazy'] = array(
'title' => $t('bLazy'),
);
if ($blazy['installed']) {
$requirements['blazy']['value'] = $blazy['version'];
$requirements['blazy']['severity'] = REQUIREMENT_OK;
}
else {
$requirements['blazy']['value'] = $blazy['error'];
$requirements['blazy']['description'] = $blazy['error message'];
$requirements['blazy']['severity'] = REQUIREMENT_ERROR;
}
}
return $requirements;
}
(function ($) {
Drupal.behaviors.lazy = {
attach: function (context, settings) {
// @see http://dinbror.dk/blog/blazy/?ref=example-page#Options
var options = settings.lazy.bLazy ? settings.lazy.bLazy : {};
var bLazy = new Blazy(options);
}
};
})(jQuery);
<?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_filter_info().
*/
function lazy_filter_info() {
$filters['lazy_filter'] = array(
'title' => t('Lazy-load'),
'description' => t('Lazy-load inline-images and/or iframes'),
'default settings' => _filter_lazy_defaults(),
'process callback' => '_filter_lazy_process',
'cache' => TRUE,
'tips callback' => '_filter_lazy_tips',
'weight' => 20,
);
return $filters;
}
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 = explode(' ', 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');
// dpm($opt_skipClass, '$opt_skipClass');
// dpm($opt_selector, '$opt_selector');
// dpm($opt_tags, '$opt_tags');
// dpm($opt_src, '$opt_src');
// dpm($opt_placeholderSrc, '$opt_placeholderSrc');
$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 = (strlen($classes) > 0) ? explode(' ', $classes) : [];
if (!in_array($opt_skipClass, $classes)) {
$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) {
switch (variable_get('lazy_filter_alter_tag', 'img iframe')) {
case 'img iframe':
return t('Both %img and %iframe elements are lazy-loaded.', array('%img' => '<img>', '%iframe' => '<iframe>'));
break;
case 'img':
return t('%img elements are lazy-loaded.', array('%img' => '<img>', '%iframe' => '<iframe>'));
break;
case 'iframe':
return t('%iframe elements are lazy-loaded.', array('%img' => '<img>', '%iframe' => '<iframe>'));
break;
}
}
/**
* Implements hook_page_build().
*/
function lazy_page_build(&$page) {
$path = drupal_get_path('module', 'lazy');
$page['page_bottom']['lazy'] = array(
'#attached' => array(),
);
$attached = &$page['page_bottom']['lazy']['#attached'];
// Default settings.
// @see http://dinbror.dk/blog/blazy/?ref=example-page#Options
$settings = array(
'errorClass' => variable_get('lazy_filter_errorClass'),
'loadInvisible' => variable_get('lazy_filter_loadInvisible'),
'offset' => intval(variable_get('lazy_filter_offset')),
'saveViewportOffsetDelay' => intval(variable_get('lazy_filter_saveViewportOffsetDelay')),
'selector' => '.' . variable_get('lazy_filter_selector'),
'src' => variable_get('lazy_filter_src'),
'successClass' => variable_get('lazy_filter_successClass'),
'validateDelay' => intval(variable_get('lazy_filter_validateDelay')),
);
$attached['js'][] = array(
'data' => array('lazy' => array('bLazy' => $settings)),
'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;
}
$file_content = file_get_contents($file);
$json = json_decode($file_content, true);
return $json['version'];
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment