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 7637748cd8SNickeau $snippetManager->upsertTagsForBar(self::LAZY_SIDE_ID, 7737748cd8SNickeau array( 7837748cd8SNickeau 'script' => [ 7937748cd8SNickeau array( 8037748cd8SNickeau "src" => "https://cdn.jsdelivr.net/npm/lazysizes@5.3.1/lazysizes.min.js", 8137748cd8SNickeau "integrity" => "sha256-bmG+LzdKASJRACVXiUC69++Nu8rz7MX1U1z8gb0c/Tk=", 8237748cd8SNickeau "crossorigin" => "anonymous" 8337748cd8SNickeau ) 8437748cd8SNickeau ] 8537748cd8SNickeau ) 8637748cd8SNickeau ); 8737748cd8SNickeau /** 8837748cd8SNickeau * The Spinner effect 8937748cd8SNickeau * lazysizes adds the class lazy loading while the images are loading 9037748cd8SNickeau * and the class lazyloaded as soon as the image is loaded. 9137748cd8SNickeau */ 9237748cd8SNickeau $snippetManager->attachCssSnippetForBar(self::LAZY_SIDE_ID); 9337748cd8SNickeau 9437748cd8SNickeau } 9537748cd8SNickeau 9637748cd8SNickeau /** 9737748cd8SNickeau * @param TagAttributes $attributes 9837748cd8SNickeau */ 9937748cd8SNickeau public static function addPlaceholderBackground(&$attributes) 10037748cd8SNickeau { 10137748cd8SNickeau // https://github.com/ApoorvSaxena/lozad.js#large-image-improvment 10237748cd8SNickeau $placeholderColor = LazyLoad::getPlaceholderColor(); 10337748cd8SNickeau if ($attributes->hasComponentAttribute(Background::BACKGROUND_COLOR)) { 10437748cd8SNickeau $placeholderColor = $attributes->getValueAndRemove(Background::BACKGROUND_COLOR); 10537748cd8SNickeau } 10637748cd8SNickeau $attributes->addHtmlAttributeValue("data-placeholder-background", "$placeholderColor"); 10737748cd8SNickeau 10837748cd8SNickeau 10937748cd8SNickeau } 11037748cd8SNickeau 11137748cd8SNickeau /** 11237748cd8SNickeau * Add lozad 11337748cd8SNickeau * Support background image 11437748cd8SNickeau * https://github.com/ApoorvSaxena/lozad.js 11537748cd8SNickeau */ 11637748cd8SNickeau public static function addLozadSnippet() 11737748cd8SNickeau { 11837748cd8SNickeau 11937748cd8SNickeau $snippetManager = PluginUtility::getSnippetManager(); 12037748cd8SNickeau 12137748cd8SNickeau // https://www.jsdelivr.com/package/npm/lozad 12237748cd8SNickeau $snippetManager->upsertTagsForBar(self::LOZAD_ID, 12337748cd8SNickeau array( 12437748cd8SNickeau 'script' => [ 12537748cd8SNickeau array( 12637748cd8SNickeau "src" => "https://cdn.jsdelivr.net/npm/lozad@1.16.0/dist/lozad.min.js", 12737748cd8SNickeau "integrity" => "sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=", 12837748cd8SNickeau "crossorigin" => "anonymous" 12937748cd8SNickeau 13037748cd8SNickeau ) 13137748cd8SNickeau ] 13237748cd8SNickeau ) 13337748cd8SNickeau ); 13437748cd8SNickeau 13537748cd8SNickeau /** 13637748cd8SNickeau * Add the fading effect 13737748cd8SNickeau */ 13837748cd8SNickeau $snippetId = "lazy-load-fade"; 13937748cd8SNickeau $snippetManager->attachCssSnippetForBar($snippetId); 14037748cd8SNickeau 14137748cd8SNickeau 14237748cd8SNickeau /** 14337748cd8SNickeau * Snippet to download the image before print 14437748cd8SNickeau * 14537748cd8SNickeau * The others javascript snippet to download lazy load depend on the image type 14637748cd8SNickeau * and features and was therefore added in the code for svg or raster 14737748cd8SNickeau */ 14837748cd8SNickeau $snippetManager->attachJavascriptSnippetForBar("lozad-print"); 14937748cd8SNickeau 15037748cd8SNickeau 15137748cd8SNickeau } 15237748cd8SNickeau 15337748cd8SNickeau /** 15437748cd8SNickeau * Class selector to identify the element to lazy load 15537748cd8SNickeau */ 15637748cd8SNickeau public static function getClass() 15737748cd8SNickeau { 15837748cd8SNickeau switch (self::ACTIVE) { 15937748cd8SNickeau case self::LAZY_SIDE_ID: 16037748cd8SNickeau return "lazyload"; 16137748cd8SNickeau case self::LOZAD_ID: 16237748cd8SNickeau return "lozad"; 16337748cd8SNickeau default: 16437748cd8SNickeau throw new \RuntimeException("The active lazy loaded is unknown (" . self::ACTIVE . ")"); 16537748cd8SNickeau } 16637748cd8SNickeau } 16737748cd8SNickeau 16837748cd8SNickeau /** 16937748cd8SNickeau * @return string - the lazy loading placeholder color 17037748cd8SNickeau */ 17137748cd8SNickeau public static function getPlaceholderColor() 17237748cd8SNickeau { 17337748cd8SNickeau return PluginUtility::getConfValue(self::CONF_LAZY_LOADING_PLACEHOLDER_COLOR, self::DEFAULT_COLOR); 17437748cd8SNickeau } 17537748cd8SNickeau 17637748cd8SNickeau /** 17737748cd8SNickeau * The placeholder is not mandatory 178*1fa8c418SNickeau * but if present, it should have the same target ratio of the image 17937748cd8SNickeau * 18037748cd8SNickeau * This function is documenting this fact. 18137748cd8SNickeau * 18237748cd8SNickeau * @param null $imgTagWidth 18337748cd8SNickeau * @param null $imgTagHeight 18437748cd8SNickeau * @return string 18537748cd8SNickeau * 18637748cd8SNickeau 18737748cd8SNickeau * 18837748cd8SNickeau * Src is always set, this is the default 18937748cd8SNickeau * src attribute is served to browsers that do not take the srcset attribute into account. 19037748cd8SNickeau * When lazy loading, we set the srcset to a transparent image to not download the image in the src 19137748cd8SNickeau * 19237748cd8SNickeau */ 19337748cd8SNickeau 194*1fa8c418SNickeau public static function getPlaceholder($imgTagWidth = null, $imgTagHeight = null): string 19537748cd8SNickeau { 19637748cd8SNickeau if ($imgTagWidth != null) { 19737748cd8SNickeau $svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 $imgTagWidth $imgTagHeight'></svg>"; 19837748cd8SNickeau /** 19937748cd8SNickeau * We encode it to be able to 20037748cd8SNickeau * use it in a `srcset` attribute that does not 20137748cd8SNickeau * want any space in the image definition 20237748cd8SNickeau */ 20337748cd8SNickeau $svgBase64 = base64_encode($svg); 20437748cd8SNickeau $image = "data:image/svg+xml;base64,$svgBase64"; 20537748cd8SNickeau } else { 20637748cd8SNickeau /** 20737748cd8SNickeau * Base64 transparent gif 20837748cd8SNickeau * 1x1 image, it will produce a square 20937748cd8SNickeau */ 21037748cd8SNickeau $image = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; 21137748cd8SNickeau } 21237748cd8SNickeau return $image; 21337748cd8SNickeau } 21437748cd8SNickeau} 215