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 151fa8c418SNickeaurequire_once(__DIR__ . '/PluginUtility.php'); 1637748cd8SNickeau 1737748cd8SNickeau 1837748cd8SNickeau/** 1937748cd8SNickeau * Class IconUtility 2037748cd8SNickeau * @package ComboStrap 2137748cd8SNickeau * @see https://combostrap.com/icon 2237748cd8SNickeau * 2337748cd8SNickeau * 2437748cd8SNickeau * Material design does not have a repository structure where we can extract the location 2537748cd8SNickeau * from the name 2637748cd8SNickeau * https://material.io/resources/icons https://google.github.io/material-design-icons/ 2737748cd8SNickeau * 2837748cd8SNickeau * Injection via javascript to avoid problem with the php svgsimple library 2937748cd8SNickeau * https://www.npmjs.com/package/svg-injector 3037748cd8SNickeau */ 31*82a60d03SNickeauclass Icon extends ImageSvg 3237748cd8SNickeau{ 3337748cd8SNickeau const CONF_ICONS_MEDIA_NAMESPACE = "icons_namespace"; 3437748cd8SNickeau const CONF_ICONS_MEDIA_NAMESPACE_DEFAULT = ":" . PluginUtility::COMBOSTRAP_NAMESPACE_NAME . ":icons"; 3537748cd8SNickeau // Canonical name 3637748cd8SNickeau const NAME = "icon"; 3737748cd8SNickeau 3837748cd8SNickeau 3937748cd8SNickeau const ICON_LIBRARY_URLS = array( 4037748cd8SNickeau self::BOOTSTRAP => "https://raw.githubusercontent.com/twbs/icons/main/icons", 4137748cd8SNickeau self::MATERIAL_DESIGN => "https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg", 42c3437056SNickeau self::FEATHER => "https://raw.githubusercontent.com/feathericons/feather/master/icons", 43*82a60d03SNickeau self::CODE_ICON => "https://raw.githubusercontent.com/microsoft/vscode-codicons/main/src/icons", 44*82a60d03SNickeau self::LOGOS => "https://raw.githubusercontent.com/gilbarbara/logos/master/logos", 45*82a60d03SNickeau self::CARBON => "https://raw.githubusercontent.com/carbon-design-system/carbon/main/packages/icons/src/svg/32", 46*82a60d03SNickeau self::TWEET_EMOJI => "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg", 47*82a60d03SNickeau self::ANT_DESIGN => "https://raw.githubusercontent.com/ant-design/ant-design-icons/master/packages/icons-svg/svg", 48*82a60d03SNickeau self::FAD => "https://raw.githubusercontent.com/fefanto/fontaudio/master/svgs", 49*82a60d03SNickeau self::CLARITY => "https://raw.githubusercontent.com/vmware/clarity-assets/master/icons/essential", 50*82a60d03SNickeau self::OCTICON => "https://raw.githubusercontent.com/primer/octicons/main/icons" 5137748cd8SNickeau ); 5237748cd8SNickeau 5337748cd8SNickeau const ICON_LIBRARY_WEBSITE_URLS = array( 5437748cd8SNickeau self::BOOTSTRAP => "https://icons.getbootstrap.com/", 5537748cd8SNickeau self::MATERIAL_DESIGN => "https://materialdesignicons.com/", 56c3437056SNickeau self::FEATHER => "https://feathericons.com/", 57c3437056SNickeau self::CODE_ICON => "https://microsoft.github.io/vscode-codicons/", 58c3437056SNickeau self::LOGOS => "https://svgporn.com/", 59*82a60d03SNickeau self::CARBON => "https://www.carbondesignsystem.com/guidelines/icons/library/", 60*82a60d03SNickeau self::TWEET_EMOJI => "https://twemoji.twitter.com/", 61*82a60d03SNickeau self::ANT_DESIGN => "https://ant.design/components/icon/", 62*82a60d03SNickeau self::CLARITY => "https://clarity.design/foundation/icons/", 63*82a60d03SNickeau self::OCTICON => "https://primer.style/octicons/" 6437748cd8SNickeau ); 6537748cd8SNickeau 6637748cd8SNickeau const CONF_DEFAULT_ICON_LIBRARY = "defaultIconLibrary"; 67c3437056SNickeau const CONF_DEFAULT_ICON_LIBRARY_DEFAULT = self::MATERIAL_DESIGN_ACRONYM; 68c3437056SNickeau 69c3437056SNickeau /** 70c3437056SNickeau * Deprecated library acronym / name 71c3437056SNickeau */ 72c3437056SNickeau const DEPRECATED_LIBRARY_ACRONYM = array( 73c3437056SNickeau "bs" => self::BOOTSTRAP, // old one (deprecated) - the good acronym is bi (seen also in the class) 74c3437056SNickeau "md" => self::MATERIAL_DESIGN 7537748cd8SNickeau ); 76c3437056SNickeau 77c3437056SNickeau /** 78c3437056SNickeau * Public known acronym / name (Used in the configuration) 79c3437056SNickeau */ 80c3437056SNickeau const PUBLIC_LIBRARY_ACRONYM = array( 81c3437056SNickeau "bi" => self::BOOTSTRAP, 82c3437056SNickeau self::MATERIAL_DESIGN_ACRONYM => self::MATERIAL_DESIGN, 83c3437056SNickeau "fe" => self::FEATHER, 84c3437056SNickeau "codicon" => self::CODE_ICON, 85c3437056SNickeau "logos" => self::LOGOS, 86*82a60d03SNickeau "carbon" => self::CARBON, 87*82a60d03SNickeau "twemoji" => self::TWEET_EMOJI, 88*82a60d03SNickeau "ant-design" => self::ANT_DESIGN, 89*82a60d03SNickeau "fad" => self::FAD, 90*82a60d03SNickeau "clarity" => self::CLARITY, 91*82a60d03SNickeau "octicon" => self::OCTICON 92c3437056SNickeau ); 93c3437056SNickeau 9437748cd8SNickeau const FEATHER = "feather"; 9537748cd8SNickeau const BOOTSTRAP = "bootstrap"; 9637748cd8SNickeau const MATERIAL_DESIGN = "material-design"; 97c3437056SNickeau const CODE_ICON = "codicon"; 98c3437056SNickeau const LOGOS = "logos"; 99c3437056SNickeau const CARBON = "carbon"; 100c3437056SNickeau const MATERIAL_DESIGN_ACRONYM = "mdi"; 101*82a60d03SNickeau const TWEET_EMOJI = "twemoji"; 102*82a60d03SNickeau const ANT_DESIGN = "ant-design"; 103*82a60d03SNickeau const FAD = "fad"; 104*82a60d03SNickeau const CLARITY = "clarity"; 105*82a60d03SNickeau const OCTICON = "octicon"; 10637748cd8SNickeau 10737748cd8SNickeau 10837748cd8SNickeau /** 10937748cd8SNickeau * The function used to render an icon 11037748cd8SNickeau * @param TagAttributes $tagAttributes - the icon attributes 111*82a60d03SNickeau * @return Icon 112*82a60d03SNickeau * @throws ExceptionCombo 11337748cd8SNickeau */ 114*82a60d03SNickeau static public function create(TagAttributes $tagAttributes): Icon 11537748cd8SNickeau { 11637748cd8SNickeau 11737748cd8SNickeau 11837748cd8SNickeau $name = "name"; 11937748cd8SNickeau if (!$tagAttributes->hasComponentAttribute($name)) { 120*82a60d03SNickeau throw new ExceptionCombo("The attributes should have a name. It's mandatory for an icon.", self::NAME); 12137748cd8SNickeau } 12237748cd8SNickeau 12337748cd8SNickeau /** 12437748cd8SNickeau * The Name 12537748cd8SNickeau */ 12637748cd8SNickeau $iconNameAttribute = $tagAttributes->getValue($name); 12737748cd8SNickeau 12837748cd8SNickeau /** 12937748cd8SNickeau * If the name have an extension, it's a file from the media directory 13037748cd8SNickeau * Otherwise, it's an icon from a library 13137748cd8SNickeau */ 13237748cd8SNickeau $mediaDokuPath = DokuPath::createMediaPathFromId($iconNameAttribute); 13337748cd8SNickeau if (!empty($mediaDokuPath->getExtension())) { 13437748cd8SNickeau 13537748cd8SNickeau // loop through candidates until a match was found: 13637748cd8SNickeau // May be an icon from the templates 137c3437056SNickeau if (!FileSystems::exists($mediaDokuPath)) { 13837748cd8SNickeau 13937748cd8SNickeau // Trying to see if it's not in the template images directory 14037748cd8SNickeau $message = "The media file could not be found in the media library. If you want an icon from an icon library, indicate a name without extension."; 14137748cd8SNickeau $message .= "<BR> Media File Library tested: $mediaDokuPath"; 142*82a60d03SNickeau throw new ExceptionCombo($message, self::NAME); 143*82a60d03SNickeau 14437748cd8SNickeau 14537748cd8SNickeau } 14637748cd8SNickeau 14737748cd8SNickeau } else { 14837748cd8SNickeau 14937748cd8SNickeau // It may be a icon already downloaded 150c3437056SNickeau $iconNameSpace = PluginUtility::getConfValue(self::CONF_ICONS_MEDIA_NAMESPACE, self::CONF_ICONS_MEDIA_NAMESPACE_DEFAULT); 15137748cd8SNickeau if (substr($iconNameSpace, 0, 1) != DokuPath::PATH_SEPARATOR) { 15237748cd8SNickeau $iconNameSpace = DokuPath::PATH_SEPARATOR . $iconNameSpace; 15337748cd8SNickeau } 15437748cd8SNickeau if (substr($iconNameSpace, -1) != DokuPath::PATH_SEPARATOR) { 15537748cd8SNickeau $iconNameSpace = $iconNameSpace . ":"; 15637748cd8SNickeau } 15737748cd8SNickeau $mediaPathId = $iconNameSpace . $iconNameAttribute . ".svg"; 15837748cd8SNickeau $mediaDokuPath = DokuPath::createMediaPathFromAbsolutePath($mediaPathId); 15937748cd8SNickeau 16037748cd8SNickeau // Bug: null file created when the stream could not get any byte 16137748cd8SNickeau // We delete them 162c3437056SNickeau if (FileSystems::exists($mediaDokuPath)) { 163c3437056SNickeau if (FileSystems::getSize($mediaDokuPath) == 0) { 164c3437056SNickeau FileSystems::delete($mediaDokuPath); 16537748cd8SNickeau } 16637748cd8SNickeau } 16737748cd8SNickeau 168c3437056SNickeau if (!FileSystems::exists($mediaDokuPath)) { 16937748cd8SNickeau 17037748cd8SNickeau /** 17137748cd8SNickeau * Download the icon 17237748cd8SNickeau */ 17337748cd8SNickeau 17437748cd8SNickeau // Create the target directory if it does not exist 17537748cd8SNickeau $iconDir = $mediaDokuPath->getParent(); 176c3437056SNickeau if (!FileSystems::exists($iconDir)) { 177c3437056SNickeau try { 178c3437056SNickeau FileSystems::createDirectory($iconDir); 179c3437056SNickeau } catch (ExceptionCombo $e) { 180*82a60d03SNickeau throw new ExceptionCombo("The icon directory ($iconDir) could not be created.", self::NAME, 0, $e); 18137748cd8SNickeau } 18237748cd8SNickeau } 18337748cd8SNickeau 18437748cd8SNickeau // Name parsing to extract the library name and icon name 18537748cd8SNickeau $sepPosition = strpos($iconNameAttribute, ":"); 186c3437056SNickeau $library = PluginUtility::getConfValue(self::CONF_DEFAULT_ICON_LIBRARY, self::CONF_DEFAULT_ICON_LIBRARY_DEFAULT); 18737748cd8SNickeau $iconName = $iconNameAttribute; 18837748cd8SNickeau if ($sepPosition != false) { 18937748cd8SNickeau $library = substr($iconNameAttribute, 0, $sepPosition); 19037748cd8SNickeau $iconName = substr($iconNameAttribute, $sepPosition + 1); 19137748cd8SNickeau } 19237748cd8SNickeau 19337748cd8SNickeau // Get the qualified library name 194c3437056SNickeau $acronymLibraries = self::getLibraries(); 19537748cd8SNickeau if (isset($acronymLibraries[$library])) { 19637748cd8SNickeau $library = $acronymLibraries[$library]; 19737748cd8SNickeau } 19837748cd8SNickeau 19937748cd8SNickeau // Get the url 20037748cd8SNickeau $iconLibraries = self::ICON_LIBRARY_URLS; 20137748cd8SNickeau if (!isset($iconLibraries[$library])) { 202*82a60d03SNickeau throw new ExceptionCombo("The icon library ($library) is unknown. The icon could not be downloaded.", self::NAME); 20337748cd8SNickeau } else { 20437748cd8SNickeau $iconBaseUrl = $iconLibraries[$library]; 20537748cd8SNickeau } 20637748cd8SNickeau 207*82a60d03SNickeau /** 208*82a60d03SNickeau * Name processing 209*82a60d03SNickeau */ 210*82a60d03SNickeau switch ($library) { 211*82a60d03SNickeau 212*82a60d03SNickeau case self::TWEET_EMOJI: 213*82a60d03SNickeau try { 214*82a60d03SNickeau $iconName = self::getEmojiCodePoint($iconName); 215*82a60d03SNickeau } catch (ExceptionCombo $e) { 216*82a60d03SNickeau throw new ExceptionCombo("The emoji name $iconName is unknown. The emoji could not be downloaded.", self::NAME, 0, $e); 217*82a60d03SNickeau } 218*82a60d03SNickeau break; 219*82a60d03SNickeau case self::ANT_DESIGN: 220*82a60d03SNickeau // table-outlined where table is the svg, outlined the category 221*82a60d03SNickeau // ordered-list-outlined where ordered-list is the svg, outlined the category 222*82a60d03SNickeau $iconProcessed = $iconName; 223*82a60d03SNickeau $index = strrpos($iconProcessed, "-"); 224*82a60d03SNickeau if ($index === false) { 225*82a60d03SNickeau throw new ExceptionCombo ("We expect that a ant design icon name ($iconName) has two parts separated by a `-` (example: table-outlined). The icon could not be downloaded.", self::NAME); 226*82a60d03SNickeau } 227*82a60d03SNickeau $iconName = substr($iconProcessed, 0, $index); 228*82a60d03SNickeau $iconType = substr($iconProcessed, $index + 1); 229*82a60d03SNickeau $iconBaseUrl .= "/$iconType"; 230*82a60d03SNickeau break; 231*82a60d03SNickeau case self::CARBON: 232*82a60d03SNickeau $iconName = self::getCarbonPhysicalName($iconName); 233*82a60d03SNickeau break; 234*82a60d03SNickeau case self::FAD: 235*82a60d03SNickeau $iconName = self::getFadPhysicalName($iconName); 236*82a60d03SNickeau } 237*82a60d03SNickeau 238*82a60d03SNickeau 23937748cd8SNickeau // The url 24037748cd8SNickeau $downloadUrl = "$iconBaseUrl/$iconName.svg"; 24137748cd8SNickeau $filePointer = @fopen($downloadUrl, 'r'); 24237748cd8SNickeau if ($filePointer != false) { 24337748cd8SNickeau 244c3437056SNickeau $numberOfByte = @file_put_contents($mediaDokuPath->toLocalPath()->toAbsolutePath()->toString(), $filePointer); 24537748cd8SNickeau if ($numberOfByte != false) { 24637748cd8SNickeau LogUtility::msg("The icon ($iconName) from the library ($library) was downloaded to ($mediaPathId)", LogUtility::LVL_MSG_INFO, self::NAME); 24737748cd8SNickeau } else { 24837748cd8SNickeau LogUtility::msg("Internal error: The icon ($iconName) from the library ($library) could no be written to ($mediaPathId)", LogUtility::LVL_MSG_ERROR, self::NAME); 24937748cd8SNickeau } 25037748cd8SNickeau 25137748cd8SNickeau } else { 25237748cd8SNickeau 25337748cd8SNickeau // (ie no icon file found at ($downloadUrl) 25437748cd8SNickeau $urlLibrary = self::ICON_LIBRARY_WEBSITE_URLS[$library]; 25537748cd8SNickeau LogUtility::msg("The library (<a href=\"$urlLibrary\">$library</a>) does not have a icon (<a href=\"$downloadUrl\">$iconName</a>).", LogUtility::LVL_MSG_ERROR, self::NAME); 25637748cd8SNickeau 25737748cd8SNickeau } 25837748cd8SNickeau 25937748cd8SNickeau } 26037748cd8SNickeau 26137748cd8SNickeau } 26237748cd8SNickeau 26337748cd8SNickeau /** 26437748cd8SNickeau * After optimization, the width and height of the svg are gone 26537748cd8SNickeau * but the icon type set them again 26637748cd8SNickeau * 26737748cd8SNickeau * The icon type is used to set: 26837748cd8SNickeau * * the default dimension 26937748cd8SNickeau * * color styling 27037748cd8SNickeau * * disable the responsive properties 27137748cd8SNickeau * 27237748cd8SNickeau */ 273*82a60d03SNickeau $tagAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, SvgDocument::ICON_TYPE); 27437748cd8SNickeau 275*82a60d03SNickeau return new Icon($mediaDokuPath, $tagAttributes); 27637748cd8SNickeau 27737748cd8SNickeau } 27837748cd8SNickeau 27937748cd8SNickeau /** 28037748cd8SNickeau * @param $iconName 28137748cd8SNickeau * @param $mediaFilePath 28237748cd8SNickeau * @deprecated Old code to download icon from the material design api 28337748cd8SNickeau */ 28437748cd8SNickeau public 28537748cd8SNickeau static function downloadIconFromMaterialDesignApi($iconName, $mediaFilePath) 28637748cd8SNickeau { 28737748cd8SNickeau // Try the official API 28837748cd8SNickeau // Read the icon meta of 28937748cd8SNickeau // Meta Json file got all icons 29037748cd8SNickeau // 29137748cd8SNickeau // * Available at: https://raw.githubusercontent.com/Templarian/MaterialDesign/master/meta.json 29237748cd8SNickeau // * See doc: https://github.com/Templarian/MaterialDesign-Site/blob/master/src/content/api.md) 29337748cd8SNickeau $arrayFormat = true; 294*82a60d03SNickeau $iconMetaJson = json_decode(file_get_contents(__DIR__ . '/../resources/dictionary/icon-meta.json'), $arrayFormat); 29537748cd8SNickeau $iconId = null; 29637748cd8SNickeau foreach ($iconMetaJson as $key => $value) { 29737748cd8SNickeau if ($value['name'] == $iconName) { 29837748cd8SNickeau $iconId = $value['id']; 29937748cd8SNickeau break; 30037748cd8SNickeau } 30137748cd8SNickeau } 30237748cd8SNickeau if ($iconId != null) { 30337748cd8SNickeau 30437748cd8SNickeau // Download 30537748cd8SNickeau // Call to the API 30637748cd8SNickeau // https://dev.materialdesignicons.com/contribute/site/api 30737748cd8SNickeau $downloadUrl = "https://materialdesignicons.com/api/download/icon/svg/$iconId"; 30837748cd8SNickeau $filePointer = file_put_contents($mediaFilePath, fopen($downloadUrl, 'r')); 30937748cd8SNickeau if ($filePointer == false) { 31037748cd8SNickeau LogUtility::msg("The file ($downloadUrl) could not be downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_ERROR, self::NAME); 31137748cd8SNickeau } else { 31237748cd8SNickeau LogUtility::msg("The material design icon ($iconName) was downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_INFO, self::NAME); 31337748cd8SNickeau } 31437748cd8SNickeau 31537748cd8SNickeau } 31637748cd8SNickeau 31737748cd8SNickeau } 31837748cd8SNickeau 319*82a60d03SNickeau private static function getLibraries(): array 320c3437056SNickeau { 321*82a60d03SNickeau return array_merge( 322*82a60d03SNickeau self::PUBLIC_LIBRARY_ACRONYM, 323*82a60d03SNickeau self::DEPRECATED_LIBRARY_ACRONYM 324*82a60d03SNickeau ); 325*82a60d03SNickeau } 326*82a60d03SNickeau 327*82a60d03SNickeau /** 328*82a60d03SNickeau * @throws ExceptionCombo 329*82a60d03SNickeau */ 330*82a60d03SNickeau public static function getEmojiCodePoint(string $emojiName) 331*82a60d03SNickeau { 332*82a60d03SNickeau $path = LocalPath::createFromPath(Resources::getDictionaryDirectory() . "/emojis.json"); 333*82a60d03SNickeau $jsonContent = FileSystems::getContent($path); 334*82a60d03SNickeau $jsonArray = Json::createFromString($jsonContent)->toArray(); 335*82a60d03SNickeau return $jsonArray[$emojiName]; 336*82a60d03SNickeau } 337*82a60d03SNickeau 338*82a60d03SNickeau /** 339*82a60d03SNickeau * Iconify normalized the name of the carbon library (making them lowercase) 340*82a60d03SNickeau * 341*82a60d03SNickeau * For instance, CSV is csv (https://icon-sets.iconify.design/carbon/csv/) 342*82a60d03SNickeau * 343*82a60d03SNickeau * This dictionary reproduce it. 344*82a60d03SNickeau * 345*82a60d03SNickeau * @param string $logicalName 346*82a60d03SNickeau * @return mixed 347*82a60d03SNickeau * @throws ExceptionCombo 348*82a60d03SNickeau */ 349*82a60d03SNickeau private static function getCarbonPhysicalName(string $logicalName) 350*82a60d03SNickeau { 351*82a60d03SNickeau $path = LocalPath::createFromPath(Resources::getDictionaryDirectory() . "/carbon-icons.json"); 352*82a60d03SNickeau $jsonContent = FileSystems::getContent($path); 353*82a60d03SNickeau $jsonArray = Json::createFromString($jsonContent)->toArray(); 354*82a60d03SNickeau $physicalName = $jsonArray[$logicalName]; 355*82a60d03SNickeau if ($physicalName === null) { 356*82a60d03SNickeau LogUtility::msg("The icon ($logicalName) is unknown as 32x32 carbon icon"); 357*82a60d03SNickeau // by default, just lowercase 358*82a60d03SNickeau return lower($logicalName); 359*82a60d03SNickeau } 360*82a60d03SNickeau return $physicalName; 361*82a60d03SNickeau } 362*82a60d03SNickeau 363*82a60d03SNickeau /** 364*82a60d03SNickeau * @throws ExceptionCombo 365*82a60d03SNickeau */ 366*82a60d03SNickeau private static function getFadPhysicalName($logicalName) 367*82a60d03SNickeau { 368*82a60d03SNickeau $path = LocalPath::createFromPath(Resources::getDictionaryDirectory() . "/fad-icons.json"); 369*82a60d03SNickeau $jsonContent = FileSystems::getContent($path); 370*82a60d03SNickeau $jsonArray = Json::createFromString($jsonContent)->toArray(); 371*82a60d03SNickeau $physicalName = $jsonArray[$logicalName]; 372*82a60d03SNickeau if ($physicalName === null) { 373*82a60d03SNickeau LogUtility::msg("The icon ($logicalName) is unknown as fad icon"); 374*82a60d03SNickeau return $logicalName; 375*82a60d03SNickeau } 376*82a60d03SNickeau return $physicalName; 377*82a60d03SNickeau } 378*82a60d03SNickeau 379*82a60d03SNickeau 380*82a60d03SNickeau public function render(): string 381*82a60d03SNickeau { 382*82a60d03SNickeau 383*82a60d03SNickeau if (FileSystems::exists($this->getPath())) { 384*82a60d03SNickeau 385*82a60d03SNickeau $svgImageLink = SvgImageLink::createMediaLinkFromPath( 386*82a60d03SNickeau $this->getPath(), 387*82a60d03SNickeau $this->getAttributes() 388*82a60d03SNickeau ); 389*82a60d03SNickeau return $svgImageLink->renderMediaTag(); 390*82a60d03SNickeau 391*82a60d03SNickeau } else { 392*82a60d03SNickeau 393*82a60d03SNickeau LogUtility::msg("The icon ($this) does not exist and cannot be rendered."); 394*82a60d03SNickeau return ""; 395*82a60d03SNickeau 396*82a60d03SNickeau } 397*82a60d03SNickeau 398c3437056SNickeau } 399c3437056SNickeau 40037748cd8SNickeau 40137748cd8SNickeau} 402