137748cd8SNickeau<?php 237748cd8SNickeau/** 337748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 437748cd8SNickeau * 537748cd8SNickeau * This source code is licensed under the GPL license found in the 637748cd8SNickeau * COPYING file in the root directory of this source tree. 737748cd8SNickeau * 837748cd8SNickeau * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 937748cd8SNickeau * @author ComboStrap <support@combostrap.com> 1037748cd8SNickeau * 1137748cd8SNickeau */ 1237748cd8SNickeau 1337748cd8SNickeaunamespace ComboStrap; 1437748cd8SNickeau 1537748cd8SNickeau/** 1637748cd8SNickeau * This one support background loading 1737748cd8SNickeau * https://github.com/ApoorvSaxena/lozad.js 1837748cd8SNickeau * 1937748cd8SNickeau * 2037748cd8SNickeau * TODO: implement no script pattern ? the https://github.com/aFarkas/lazysizes#the-noscript-pattern 2137748cd8SNickeau * 2237748cd8SNickeau */ 2337748cd8SNickeauclass LazyLoad 2437748cd8SNickeau{ 2537748cd8SNickeau 2637748cd8SNickeau const CONF_LAZY_LOADING_PLACEHOLDER_COLOR = "lazyLoadingPlaceholderColor"; 2737748cd8SNickeau 2837748cd8SNickeau /** 2937748cd8SNickeau * Lozad was choosen because 3037748cd8SNickeau * it was easier to add svg injection 3137748cd8SNickeau * it supports background image 3237748cd8SNickeau * it's most used (JsDelivr stats) 3337748cd8SNickeau */ 3437748cd8SNickeau const ACTIVE = self::LOZAD_ID; 3537748cd8SNickeau 3637748cd8SNickeau /** 3737748cd8SNickeau * The id of the lazy loaders 3837748cd8SNickeau */ 3937748cd8SNickeau const LAZY_SIDE_ID = "lazy-sizes"; 4037748cd8SNickeau const LOZAD_ID = "lozad"; 4137748cd8SNickeau 4237748cd8SNickeau 4337748cd8SNickeau const CANONICAL = "lazy"; 4437748cd8SNickeau const DEFAULT_COLOR = "#cbf1ea"; 4537748cd8SNickeau 4637748cd8SNickeau /** 4737748cd8SNickeau * Used to select all lazy loaded 4837748cd8SNickeau * resources and load them before print 4937748cd8SNickeau */ 5037748cd8SNickeau const LAZY_CLASS = "lazy-combo"; 5137748cd8SNickeau 5237748cd8SNickeau 5337748cd8SNickeau public static function addSnippet() 5437748cd8SNickeau { 5537748cd8SNickeau switch (self::ACTIVE) { 5637748cd8SNickeau case self::LAZY_SIDE_ID: 5737748cd8SNickeau LazyLoad::addLazySizesSnippet(); 5837748cd8SNickeau break; 5937748cd8SNickeau case self::LOZAD_ID: 6037748cd8SNickeau LazyLoad::addLozadSnippet(); 6137748cd8SNickeau break; 6237748cd8SNickeau default: 6337748cd8SNickeau throw new \RuntimeException("The active lazy loaded is unknown (" . self::ACTIVE . ")"); 6437748cd8SNickeau } 6537748cd8SNickeau 6637748cd8SNickeau } 6737748cd8SNickeau 6837748cd8SNickeau /** 6937748cd8SNickeau * Add the lazy sizes snippet 7037748cd8SNickeau */ 7137748cd8SNickeau private static function addLazySizesSnippet() 7237748cd8SNickeau { 7337748cd8SNickeau 7437748cd8SNickeau $snippetManager = PluginUtility::getSnippetManager(); 7537748cd8SNickeau 76*4cadd4f8SNickeau $snippetManager->attachJavascriptLibraryForSlot( 77*4cadd4f8SNickeau self::LAZY_SIDE_ID, 78*4cadd4f8SNickeau "https://cdn.jsdelivr.net/npm/lazysizes@5.3.1/lazysizes.min.js", 79*4cadd4f8SNickeau "sha256-bmG+LzdKASJRACVXiUC69++Nu8rz7MX1U1z8gb0c/Tk=" 8037748cd8SNickeau ); 8137748cd8SNickeau /** 8237748cd8SNickeau * The Spinner effect 8337748cd8SNickeau * lazysizes adds the class lazy loading while the images are loading 8437748cd8SNickeau * and the class lazyloaded as soon as the image is loaded. 8537748cd8SNickeau */ 86*4cadd4f8SNickeau $snippetManager->attachCssInternalStyleSheetForSlot(self::LAZY_SIDE_ID); 8737748cd8SNickeau 8837748cd8SNickeau } 8937748cd8SNickeau 9037748cd8SNickeau /** 9137748cd8SNickeau * @param TagAttributes $attributes 9237748cd8SNickeau */ 9337748cd8SNickeau public static function addPlaceholderBackground(&$attributes) 9437748cd8SNickeau { 9537748cd8SNickeau // https://github.com/ApoorvSaxena/lozad.js#large-image-improvment 9637748cd8SNickeau $placeholderColor = LazyLoad::getPlaceholderColor(); 9737748cd8SNickeau if ($attributes->hasComponentAttribute(Background::BACKGROUND_COLOR)) { 9837748cd8SNickeau $placeholderColor = $attributes->getValueAndRemove(Background::BACKGROUND_COLOR); 9937748cd8SNickeau } 100*4cadd4f8SNickeau $attributes->addOutputAttributeValue("data-placeholder-background", "$placeholderColor"); 10137748cd8SNickeau 10237748cd8SNickeau 10337748cd8SNickeau } 10437748cd8SNickeau 10537748cd8SNickeau /** 10637748cd8SNickeau * Add lozad 10737748cd8SNickeau * Support background image 10837748cd8SNickeau * https://github.com/ApoorvSaxena/lozad.js 10937748cd8SNickeau */ 11037748cd8SNickeau public static function addLozadSnippet() 11137748cd8SNickeau { 11237748cd8SNickeau 11337748cd8SNickeau $snippetManager = PluginUtility::getSnippetManager(); 11437748cd8SNickeau 11537748cd8SNickeau // https://www.jsdelivr.com/package/npm/lozad 116*4cadd4f8SNickeau $snippetManager 117*4cadd4f8SNickeau ->attachJavascriptLibraryForSlot( 118*4cadd4f8SNickeau self::LOZAD_ID, 119*4cadd4f8SNickeau "https://cdn.jsdelivr.net/npm/lozad@1.16.0/dist/lozad.min.js", 120*4cadd4f8SNickeau "sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" 12137748cd8SNickeau ) 122*4cadd4f8SNickeau ->setDoesManipulateTheDomOnRun(false); 12337748cd8SNickeau 12437748cd8SNickeau /** 12537748cd8SNickeau * Add the fading effect 12637748cd8SNickeau */ 12737748cd8SNickeau $snippetId = "lazy-load-fade"; 128*4cadd4f8SNickeau $snippetManager->attachCssInternalStyleSheetForSlot($snippetId); 12937748cd8SNickeau 13037748cd8SNickeau 13137748cd8SNickeau /** 13237748cd8SNickeau * Snippet to download the image before print 13337748cd8SNickeau * 13437748cd8SNickeau * The others javascript snippet to download lazy load depend on the image type 13537748cd8SNickeau * and features and was therefore added in the code for svg or raster 13637748cd8SNickeau */ 137*4cadd4f8SNickeau $snippetManager->attachInternalJavascriptForSlot("lozad-print"); 13837748cd8SNickeau 13937748cd8SNickeau 14037748cd8SNickeau } 14137748cd8SNickeau 14237748cd8SNickeau /** 14337748cd8SNickeau * Class selector to identify the element to lazy load 14437748cd8SNickeau */ 14537748cd8SNickeau public static function getClass() 14637748cd8SNickeau { 14737748cd8SNickeau switch (self::ACTIVE) { 14837748cd8SNickeau case self::LAZY_SIDE_ID: 14937748cd8SNickeau return "lazyload"; 15037748cd8SNickeau case self::LOZAD_ID: 15137748cd8SNickeau return "lozad"; 15237748cd8SNickeau default: 15337748cd8SNickeau throw new \RuntimeException("The active lazy loaded is unknown (" . self::ACTIVE . ")"); 15437748cd8SNickeau } 15537748cd8SNickeau } 15637748cd8SNickeau 15737748cd8SNickeau /** 15837748cd8SNickeau * @return string - the lazy loading placeholder color 15937748cd8SNickeau */ 16037748cd8SNickeau public static function getPlaceholderColor() 16137748cd8SNickeau { 16237748cd8SNickeau return PluginUtility::getConfValue(self::CONF_LAZY_LOADING_PLACEHOLDER_COLOR, self::DEFAULT_COLOR); 16337748cd8SNickeau } 16437748cd8SNickeau 16537748cd8SNickeau /** 16637748cd8SNickeau * The placeholder is not mandatory 1671fa8c418SNickeau * but if present, it should have the same target ratio of the image 16837748cd8SNickeau * 16937748cd8SNickeau * This function is documenting this fact. 17037748cd8SNickeau * 17137748cd8SNickeau * @param null $imgTagWidth 17237748cd8SNickeau * @param null $imgTagHeight 17337748cd8SNickeau * @return string 17437748cd8SNickeau * 17537748cd8SNickeau * 17637748cd8SNickeau * Src is always set, this is the default 17737748cd8SNickeau * src attribute is served to browsers that do not take the srcset attribute into account. 17837748cd8SNickeau * When lazy loading, we set the srcset to a transparent image to not download the image in the src 17937748cd8SNickeau * 18037748cd8SNickeau */ 1811fa8c418SNickeau public static function getPlaceholder($imgTagWidth = null, $imgTagHeight = null): string 18237748cd8SNickeau { 18337748cd8SNickeau if ($imgTagWidth != null) { 18437748cd8SNickeau $svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 $imgTagWidth $imgTagHeight'></svg>"; 18537748cd8SNickeau /** 18637748cd8SNickeau * We encode it to be able to 18737748cd8SNickeau * use it in a `srcset` attribute that does not 18837748cd8SNickeau * want any space in the image definition 18937748cd8SNickeau */ 19037748cd8SNickeau $svgBase64 = base64_encode($svg); 19137748cd8SNickeau $image = "data:image/svg+xml;base64,$svgBase64"; 19237748cd8SNickeau } else { 19337748cd8SNickeau /** 19437748cd8SNickeau * Base64 transparent gif 19537748cd8SNickeau * 1x1 image, it will produce a square 19637748cd8SNickeau */ 19737748cd8SNickeau $image = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; 19837748cd8SNickeau } 19937748cd8SNickeau return $image; 20037748cd8SNickeau } 20137748cd8SNickeau} 202