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