Commit bb4c1f87 authored by osman's avatar osman

* Image field display formatters has an option now to enable lazy-loading per field, per view-mode.

* Minor tweaks and improvements.
parent c4be3ce6
......@@ -6,6 +6,7 @@
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
/**
* Implements hook_help().
......@@ -13,7 +14,7 @@ use Drupal\Core\Routing\RouteMatchInterface;
function lazy_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.lazy':
$readme = file_get_contents(dirname(__FILE__) . '/README.md');
$readme = file_get_contents(__DIR__ . '/README.md');
if (\Drupal::moduleHandler()->moduleExists('markdown')) {
// Use the Markdown filter to render the README.
......@@ -23,24 +24,51 @@ function lazy_help($route_name, RouteMatchInterface $route_match) {
$filter = $filter_manager->createInstance('markdown', $config);
return $filter->process($readme, 'en');
}
else {
return '<pre>' . $readme . '</pre>';
}
return '<pre>' . $readme . '</pre>';
}
return NULL;
}
/**
* Implements hook_preprocess_image().
* Implements template_preprocess_field().
*/
function lazy_preprocess_image(&$variables) {
$config = \Drupal::config('lazy.settings');
function lazy_preprocess_field(&$variables) {
$element = $variables['element'];
if ($element['#field_type'] === 'image') {
$entity = $element['#object'];
$entity_type = $entity->getEntityTypeId();
$bundle = $entity->bundle();
$view_mode = $element['#view_mode'];
$field_name = $element['#field_name'];
$render_display = EntityViewDisplay::collectRenderDisplay($entity, $view_mode);
$field_display = $render_display->getComponent($field_name);
$image_fields = [];
if (isset($field_display['third_party_settings']['lazy']) && $field_display['third_party_settings']['lazy']['lazy_image']) {
foreach ($variables['items'] as $key => $item) {
$variables['items'][$key]['content']['#item_attributes']['data-lazy-load-fields'] = 'image';
$view_mode = ($view_mode === 'full') ? 'default' : $view_mode;
$image_fields["$entity_type--$bundle--$view_mode--$field_name"] = TRUE;
}
}
if ($config->get('image_fields')) {
$variables['attributes'][$config->get('src')] = $variables['attributes']['src'];
$variables['attributes']['src'] = $config->get('placeholderSrc');
$variables['attributes']['class'][] = $config->get('selector');
lazy_settings_update($image_fields);
}
}
/**
* Implements template_preprocess_image().
*/
function lazy_preprocess_image(&$variables) {
if (array_key_exists('data-lazy-load-fields', $variables['attributes'])) {
unset($variables['attributes']['data-lazy-load-fields']);
$config = \Drupal::config('lazy.settings')->get();
$variables['attributes'][$config['src']] = $variables['attributes']['src'];
$variables['attributes']['src'] = $config['placeholderSrc'];
$variables['attributes']['class'][] = $config['selector'];
}
}
......@@ -48,20 +76,19 @@ function lazy_preprocess_image(&$variables) {
* Implements hook_page_attachments().
*/
function lazy_page_attachments(array &$attachments) {
$enabled = lazy_is_enabled();
if ($enabled) {
$config = \Drupal::config('lazy.settings');
$config = lazy_is_enabled();
if ($config) {
$options = [
'errorClass' => $config->get('errorClass'),
'loadInvisible' => boolval($config->get('loadInvisible')),
'offset' => intval($config->get('offset')),
'saveViewportOffsetDelay' => $config->get('saveViewportOffsetDelay'),
'selector' => '.' . $config->get('selector'),
'skipClass' => $config->get('skipClass'),
'src' => $config->get('src'),
'successClass' => $config->get('successClass'),
'validateDelay' => $config->get('validateDelay'),
'placeholderSrc' => $config->get('placeholderSrc'),
'errorClass' => $config['errorClass'],
'loadInvisible' => (bool) $config['loadInvisible'],
'offset' => (int) $config['offset'],
'saveViewportOffsetDelay' => (int) $config['saveViewportOffsetDelay'],
'selector' => '.' . $config['selector'],
'skipClass' => $config['skipClass'],
'src' => $config['src'],
'successClass' => $config['successClass'],
'validateDelay' => $config['validateDelay'],
'placeholderSrc' => $config['placeholderSrc'],
];
$attachments['#attached']['library'][] = 'lazy/lazy';
$attachments['#attached']['drupalSettings']['lazy'] = $options;
......@@ -70,6 +97,8 @@ function lazy_page_attachments(array &$attachments) {
/**
* Callback function to check whether lazy is enabled in any text-formats.
*
* @return mixed Lazy configuration object if enabled, false otherwise.
*/
function lazy_is_enabled() {
$status = [];
......@@ -90,9 +119,103 @@ function lazy_is_enabled() {
}
$config = \Drupal::config('lazy.settings');
if ($config->get('image_fields')) {
$status['fields'] = TRUE;
$image_fields = $config->get('image_fields');
if (count($image_fields)) {
foreach ($image_fields as $field_name => $bool_value) {
if ($bool_value) {
$status[$field_name] = TRUE;
}
}
}
return count($status) ? $config->get() : FALSE;
}
/**
* Implements hook_field_formatter_third_party_settings_form().
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* @param $view_mode
* @param $form
*
* @return array
*/
function lazy_field_formatter_third_party_settings_form($plugin, $field_definition, $view_mode, $form, $form_state) {
$element = [];
if ($plugin->getPluginId() === 'image') {
$element['lazy_image'] = [
'#type' => 'checkbox',
'#title' => t('Enable lazy-loading'),
'#default_value' => $plugin
->getThirdPartySetting('lazy', 'lazy_image', FALSE),
];
}
return $element;
}
/**
* @param $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
* @param $form_id
*/
function lazy_form_entity_view_display_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
$image_fields = [];
if ($fields = $form_state->getValue('fields')) {
foreach ($fields as $field_name => $field) {
if (
($field['type'] === 'image')
&& isset($field['settings_edit_form'])
&& isset($field['settings_edit_form']['third_party_settings'])
&& isset($field['settings_edit_form']['third_party_settings']['lazy'])
&& isset($field['settings_edit_form']['third_party_settings']['lazy']['lazy_image'])
) {
$route_match = \Drupal::service('current_route_match');
$view_mode = $route_match->getParameter('view_mode_name');
$image_fields["$entity_type--$bundle--$view_mode--$field_name"] = (bool) $field['settings_edit_form']['third_party_settings']['lazy']['lazy_image'];
}
}
}
return count($status) ? TRUE : FALSE;
lazy_settings_update($image_fields);
}
/**
* Implements hook_field_formatter_settings_summary_alter().
*
* @param $summary
* @param $context
*/
function lazy_field_formatter_settings_summary_alter(&$summary, $context) {
if ($context['formatter']->getPluginId() === 'image') {
if ($context['formatter']->getThirdPartySetting('lazy', 'lazy_image', FALSE)) {
$summary[] = t('Lazy-loading enabled');
}
}
}
/**
* Update `lazy.settings.image_fields` value with currently enabled options.
*
* @param array $image_fields
*/
function lazy_settings_update(array $image_fields) {
$current_image_fields = \Drupal::config('lazy.settings')->get('image_fields');
if (empty($current_image_fields)) {
$current_image_fields = [];
}
$fields = array_merge($current_image_fields, $image_fields);
foreach ($fields as $field_name => $bool_value) {
if (!$bool_value) {
unset($fields[$field_name]);
}
}
\Drupal::service('config.factory')->getEditable('lazy.settings')
->set('image_fields', $fields)
->save();
}
\ No newline at end of file
......@@ -31,15 +31,15 @@ class LazyForm extends ConfigFormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('lazy.settings');
$filter_enabled = lazy_is_enabled();
$description = $this->t('The %filter filter must be enabled for at least one <a href=":path">text-format</a>.', [
$description = $this->t('The inline images and iframes will be lazy-loaded for the selected text-formats');
$desc_extra = $this->t('The %filter filter must be enabled for at least one <a href=":path">text-format</a>.', [
':path' => Url::fromRoute('filter.admin_overview')->toString(),
'%filter' => 'Lazy-load',
]);
if (
!boolval($config->get('alter_tag')['img'])
&& !boolval($config->get('alter_tag')['iframe'])
&& !boolval($config->get('image_fields'))
!(bool) $config->get('alter_tag')['img']
&& !(bool) $config->get('alter_tag')['iframe']
) {
drupal_set_message($this->t('Lazy-load is currently disabled. Update configuration in global settings to enable it.'), 'warning');
}
......@@ -58,15 +58,17 @@ class LazyForm extends ConfigFormBase {
'iframe' => $this->t('Enable for iframes (%iframe tags)', ['%iframe' => '<iframe>']),
],
'#default_value' => $config->get('alter_tag'),
'#description' => $filter_enabled ? '' : $description,
'#description' => $description . ($filter_enabled ? '' : $desc_extra),
'#disabled' => !$filter_enabled,
];
$form['settings']['image_fields'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable on image fields attached to fieldable entities. For example, content-types, blocks, paragraphs.'),
'#default_value' => $config->get('image_fields'),
'#title' => '<del>' . $this->t('Enable on image fields attached to fieldable entities. For example, content-types, blocks, paragraphs.') . '</del>',
'#description' => $this->t('This option is now controlled separately for each image field, in their display settings.'),
'#default_value' => 0,
'#return_value' => TRUE,
'#disabled' => TRUE,
];
$form['settings']['placeholderSrc'] = [
......@@ -171,16 +173,15 @@ class LazyForm extends ConfigFormBase {
$this->config('lazy.settings')
->set('alter_tag', $form_state->getValue('alter_tag'))
->set('errorClass', $form_state->getValue('errorClass'))
->set('loadInvisible', boolval($form_state->getValue('loadInvisible')))
->set('offset', intval($form_state->getValue('offset')))
->set('saveViewportOffsetDelay', $form_state->getValue('saveViewportOffsetDelay'))
->set('loadInvisible', (bool) $form_state->getValue('loadInvisible'))
->set('offset', (int) $form_state->getValue('offset'))
->set('saveViewportOffsetDelay', (int) $form_state->getValue('saveViewportOffsetDelay'))
->set('selector', $form_state->getValue('selector'))
->set('skipClass', $form_state->getValue('skipClass'))
->set('src', $form_state->getValue('src'))
->set('successClass', $form_state->getValue('successClass'))
->set('validateDelay', $form_state->getValue('validateDelay'))
->set('placeholderSrc', $form_state->getValue('placeholderSrc'))
->set('image_fields', $form_state->getValue('image_fields'))
->save();
parent::submitForm($form, $form_state);
}
......
......@@ -23,35 +23,45 @@ class LazyFilter extends FilterBase {
* {@inheritdoc}
*/
public function process($text, $langcode) {
$config = \Drupal::config('lazy.settings');
$opt_skipClass = $config->get('skipClass');
$opt_selector = ltrim($config->get('selector'), '.');
$opt_tags = $config->get('alter_tag');
$opt_src = ($config->get('src') !== 'src') ? $config->get('src') : 'data-filterlazy-src';
$opt_placeholderSrc = $config->get('placeholderSrc');
$config = \Drupal::config('lazy.settings')->get();
$opt_skipClass = $config['skipClass'];
$opt_selector = ltrim($config['selector'], '.');
$opt_tags = $config['alter_tag'];
$opt_src = ($config['src'] !== 'src') ? $config['src'] : 'data-filterlazy-src';
$opt_placeholderSrc = $config['placeholderSrc'];
$result = new FilterProcessResult($text);
$html_dom = Html::load($text);
foreach ($opt_tags as $tag) {
foreach ($opt_tags as $tag => $status) {
$matches = $html_dom->getElementsByTagName($tag);
foreach ($matches as $element) {
$classes = $element->getAttribute('class');
$classes = (strlen($classes) > 0) ? explode(' ', $classes) : [];
$parent_classes = $element->parentNode->getAttribute('class');
$parent_classes = (strlen($parent_classes) > 0) ? explode(' ', $parent_classes) : [];
if (!in_array($opt_skipClass, $classes) && !in_array($opt_skipClass, $parent_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);
if (empty($opt_tags[$tag])) {
// If the `tag` is not enabled remove the bLazy selector class.
if (($key = array_search($opt_selector, $classes)) !== false) {
unset($classes[$key]);
$element->setAttribute('class', implode(' ', $classes));
if (empty($classes)) {
$element->removeAttribute('class');
}
}
}
else {
// `tag` is enabled. Make sure skipClass is not set before proceeding.
if (!in_array($opt_skipClass, $classes) && !in_array($opt_skipClass, $parent_classes)) {
$classes[] = $opt_selector;
$classes = array_unique($classes);
$element->setAttribute('class', implode(' ', $classes));
$src = $element->getAttribute('src');
$element->removeAttribute('src');
$element->setAttribute($opt_src, $src);
$element->setAttribute('src', $opt_placeholderSrc);
}
}
}
}
......
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