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*1fa8c418SNickeaurequire_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 */ 3137748cd8SNickeauclass Icon 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", 4237748cd8SNickeau self::FEATHER => "https://raw.githubusercontent.com/feathericons/feather/master/icons" 4337748cd8SNickeau ); 4437748cd8SNickeau 4537748cd8SNickeau const ICON_LIBRARY_WEBSITE_URLS = array( 4637748cd8SNickeau self::BOOTSTRAP => "https://icons.getbootstrap.com/", 4737748cd8SNickeau self::MATERIAL_DESIGN => "https://materialdesignicons.com/", 4837748cd8SNickeau self::FEATHER => "https://feathericons.com/" 4937748cd8SNickeau ); 5037748cd8SNickeau 5137748cd8SNickeau const CONF_DEFAULT_ICON_LIBRARY = "defaultIconLibrary"; 5237748cd8SNickeau const LIBRARY_ACRONYM = array( 5337748cd8SNickeau "bs" => self::BOOTSTRAP, 5437748cd8SNickeau "md" => self::MATERIAL_DESIGN, 5537748cd8SNickeau "fe" => self::FEATHER 5637748cd8SNickeau ); 5737748cd8SNickeau const FEATHER = "feather"; 5837748cd8SNickeau const BOOTSTRAP = "bootstrap"; 5937748cd8SNickeau const MATERIAL_DESIGN = "material-design"; 6037748cd8SNickeau 6137748cd8SNickeau 6237748cd8SNickeau /** 6337748cd8SNickeau * The function used to render an icon 6437748cd8SNickeau * @param TagAttributes $tagAttributes - the icon attributes 6537748cd8SNickeau * @return bool|mixed - false if any error or the HTML 6637748cd8SNickeau */ 6737748cd8SNickeau static public function renderIconByAttributes($tagAttributes) 6837748cd8SNickeau { 6937748cd8SNickeau 7037748cd8SNickeau 7137748cd8SNickeau $name = "name"; 7237748cd8SNickeau if (!$tagAttributes->hasComponentAttribute($name)) { 7337748cd8SNickeau LogUtility::msg("The attributes should have a name. It's mandatory for an icon.", LogUtility::LVL_MSG_ERROR, self::NAME); 7437748cd8SNickeau return false; 7537748cd8SNickeau } 7637748cd8SNickeau 7737748cd8SNickeau /** 7837748cd8SNickeau * The Name 7937748cd8SNickeau */ 8037748cd8SNickeau $iconNameAttribute = $tagAttributes->getValue($name); 8137748cd8SNickeau 8237748cd8SNickeau /** 8337748cd8SNickeau * If the name have an extension, it's a file from the media directory 8437748cd8SNickeau * Otherwise, it's an icon from a library 8537748cd8SNickeau */ 8637748cd8SNickeau $mediaDokuPath = DokuPath::createMediaPathFromId($iconNameAttribute); 8737748cd8SNickeau if (!empty($mediaDokuPath->getExtension())) { 8837748cd8SNickeau 8937748cd8SNickeau // loop through candidates until a match was found: 9037748cd8SNickeau // May be an icon from the templates 9137748cd8SNickeau if (!$mediaDokuPath->exists()) { 9237748cd8SNickeau 9337748cd8SNickeau // Trying to see if it's not in the template images directory 9437748cd8SNickeau $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."; 9537748cd8SNickeau $message .= "<BR> Media File Library tested: $mediaDokuPath"; 9637748cd8SNickeau LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::NAME); 9737748cd8SNickeau return false; 9837748cd8SNickeau 9937748cd8SNickeau } 10037748cd8SNickeau 10137748cd8SNickeau } else { 10237748cd8SNickeau 10337748cd8SNickeau // It may be a icon already downloaded 10437748cd8SNickeau $iconNameSpace = ConfUtility::getConf(self::CONF_ICONS_MEDIA_NAMESPACE); 10537748cd8SNickeau if (substr($iconNameSpace, 0, 1) != DokuPath::PATH_SEPARATOR) { 10637748cd8SNickeau $iconNameSpace = DokuPath::PATH_SEPARATOR . $iconNameSpace; 10737748cd8SNickeau } 10837748cd8SNickeau if (substr($iconNameSpace, -1) != DokuPath::PATH_SEPARATOR) { 10937748cd8SNickeau $iconNameSpace = $iconNameSpace . ":"; 11037748cd8SNickeau } 11137748cd8SNickeau $mediaPathId = $iconNameSpace . $iconNameAttribute . ".svg"; 11237748cd8SNickeau $mediaDokuPath = DokuPath::createMediaPathFromAbsolutePath($mediaPathId); 11337748cd8SNickeau 11437748cd8SNickeau // Bug: null file created when the stream could not get any byte 11537748cd8SNickeau // We delete them 11637748cd8SNickeau if ($mediaDokuPath->exists()) { 11737748cd8SNickeau if ($mediaDokuPath->getSize() == 0) { 11837748cd8SNickeau $mediaDokuPath->remove(); 11937748cd8SNickeau } 12037748cd8SNickeau } 12137748cd8SNickeau 12237748cd8SNickeau if (!$mediaDokuPath->exists()) { 12337748cd8SNickeau 12437748cd8SNickeau /** 12537748cd8SNickeau * Download the icon 12637748cd8SNickeau */ 12737748cd8SNickeau 12837748cd8SNickeau // Create the target directory if it does not exist 12937748cd8SNickeau $iconDir = $mediaDokuPath->getParent(); 13037748cd8SNickeau if (!$iconDir->exists()) { 13137748cd8SNickeau $filePointer = $iconDir->createAsDirectory(); 13237748cd8SNickeau if ($filePointer == false) { 13337748cd8SNickeau LogUtility::msg("The icon directory ($iconDir) could not be created.", LogUtility::LVL_MSG_ERROR, self::NAME); 13437748cd8SNickeau return false; 13537748cd8SNickeau } 13637748cd8SNickeau } 13737748cd8SNickeau 13837748cd8SNickeau // Name parsing to extract the library name and icon name 13937748cd8SNickeau $sepPosition = strpos($iconNameAttribute, ":"); 14037748cd8SNickeau $library = PluginUtility::getConfValue(self::CONF_DEFAULT_ICON_LIBRARY); 14137748cd8SNickeau $iconName = $iconNameAttribute; 14237748cd8SNickeau if ($sepPosition != false) { 14337748cd8SNickeau $library = substr($iconNameAttribute, 0, $sepPosition); 14437748cd8SNickeau $iconName = substr($iconNameAttribute, $sepPosition + 1); 14537748cd8SNickeau } 14637748cd8SNickeau 14737748cd8SNickeau // Get the qualified library name 14837748cd8SNickeau $acronymLibraries = self::LIBRARY_ACRONYM; 14937748cd8SNickeau if (isset($acronymLibraries[$library])) { 15037748cd8SNickeau $library = $acronymLibraries[$library]; 15137748cd8SNickeau } 15237748cd8SNickeau 15337748cd8SNickeau // Get the url 15437748cd8SNickeau $iconLibraries = self::ICON_LIBRARY_URLS; 15537748cd8SNickeau if (!isset($iconLibraries[$library])) { 15637748cd8SNickeau LogUtility::msg("The icon library ($library) is unknown. The icon could not be downloaded.", LogUtility::LVL_MSG_ERROR, self::NAME); 15737748cd8SNickeau return false; 15837748cd8SNickeau } else { 15937748cd8SNickeau $iconBaseUrl = $iconLibraries[$library]; 16037748cd8SNickeau } 16137748cd8SNickeau 16237748cd8SNickeau // The url 16337748cd8SNickeau $downloadUrl = "$iconBaseUrl/$iconName.svg"; 16437748cd8SNickeau $filePointer = @fopen($downloadUrl, 'r'); 16537748cd8SNickeau if ($filePointer != false) { 16637748cd8SNickeau 16737748cd8SNickeau $numberOfByte = @file_put_contents($mediaDokuPath->getFileSystemPath(), $filePointer); 16837748cd8SNickeau if ($numberOfByte != false) { 16937748cd8SNickeau LogUtility::msg("The icon ($iconName) from the library ($library) was downloaded to ($mediaPathId)", LogUtility::LVL_MSG_INFO, self::NAME); 17037748cd8SNickeau } else { 17137748cd8SNickeau LogUtility::msg("Internal error: The icon ($iconName) from the library ($library) could no be written to ($mediaPathId)", LogUtility::LVL_MSG_ERROR, self::NAME); 17237748cd8SNickeau } 17337748cd8SNickeau 17437748cd8SNickeau } else { 17537748cd8SNickeau 17637748cd8SNickeau // (ie no icon file found at ($downloadUrl) 17737748cd8SNickeau $urlLibrary = self::ICON_LIBRARY_WEBSITE_URLS[$library]; 17837748cd8SNickeau 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); 17937748cd8SNickeau 18037748cd8SNickeau } 18137748cd8SNickeau 18237748cd8SNickeau } 18337748cd8SNickeau 18437748cd8SNickeau } 18537748cd8SNickeau 18637748cd8SNickeau if ($mediaDokuPath->exists()) { 18737748cd8SNickeau 18837748cd8SNickeau 18937748cd8SNickeau /** 19037748cd8SNickeau * After optimization, the width and height of the svg are gone 19137748cd8SNickeau * but the icon type set them again 19237748cd8SNickeau * 19337748cd8SNickeau * The icon type is used to set: 19437748cd8SNickeau * * the default dimension 19537748cd8SNickeau * * color styling 19637748cd8SNickeau * * disable the responsive properties 19737748cd8SNickeau * 19837748cd8SNickeau */ 19937748cd8SNickeau $tagAttributes->addComponentAttributeValue("type", SvgDocument::ICON_TYPE); 20037748cd8SNickeau 20137748cd8SNickeau 20237748cd8SNickeau $svgImageLink = SvgImageLink::createMediaLinkFromNonQualifiedPath( 20337748cd8SNickeau $mediaDokuPath->getAbsolutePath(), 20437748cd8SNickeau null, 20537748cd8SNickeau $tagAttributes 20637748cd8SNickeau ); 20737748cd8SNickeau return $svgImageLink->renderMediaTag(); 20837748cd8SNickeau 20937748cd8SNickeau } else { 21037748cd8SNickeau 21137748cd8SNickeau return ""; 21237748cd8SNickeau 21337748cd8SNickeau } 21437748cd8SNickeau 21537748cd8SNickeau 21637748cd8SNickeau } 21737748cd8SNickeau 21837748cd8SNickeau /** 21937748cd8SNickeau * @param $iconName 22037748cd8SNickeau * @param $mediaFilePath 22137748cd8SNickeau * @deprecated Old code to download icon from the material design api 22237748cd8SNickeau */ 22337748cd8SNickeau public 22437748cd8SNickeau static function downloadIconFromMaterialDesignApi($iconName, $mediaFilePath) 22537748cd8SNickeau { 22637748cd8SNickeau // Try the official API 22737748cd8SNickeau // Read the icon meta of 22837748cd8SNickeau // Meta Json file got all icons 22937748cd8SNickeau // 23037748cd8SNickeau // * Available at: https://raw.githubusercontent.com/Templarian/MaterialDesign/master/meta.json 23137748cd8SNickeau // * See doc: https://github.com/Templarian/MaterialDesign-Site/blob/master/src/content/api.md) 23237748cd8SNickeau $arrayFormat = true; 23337748cd8SNickeau $iconMetaJson = json_decode(file_get_contents(__DIR__ . '/icon-meta.json'), $arrayFormat); 23437748cd8SNickeau $iconId = null; 23537748cd8SNickeau foreach ($iconMetaJson as $key => $value) { 23637748cd8SNickeau if ($value['name'] == $iconName) { 23737748cd8SNickeau $iconId = $value['id']; 23837748cd8SNickeau break; 23937748cd8SNickeau } 24037748cd8SNickeau } 24137748cd8SNickeau if ($iconId != null) { 24237748cd8SNickeau 24337748cd8SNickeau // Download 24437748cd8SNickeau // Call to the API 24537748cd8SNickeau // https://dev.materialdesignicons.com/contribute/site/api 24637748cd8SNickeau $downloadUrl = "https://materialdesignicons.com/api/download/icon/svg/$iconId"; 24737748cd8SNickeau $filePointer = file_put_contents($mediaFilePath, fopen($downloadUrl, 'r')); 24837748cd8SNickeau if ($filePointer == false) { 24937748cd8SNickeau LogUtility::msg("The file ($downloadUrl) could not be downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_ERROR, self::NAME); 25037748cd8SNickeau } else { 25137748cd8SNickeau LogUtility::msg("The material design icon ($iconName) was downloaded to ($mediaFilePath)", LogUtility::LVL_MSG_INFO, self::NAME); 25237748cd8SNickeau } 25337748cd8SNickeau 25437748cd8SNickeau } 25537748cd8SNickeau 25637748cd8SNickeau } 25737748cd8SNickeau 25837748cd8SNickeau 25937748cd8SNickeau} 260