137748cd8SNickeau<?php 237748cd8SNickeau/** 337748cd8SNickeau * Copyright (c) 2020. 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 15*1fa8c418SNickeau 1637748cd8SNickeaurequire_once(__DIR__ . '/PluginUtility.php'); 17*1fa8c418SNickeau 1837748cd8SNickeau 1937748cd8SNickeau/** 2037748cd8SNickeau * Image 2137748cd8SNickeau * This is the class that handles the 2237748cd8SNickeau * svg link type 2337748cd8SNickeau */ 24*1fa8c418SNickeauclass SvgImageLink extends ImageLink 2537748cd8SNickeau{ 2637748cd8SNickeau 27*1fa8c418SNickeau const CANONICAL = ImageSvg::CANONICAL; 2837748cd8SNickeau 2937748cd8SNickeau /** 3037748cd8SNickeau * The maximum size to be embedded 3137748cd8SNickeau * Above this size limit they are fetched 3237748cd8SNickeau */ 3337748cd8SNickeau const CONF_MAX_KB_SIZE_FOR_INLINE_SVG = "svgMaxInlineSizeKb"; 3437748cd8SNickeau 3537748cd8SNickeau /** 3637748cd8SNickeau * Lazy Load 3737748cd8SNickeau */ 3837748cd8SNickeau const CONF_LAZY_LOAD_ENABLE = "svgLazyLoadEnable"; 3937748cd8SNickeau 4037748cd8SNickeau /** 4137748cd8SNickeau * Svg Injection 4237748cd8SNickeau */ 4337748cd8SNickeau const CONF_SVG_INJECTION_ENABLE = "svgInjectionEnable"; 4437748cd8SNickeau 4537748cd8SNickeau 4637748cd8SNickeau /** 4737748cd8SNickeau * SvgImageLink constructor. 48*1fa8c418SNickeau * @param ImageSvg $imageSvg 4937748cd8SNickeau * @param TagAttributes $tagAttributes 5037748cd8SNickeau */ 51*1fa8c418SNickeau public function __construct($imageSvg) 5237748cd8SNickeau { 53*1fa8c418SNickeau parent::__construct($imageSvg); 54*1fa8c418SNickeau $imageSvg->getAttributes()->setLogicalTag(self::CANONICAL); 55*1fa8c418SNickeau 5637748cd8SNickeau } 5737748cd8SNickeau 5837748cd8SNickeau 59*1fa8c418SNickeau private function createImgHTMLTag(): string 6037748cd8SNickeau { 6137748cd8SNickeau 6237748cd8SNickeau 6337748cd8SNickeau $lazyLoad = $this->getLazyLoad(); 6437748cd8SNickeau 6537748cd8SNickeau $svgInjection = PluginUtility::getConfValue(self::CONF_SVG_INJECTION_ENABLE, 1); 6637748cd8SNickeau /** 6737748cd8SNickeau * Snippet 6837748cd8SNickeau */ 6937748cd8SNickeau if ($svgInjection) { 7037748cd8SNickeau $snippetManager = PluginUtility::getSnippetManager(); 7137748cd8SNickeau 7237748cd8SNickeau // Based on https://github.com/iconic/SVGInjector/ 7337748cd8SNickeau // See also: https://github.com/iconfu/svg-inject 7437748cd8SNickeau // !! There is a fork: https://github.com/tanem/svg-injector !! 7537748cd8SNickeau // Fallback ? : https://github.com/iconic/SVGInjector/#per-element-png-fallback 7637748cd8SNickeau $snippetManager->upsertTagsForBar("svg-injector", 7737748cd8SNickeau array( 7837748cd8SNickeau 'script' => [ 7937748cd8SNickeau array( 8037748cd8SNickeau "src" => "https://cdn.jsdelivr.net/npm/svg-injector@1.1.3/svg-injector.min.js", 8137748cd8SNickeau // "integrity" => "sha256-CjBlJvxqLCU2HMzFunTelZLFHCJdqgDoHi/qGJWdRJk=", 8237748cd8SNickeau "crossorigin" => "anonymous" 8337748cd8SNickeau ) 8437748cd8SNickeau ] 8537748cd8SNickeau ) 8637748cd8SNickeau ); 8737748cd8SNickeau } 8837748cd8SNickeau 8937748cd8SNickeau // Add lazy load snippet 9037748cd8SNickeau if ($lazyLoad) { 9137748cd8SNickeau LazyLoad::addLozadSnippet(); 9237748cd8SNickeau } 9337748cd8SNickeau 9437748cd8SNickeau /** 9537748cd8SNickeau * Remove the cache attribute 9637748cd8SNickeau * (no cache for the img tag) 9737748cd8SNickeau */ 98*1fa8c418SNickeau $image = $this->getDefaultImage(); 99*1fa8c418SNickeau $attributes = $image->getAttributes(); 100*1fa8c418SNickeau $attributes->removeComponentAttributeIfPresent(CacheMedia::CACHE_KEY); 10137748cd8SNickeau 10237748cd8SNickeau /** 10337748cd8SNickeau * Remove linking (not yet implemented) 10437748cd8SNickeau */ 105*1fa8c418SNickeau $attributes->removeComponentAttributeIfPresent(MediaLink::LINKING_KEY); 10637748cd8SNickeau 10737748cd8SNickeau 10837748cd8SNickeau /** 10937748cd8SNickeau * Src 11037748cd8SNickeau */ 111*1fa8c418SNickeau $srcValue = $image->getUrl(DokuwikiUrl::URL_ENCODED_AND); 11237748cd8SNickeau if ($lazyLoad) { 11337748cd8SNickeau 11437748cd8SNickeau /** 11537748cd8SNickeau * Note: Responsive image srcset is not needed for svg 11637748cd8SNickeau */ 117*1fa8c418SNickeau $attributes->addHtmlAttributeValue("data-src", $srcValue); 118*1fa8c418SNickeau $attributes->addHtmlAttributeValue("src", LazyLoad::getPlaceholder( 119*1fa8c418SNickeau $image->getTargetWidth(), 120*1fa8c418SNickeau $image->getTargetHeight() 121*1fa8c418SNickeau )); 12237748cd8SNickeau 12337748cd8SNickeau } else { 12437748cd8SNickeau 125*1fa8c418SNickeau $attributes->addHtmlAttributeValue("src", $srcValue); 12637748cd8SNickeau 12737748cd8SNickeau } 12837748cd8SNickeau 12937748cd8SNickeau /** 13037748cd8SNickeau * Adaptive Image 13137748cd8SNickeau * It adds a `height: auto` that avoid a layout shift when 13237748cd8SNickeau * using the img tag 13337748cd8SNickeau */ 134*1fa8c418SNickeau $attributes->addClassName(RasterImageLink::RESPONSIVE_CLASS); 13537748cd8SNickeau 13637748cd8SNickeau 13737748cd8SNickeau /** 138*1fa8c418SNickeau * Alt is mandatory 13937748cd8SNickeau */ 140*1fa8c418SNickeau $attributes->addHtmlAttributeValue("alt", $image->getAltNotEmpty()); 14137748cd8SNickeau 14237748cd8SNickeau 14337748cd8SNickeau /** 14437748cd8SNickeau * Class management 14537748cd8SNickeau * 14637748cd8SNickeau * functionalClass is the class used in Javascript 14737748cd8SNickeau * that should be in the class attribute 14837748cd8SNickeau * When injected, the other class should come in a `data-class` attribute 14937748cd8SNickeau */ 15037748cd8SNickeau $svgFunctionalClass = ""; 15137748cd8SNickeau if ($svgInjection && $lazyLoad) { 15237748cd8SNickeau PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("lozad-svg-injection"); 15337748cd8SNickeau $svgFunctionalClass = "lazy-svg-injection-combo"; 15437748cd8SNickeau } else if ($lazyLoad && !$svgInjection) { 15537748cd8SNickeau PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("lozad-svg"); 15637748cd8SNickeau $svgFunctionalClass = "lazy-svg-combo"; 15737748cd8SNickeau } else if ($svgInjection && !$lazyLoad) { 15837748cd8SNickeau PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("svg-injector"); 15937748cd8SNickeau $svgFunctionalClass = "svg-injection-combo"; 16037748cd8SNickeau } 16137748cd8SNickeau if ($lazyLoad) { 16237748cd8SNickeau // A class to all component lazy loaded to download them before print 16337748cd8SNickeau $svgFunctionalClass .= " " . LazyLoad::LAZY_CLASS; 16437748cd8SNickeau } 165*1fa8c418SNickeau $attributes->addClassName($svgFunctionalClass); 16637748cd8SNickeau 16737748cd8SNickeau /** 16837748cd8SNickeau * Dimension are mandatory 16937748cd8SNickeau * to avoid layout shift (CLS) 17037748cd8SNickeau */ 171*1fa8c418SNickeau $attributes->addHtmlAttributeValue(Dimension::WIDTH_KEY, $image->getTargetWidth()); 172*1fa8c418SNickeau $attributes->addHtmlAttributeValue(Dimension::HEIGHT_KEY, $image->getTargetHeight()); 17337748cd8SNickeau 17437748cd8SNickeau /** 17537748cd8SNickeau * Return the image 17637748cd8SNickeau */ 177*1fa8c418SNickeau return '<img ' . $attributes->toHTMLAttributeString() . '/>'; 17837748cd8SNickeau 17937748cd8SNickeau } 18037748cd8SNickeau 18137748cd8SNickeau 18237748cd8SNickeau /** 18337748cd8SNickeau * Render a link 18437748cd8SNickeau * Snippet derived from {@link \Doku_Renderer_xhtml::internalmedia()} 18537748cd8SNickeau * A media can be a video also 18637748cd8SNickeau * @return string 18737748cd8SNickeau */ 188*1fa8c418SNickeau public function renderMediaTag(): string 18937748cd8SNickeau { 19037748cd8SNickeau 191*1fa8c418SNickeau /** 192*1fa8c418SNickeau * @var ImageSvg $image 193*1fa8c418SNickeau */ 194*1fa8c418SNickeau $image = $this->getDefaultImage(); 195*1fa8c418SNickeau if ($image->exists()) { 19637748cd8SNickeau 19737748cd8SNickeau /** 19837748cd8SNickeau * This attributes should not be in the render 19937748cd8SNickeau */ 200*1fa8c418SNickeau $attributes = $this->getDefaultImage()->getAttributes(); 201*1fa8c418SNickeau $attributes->removeComponentAttributeIfPresent(MediaLink::MEDIA_DOKUWIKI_TYPE); 202*1fa8c418SNickeau $attributes->removeComponentAttributeIfPresent(MediaLink::DOKUWIKI_SRC); 20337748cd8SNickeau /** 20437748cd8SNickeau * TODO: Title should be a node just below SVG 20537748cd8SNickeau */ 206*1fa8c418SNickeau $attributes->removeComponentAttributeIfPresent(Page::TITLE_META_PROPERTY); 20737748cd8SNickeau 20837748cd8SNickeau if ( 209*1fa8c418SNickeau $image->getSize() > $this->getMaxInlineSize() 21037748cd8SNickeau ) { 21137748cd8SNickeau 21237748cd8SNickeau /** 21337748cd8SNickeau * Img tag 21437748cd8SNickeau */ 21537748cd8SNickeau $imgHTML = $this->createImgHTMLTag(); 21637748cd8SNickeau 21737748cd8SNickeau } else { 21837748cd8SNickeau 21937748cd8SNickeau /** 22037748cd8SNickeau * Svg tag 22137748cd8SNickeau */ 222*1fa8c418SNickeau $imgHTML = file_get_contents($image->getSvgFile()); 22337748cd8SNickeau 22437748cd8SNickeau } 22537748cd8SNickeau 22637748cd8SNickeau 22737748cd8SNickeau } else { 22837748cd8SNickeau 22937748cd8SNickeau $imgHTML = "<span class=\"text-danger\">The svg ($this) does not exist</span>"; 23037748cd8SNickeau 23137748cd8SNickeau } 23237748cd8SNickeau return $imgHTML; 23337748cd8SNickeau } 23437748cd8SNickeau 23537748cd8SNickeau private function getMaxInlineSize() 23637748cd8SNickeau { 23737748cd8SNickeau return PluginUtility::getConfValue(self::CONF_MAX_KB_SIZE_FOR_INLINE_SVG, 2) * 1024; 23837748cd8SNickeau } 23937748cd8SNickeau 24037748cd8SNickeau 24137748cd8SNickeau public function getLazyLoad() 24237748cd8SNickeau { 24337748cd8SNickeau $lazyLoad = parent::getLazyLoad(); 24437748cd8SNickeau if ($lazyLoad !== null) { 24537748cd8SNickeau return $lazyLoad; 24637748cd8SNickeau } else { 24737748cd8SNickeau return PluginUtility::getConfValue(SvgImageLink::CONF_LAZY_LOAD_ENABLE); 24837748cd8SNickeau } 24937748cd8SNickeau } 25037748cd8SNickeau 25137748cd8SNickeau 25237748cd8SNickeau} 253