1<?php 2/** 3 * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4 * 5 * This source code is licensed under the GPL license found in the 6 * COPYING file in the root directory of this source tree. 7 * 8 * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9 * @author ComboStrap <support@combostrap.com> 10 * 11 */ 12 13namespace ComboStrap; 14 15require_once(__DIR__ . '/ConfUtility.php'); 16require_once(__DIR__ . '/SvgImageLink.php'); 17 18 19/** 20 * Class IconUtility 21 * @package ComboStrap 22 * @see https://combostrap.com/icon 23 * 24 * 25 * Material design does not have a repository structure where we can extract the location 26 * from the name 27 * https://material.io/resources/icons https://google.github.io/material-design-icons/ 28 * 29 * Injection via javascript to avoid problem with the php svgsimple library 30 * https://www.npmjs.com/package/svg-injector 31 */ 32class Icon 33{ 34 const CONF_ICONS_MEDIA_NAMESPACE = "icons_namespace"; 35 const CONF_ICONS_MEDIA_NAMESPACE_DEFAULT = ":" . PluginUtility::COMBOSTRAP_NAMESPACE_NAME . ":icons"; 36 // Canonical name 37 const NAME = "icon"; 38 39 40 const ICON_LIBRARY_URLS = array( 41 self::BOOTSTRAP => "https://raw.githubusercontent.com/twbs/icons/main/icons", 42 self::MATERIAL_DESIGN => "https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg", 43 self::FEATHER => "https://raw.githubusercontent.com/feathericons/feather/master/icons" 44 ); 45 46 const ICON_LIBRARY_WEBSITE_URLS = array( 47 self::BOOTSTRAP => "https://icons.getbootstrap.com/", 48 self::MATERIAL_DESIGN => "https://materialdesignicons.com/", 49 self::FEATHER => "https://feathericons.com/" 50 ); 51 52 const CONF_DEFAULT_ICON_LIBRARY = "defaultIconLibrary"; 53 const LIBRARY_ACRONYM = array( 54 "bs" => self::BOOTSTRAP, 55 "md" => self::MATERIAL_DESIGN, 56 "fe" => self::FEATHER 57 ); 58 const FEATHER = "feather"; 59 const BOOTSTRAP = "bootstrap"; 60 const MATERIAL_DESIGN = "material-design"; 61 62 63 /** 64 * The function used to render an icon 65 * @param TagAttributes $tagAttributes - the icon attributes 66 * @return bool|mixed - false if any error or the HTML 67 */ 68 static public function renderIconByAttributes($tagAttributes) 69 { 70 71 72 $name = "name"; 73 if (!$tagAttributes->hasComponentAttribute($name)) { 74 LogUtility::msg("The attributes should have a name. It's mandatory for an icon.", LogUtility::LVL_MSG_ERROR, self::NAME); 75 return false; 76 } 77 78 /** 79 * The Name 80 */ 81 $iconNameAttribute = $tagAttributes->getValue($name); 82 83 /** 84 * If the name have an extension, it's a file from the media directory 85 * Otherwise, it's an icon from a library 86 */ 87 $mediaDokuPath = DokuPath::createMediaPathFromId($iconNameAttribute); 88 if (!empty($mediaDokuPath->getExtension())) { 89 90 // loop through candidates until a match was found: 91 // May be an icon from the templates 92 if (!$mediaDokuPath->exists()) { 93 94 // Trying to see if it's not in the template images directory 95 $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."; 96 $message .= "<BR> Media File Library tested: $mediaDokuPath"; 97 LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::NAME); 98 return false; 99 100 } 101 102 } else { 103 104 // It may be a icon already downloaded 105 $iconNameSpace = ConfUtility::getConf(self::CONF_ICONS_MEDIA_NAMESPACE); 106 if (substr($iconNameSpace, 0, 1) != DokuPath::PATH_SEPARATOR) { 107 $iconNameSpace = DokuPath::PATH_SEPARATOR . $iconNameSpace; 108 } 109 if (substr($iconNameSpace, -1) != DokuPath::PATH_SEPARATOR) { 110 $iconNameSpace = $iconNameSpace . ":"; 111 } 112 $mediaPathId = $iconNameSpace . $iconNameAttribute . ".svg"; 113 $mediaDokuPath = DokuPath::createMediaPathFromAbsolutePath($mediaPathId); 114 115 // Bug: null file created when the stream could not get any byte 116 // We delete them 117 if ($mediaDokuPath->exists()) { 118 if ($mediaDokuPath->getSize() == 0) { 119 $mediaDokuPath->remove(); 120 } 121 } 122 123 if (!$mediaDokuPath->exists()) { 124 125 /** 126 * Download the icon 127 */ 128 129 // Create the target directory if it does not exist 130 $iconDir = $mediaDokuPath->getParent(); 131 if (!$iconDir->exists()) { 132 $filePointer = $iconDir->createAsDirectory(); 133 if ($filePointer == false) { 134 LogUtility::msg("The icon directory ($iconDir) could not be created.", LogUtility::LVL_MSG_ERROR, self::NAME); 135 return false; 136 } 137 } 138 139 // Name parsing to extract the library name and icon name 140 $sepPosition = strpos($iconNameAttribute, ":"); 141 $library = PluginUtility::getConfValue(self::CONF_DEFAULT_ICON_LIBRARY); 142 $iconName = $iconNameAttribute; 143 if ($sepPosition != false) { 144 $library = substr($iconNameAttribute, 0, $sepPosition); 145 $iconName = substr($iconNameAttribute, $sepPosition + 1); 146 } 147 148 // Get the qualified library name 149 $acronymLibraries = self::LIBRARY_ACRONYM; 150 if (isset($acronymLibraries[$library])) { 151 $library = $acronymLibraries[$library]; 152 } 153 154 // Get the url 155 $iconLibraries = self::ICON_LIBRARY_URLS; 156 if (!isset($iconLibraries[$library])) { 157 LogUtility::msg("The icon library ($library) is unknown. The icon could not be downloaded.", LogUtility::LVL_MSG_ERROR, self::NAME); 158 return false; 159 } else { 160 $iconBaseUrl = $iconLibraries[$library]; 161 } 162 163 // The url 164 $downloadUrl = "$iconBaseUrl/$iconName.svg"; 165 $filePointer = @fopen($downloadUrl, 'r'); 166 if ($filePointer != false) { 167 168 $numberOfByte = @file_put_contents($mediaDokuPath->getFileSystemPath(), $filePointer); 169 if ($numberOfByte != false) { 170 LogUtility::msg("The icon ($iconName) from the library ($library) was downloaded to ($mediaPathId)", LogUtility::LVL_MSG_INFO, self::NAME); 171 } else { 172 LogUtility::msg("Internal error: The icon ($iconName) from the library ($library) could no be written to ($mediaPathId)", LogUtility::LVL_MSG_ERROR, self::NAME); 173 } 174 175 } else { 176 177 // (ie no icon file found at ($downloadUrl) 178 $urlLibrary = self::ICON_LIBRARY_WEBSITE_URLS[$library]; 179 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); 180 181 } 182 183 } 184 185 } 186 187 if ($mediaDokuPath->exists()) { 188 189 190 /** 191 * After optimization, the width and height of the svg are gone 192 * but the icon type set them again 193 * 194 * The icon type is used to set: 195 * * the default dimension 196 * * color styling 197 * * disable the responsive properties 198 * 199 */ 200 $tagAttributes->addComponentAttributeValue("type", SvgDocument::ICON_TYPE); 201 202 203 $svgImageLink = SvgImageLink::createMediaLinkFromNonQualifiedPath( 204 $mediaDokuPath->getAbsolutePath(), 205 null, 206 $tagAttributes 207 ); 208 return $svgImageLink->renderMediaTag(); 209 210 } else { 211 212 return ""; 213 214 } 215 216 217 } 218 219 /** 220 * @param $iconName 221 * @param $mediaFilePath 222 * @deprecated Old code to download icon from the material design api 223 */ 224 public 225 static function downloadIconFromMaterialDesignApi($iconName, $mediaFilePath) 226 { 227 // Try the official API 228 // Read the icon meta of 229 // Meta Json file got all icons 230 // 231 // * Available at: https://raw.githubusercontent.com/Templarian/MaterialDesign/master/meta.json 232 // * See doc: https://github.com/Templarian/MaterialDesign-Site/blob/master/src/content/api.md) 233 $arrayFormat = true; 234 $iconMetaJson = json_decode(file_get_contents(__DIR__ . '/icon-meta.json'), $arrayFormat); 235 $iconId = null; 236 foreach ($iconMetaJson as $key => $value) { 237 if ($value['name'] == $iconName) { 238 $iconId = $value['id']; 239 break; 240 } 241 } 242 if ($iconId != null) { 243 244 // Download 245 // Call to the API 246 // https://dev.materialdesignicons.com/contribute/site/api 247 $downloadUrl = "https://materialdesignicons.com/api/download/icon/svg/$iconId"; 248 $filePointer = file_put_contents($mediaFilePath, fopen($downloadUrl, 'r')); 249 if ($filePointer == false) { 250 LogUtility::msg("The file ($downloadUrl) could not be downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_ERROR, self::NAME); 251 } else { 252 LogUtility::msg("The material design icon ($iconName) was downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_INFO, self::NAME); 253 } 254 255 } 256 257 } 258 259 260} 261