xref: /template/strap/ComboStrap/LazyLoad.php (revision 1fa8c418ed5809db58049141be41b7738471dd32)
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