* */ namespace ComboStrap; require_once(__DIR__ . '/PluginUtility.php'); /** * Image * This is the class that handles the * svg link type */ class SvgImageLink extends ImageLink { const CANONICAL = ImageSvg::CANONICAL; /** * The maximum size to be embedded * Above this size limit they are fetched */ const CONF_MAX_KB_SIZE_FOR_INLINE_SVG = "svgMaxInlineSizeKb"; /** * Lazy Load */ const CONF_LAZY_LOAD_ENABLE = "svgLazyLoadEnable"; /** * Svg Injection */ const CONF_SVG_INJECTION_ENABLE = "svgInjectionEnable"; /** * SvgImageLink constructor. * @param ImageSvg $imageSvg * @param TagAttributes $tagAttributes */ public function __construct($imageSvg) { parent::__construct($imageSvg); $imageSvg->getAttributes()->setLogicalTag(self::CANONICAL); } private function createImgHTMLTag(): string { $lazyLoad = $this->getLazyLoad(); $svgInjection = PluginUtility::getConfValue(self::CONF_SVG_INJECTION_ENABLE, 1); /** * Snippet */ if ($svgInjection) { $snippetManager = PluginUtility::getSnippetManager(); // Based on https://github.com/iconic/SVGInjector/ // See also: https://github.com/iconfu/svg-inject // !! There is a fork: https://github.com/tanem/svg-injector !! // Fallback ? : https://github.com/iconic/SVGInjector/#per-element-png-fallback $snippetManager->upsertTagsForBar("svg-injector", array( 'script' => [ array( "src" => "https://cdn.jsdelivr.net/npm/svg-injector@1.1.3/svg-injector.min.js", // "integrity" => "sha256-CjBlJvxqLCU2HMzFunTelZLFHCJdqgDoHi/qGJWdRJk=", "crossorigin" => "anonymous" ) ] ) ); } // Add lazy load snippet if ($lazyLoad) { LazyLoad::addLozadSnippet(); } /** * Remove the cache attribute * (no cache for the img tag) */ $image = $this->getDefaultImage(); $attributes = $image->getAttributes(); $attributes->removeComponentAttributeIfPresent(CacheMedia::CACHE_KEY); /** * Remove linking (not yet implemented) */ $attributes->removeComponentAttributeIfPresent(MediaLink::LINKING_KEY); /** * Src */ $srcValue = $image->getUrl(DokuwikiUrl::URL_ENCODED_AND); if ($lazyLoad) { /** * Note: Responsive image srcset is not needed for svg */ $attributes->addHtmlAttributeValue("data-src", $srcValue); $attributes->addHtmlAttributeValue("src", LazyLoad::getPlaceholder( $image->getTargetWidth(), $image->getTargetHeight() )); } else { $attributes->addHtmlAttributeValue("src", $srcValue); } /** * Adaptive Image * It adds a `height: auto` that avoid a layout shift when * using the img tag */ $attributes->addClassName(RasterImageLink::RESPONSIVE_CLASS); /** * Alt is mandatory */ $attributes->addHtmlAttributeValue("alt", $image->getAltNotEmpty()); /** * Class management * * functionalClass is the class used in Javascript * that should be in the class attribute * When injected, the other class should come in a `data-class` attribute */ $svgFunctionalClass = ""; if ($svgInjection && $lazyLoad) { PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("lozad-svg-injection"); $svgFunctionalClass = "lazy-svg-injection-combo"; } else if ($lazyLoad && !$svgInjection) { PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("lozad-svg"); $svgFunctionalClass = "lazy-svg-combo"; } else if ($svgInjection && !$lazyLoad) { PluginUtility::getSnippetManager()->attachJavascriptSnippetForBar("svg-injector"); $svgFunctionalClass = "svg-injection-combo"; } if ($lazyLoad) { // A class to all component lazy loaded to download them before print $svgFunctionalClass .= " " . LazyLoad::LAZY_CLASS; } $attributes->addClassName($svgFunctionalClass); /** * Dimension are mandatory * to avoid layout shift (CLS) */ $attributes->addHtmlAttributeValue(Dimension::WIDTH_KEY, $image->getTargetWidth()); $attributes->addHtmlAttributeValue(Dimension::HEIGHT_KEY, $image->getTargetHeight()); /** * Return the image */ return 'toHTMLAttributeString() . '/>'; } /** * Render a link * Snippet derived from {@link \Doku_Renderer_xhtml::internalmedia()} * A media can be a video also * @return string */ public function renderMediaTag(): string { /** * @var ImageSvg $image */ $image = $this->getDefaultImage(); if ($image->exists()) { /** * This attributes should not be in the render */ $attributes = $this->getDefaultImage()->getAttributes(); $attributes->removeComponentAttributeIfPresent(MediaLink::MEDIA_DOKUWIKI_TYPE); $attributes->removeComponentAttributeIfPresent(MediaLink::DOKUWIKI_SRC); /** * TODO: Title should be a node just below SVG */ $attributes->removeComponentAttributeIfPresent(Page::TITLE_META_PROPERTY); if ( $image->getSize() > $this->getMaxInlineSize() ) { /** * Img tag */ $imgHTML = $this->createImgHTMLTag(); } else { /** * Svg tag */ $imgHTML = file_get_contents($image->getSvgFile()); } } else { $imgHTML = "The svg ($this) does not exist"; } return $imgHTML; } private function getMaxInlineSize() { return PluginUtility::getConfValue(self::CONF_MAX_KB_SIZE_FOR_INLINE_SVG, 2) * 1024; } public function getLazyLoad() { $lazyLoad = parent::getLazyLoad(); if ($lazyLoad !== null) { return $lazyLoad; } else { return PluginUtility::getConfValue(SvgImageLink::CONF_LAZY_LOAD_ENABLE); } } }