View source
<?php
namespace Drupal\lazy\Plugin\Filter;
use Drupal\Component\Utility\Html;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
use Drupal\lazy\Lazy;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LazyFilter extends FilterBase implements ContainerFactoryPluginInterface {
protected $configFactory;
protected $lazyLoad;
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, Lazy $lazy_load) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->configFactory = $config_factory;
$this->lazyLoad = $lazy_load;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('config.factory'), $container
->get('lazy'));
}
public function settingsForm(array $form, FormStateInterface $form_state) {
$form['info'] = [
'#markup' => $this
->t('Lazy-load filter can be enabled for images and iframes.'),
];
$form['image'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable for images (%img tags)', [
'%img' => '<img>',
]),
"#description" => $this
->t('This option only applies to inline-images. If <em>Embed media</em> filter is enabled, the images embedded from media library would use the the selected view mode settings.'),
'#default_value' => $this->settings['image'],
'#return_value' => TRUE,
];
$form['iframe'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable for iframes (%iframe tags)', [
'%iframe' => '<iframe>',
]),
'#default_value' => $this->settings['iframe'],
'#return_value' => TRUE,
];
return $form;
}
public function setConfiguration(array $configuration) {
parent::setConfiguration($configuration);
if ($configuration['status'] && !empty($configuration['settings']) && $configuration['settings']['image'] == FALSE && $configuration['settings']['iframe'] == FALSE) {
$this->status = FALSE;
$this
->messenger()
->addWarning($this
->t('Lazy-loading is not enabled. The filter configuration needs to be enabled for either of the IMG or IFRAME tags.'));
}
return $this;
}
public function process($text, $langcode) : FilterProcessResult {
$result = new FilterProcessResult($text);
if ($this->status && ($this->settings['image'] || $this->settings['iframe']) && $this->lazyLoad
->isPathAllowed() && ($lazy_settings = $this->configFactory
->get('lazy.settings')
->get())) {
$html_dom = Html::load($text);
$xpath = new \DOMXPath($html_dom);
foreach ($xpath
->query('//img | //iframe') as $node) {
$classes = empty($node
->getAttribute('class')) ? [] : explode(' ', $node
->getAttribute('class'));
$parent_classes = empty($node->parentNode
->getAttribute('class')) ? [] : explode(' ', $node->parentNode
->getAttribute('class'));
$src = $node
->getAttribute('src');
$enabled_tags = [
'img' => $this->settings['image'],
'iframe' => $this->settings['iframe'],
];
foreach ($enabled_tags as $tag => $status) {
if ($node->tagName === $tag && $enabled_tags[$node->tagName]) {
if (in_array($lazy_settings['skipClass'], $classes, TRUE) || in_array($lazy_settings['skipClass'], $parent_classes, TRUE)) {
continue;
}
if ($lazy_settings['preferNative']) {
$node
->setAttribute('loading', 'lazy');
}
else {
$classes[] = $lazy_settings['lazysizes']['lazyClass'];
$classes = array_unique($classes);
$node
->setAttribute('class', implode(' ', $classes));
$opt_src = $lazy_settings['lazysizes']['srcAttr'] !== 'src' ? $lazy_settings['lazysizes']['srcAttr'] : 'data-filterlazy-src';
$node
->removeAttribute('src');
$node
->setAttribute($opt_src, $src);
if ($lazy_settings['placeholderSrc']) {
$node
->setAttribute('src', $lazy_settings['placeholderSrc']);
}
}
}
}
}
$result
->setProcessedText(Html::serialize($html_dom));
}
return $result;
}
public function tips($long = FALSE) {
$tags = [
'img' => $this->settings['image'],
'iframe' => $this->settings['iframe'],
];
$options = [
'%img' => '<img>',
'%iframe' => '<iframe>',
];
$skip_class = $this->configFactory
->get('lazy.settings')
->get('skipClass');
$skip_help = $this
->t('If you want certain elements skip lazy-loading, add <code>%skip_class</code> class name.', [
'%skip_class' => $skip_class,
]);
if (!empty($tags)) {
if ($tags['img'] && $tags['iframe']) {
return $this
->t('Lazy-loading is enabled for both %img and %iframe tags.', $options) . ' ' . $skip_help;
}
if ($tags['img']) {
return $this
->t('Lazy-loading is enabled for %img tags.', $options) . ' ' . $skip_help;
}
if ($tags['iframe']) {
return $this
->t('Lazy-loading is enabled for %iframe tags.', $options) . ' ' . $skip_help;
}
}
return $this
->t('Lazy-loading is not enabled.');
}
}