137748cd8SNickeau<?php 237748cd8SNickeau 337748cd8SNickeau 437748cd8SNickeaunamespace ComboStrap; 537748cd8SNickeau 637748cd8SNickeau 737748cd8SNickeauuse dokuwiki\Extension\Plugin; 837748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin; 9*4cadd4f8SNickeauuse PHPUnit\Exception; 1037748cd8SNickeau 1137748cd8SNickeaurequire_once(__DIR__ . '/../vendor/autoload.php'); 1237748cd8SNickeau 1337748cd8SNickeau/** 141fa8c418SNickeau * Parent in th hierarchy should be first 151fa8c418SNickeau * Ie before {@link ImageLink, SvgImageLink, RasterImageLink) 161fa8c418SNickeau */ 17c3437056SNickeaurequire_once(__DIR__ . '/CachedDocument.php'); 18c3437056SNickeaurequire_once(__DIR__ . '/PageCompilerDocument.php'); 19c3437056SNickeaurequire_once(__DIR__ . '/OutputDocument.php'); 20c3437056SNickeaurequire_once(__DIR__ . '/FileSystem.php'); 21c3437056SNickeaurequire_once(__DIR__ . '/Path.php'); 22c3437056SNickeaurequire_once(__DIR__ . '/PathAbs.php'); 23c3437056SNickeaurequire_once(__DIR__ . '/File.php'); 24c3437056SNickeaurequire_once(__DIR__ . '/DokuFs.php'); 251fa8c418SNickeaurequire_once(__DIR__ . '/DokuPath.php'); 26c3437056SNickeaurequire_once(__DIR__ . '/ResourceCombo.php'); 27c3437056SNickeaurequire_once(__DIR__ . '/ResourceComboAbs.php'); 281fa8c418SNickeaurequire_once(__DIR__ . '/Media.php'); 291fa8c418SNickeaurequire_once(__DIR__ . '/MediaLink.php'); 30c3437056SNickeaurequire_once(__DIR__ . '/Metadata.php'); 31c3437056SNickeaurequire_once(__DIR__ . '/MetadataBoolean.php'); 32c3437056SNickeaurequire_once(__DIR__ . '/MetadataDateTime.php'); 33c3437056SNickeaurequire_once(__DIR__ . '/MetadataMultiple.php'); 34c3437056SNickeaurequire_once(__DIR__ . '/MetadataTabular.php'); 35c3437056SNickeaurequire_once(__DIR__ . '/MetadataText.php'); 36c3437056SNickeaurequire_once(__DIR__ . '/MetadataJson.php'); 37c3437056SNickeaurequire_once(__DIR__ . '/MetadataWikiPath.php'); 38c3437056SNickeaurequire_once(__DIR__ . '/MetadataStore.php'); 39c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreAbs.php'); 40c3437056SNickeaurequire_once(__DIR__ . '/MetadataSingleArrayStore.php'); 41*4cadd4f8SNickeaurequire_once(__DIR__ . '/XmlDocument.php'); 421fa8c418SNickeau 431fa8c418SNickeau/** 4437748cd8SNickeau * Plugin Utility is added in all Dokuwiki extension 4537748cd8SNickeau * and 4637748cd8SNickeau * all classes are added in plugin utility 4737748cd8SNickeau * 4837748cd8SNickeau * This is an utility master and the class loader 4937748cd8SNickeau * 5037748cd8SNickeau * If the load is relative, the load path is used 5137748cd8SNickeau * and the bad php file may be loaded 5237748cd8SNickeau * Furthermore, the absolute path helps 5337748cd8SNickeau * the IDE when refactoring 5437748cd8SNickeau */ 5537748cd8SNickeaurequire_once(__DIR__ . '/AdsUtility.php'); 56c3437056SNickeaurequire_once(__DIR__ . '/Alias.php'); 57c3437056SNickeaurequire_once(__DIR__ . '/AliasPath.php'); 58c3437056SNickeaurequire_once(__DIR__ . '/AliasType.php'); 59c3437056SNickeaurequire_once(__DIR__ . '/Aliases.php'); 6037748cd8SNickeaurequire_once(__DIR__ . '/Align.php'); 61c3437056SNickeaurequire_once(__DIR__ . '/AnalyticsDocument.php'); 6237748cd8SNickeaurequire_once(__DIR__ . '/AnalyticsMenuItem.php'); 6337748cd8SNickeaurequire_once(__DIR__ . '/Animation.php'); 6437748cd8SNickeaurequire_once(__DIR__ . '/ArrayCaseInsensitive.php'); 6537748cd8SNickeaurequire_once(__DIR__ . '/ArrayUtility.php'); 6637748cd8SNickeaurequire_once(__DIR__ . '/Background.php'); 67c3437056SNickeaurequire_once(__DIR__ . '/BacklinkCount.php'); 68c3437056SNickeaurequire_once(__DIR__ . '/BacklinkMenuItem.php'); 6937748cd8SNickeaurequire_once(__DIR__ . '/Boldness.php'); 70c3437056SNickeaurequire_once(__DIR__ . '/Boolean.php'); 7137748cd8SNickeaurequire_once(__DIR__ . '/Bootstrap.php'); 72*4cadd4f8SNickeaurequire_once(__DIR__ . '/Brand.php'); 73*4cadd4f8SNickeaurequire_once(__DIR__ . '/BrandButton.php'); 74*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheDependencies.php'); 75c3437056SNickeaurequire_once(__DIR__ . '/CacheExpirationDate.php'); 76c3437056SNickeaurequire_once(__DIR__ . '/CacheExpirationFrequency.php'); 77*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheLog.php'); 7837748cd8SNickeaurequire_once(__DIR__ . '/CacheManager.php'); 7937748cd8SNickeaurequire_once(__DIR__ . '/CacheMedia.php'); 80*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheMenuItem.php'); 81*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheReportHtmlDataBlockArray.php'); 82*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheResults.php'); 83*4cadd4f8SNickeaurequire_once(__DIR__ . '/CacheResult.php'); 8437748cd8SNickeaurequire_once(__DIR__ . '/Call.php'); 8537748cd8SNickeaurequire_once(__DIR__ . '/CallStack.php'); 86c3437056SNickeaurequire_once(__DIR__ . '/Canonical.php'); 87*4cadd4f8SNickeaurequire_once(__DIR__ . '/ColorRgb.php'); 88*4cadd4f8SNickeaurequire_once(__DIR__ . '/ColorHsl.php'); 89*4cadd4f8SNickeaurequire_once(__DIR__ . '/ComboStrap.php'); 9037748cd8SNickeaurequire_once(__DIR__ . '/ConditionalValue.php'); 91c3437056SNickeaurequire_once(__DIR__ . '/Console.php'); 92c3437056SNickeaurequire_once(__DIR__ . '/Cron.php'); 93c3437056SNickeaurequire_once(__DIR__ . '/DatabasePageRow.php'); 94c3437056SNickeaurequire_once(__DIR__ . '/DataType.php'); 95*4cadd4f8SNickeaurequire_once(__DIR__ . '/Dictionary.php'); 9637748cd8SNickeaurequire_once(__DIR__ . '/Dimension.php'); 97c3437056SNickeaurequire_once(__DIR__ . '/DisqusIdentifier.php'); 98*4cadd4f8SNickeaurequire_once(__DIR__ . '/Display.php'); 9937748cd8SNickeaurequire_once(__DIR__ . '/DokuwikiUrl.php'); 100c3437056SNickeaurequire_once(__DIR__ . '/DokuwikiId.php'); 101c3437056SNickeaurequire_once(__DIR__ . '/EndDate.php'); 102c3437056SNickeaurequire_once(__DIR__ . '/Event.php'); 1031fa8c418SNickeaurequire_once(__DIR__ . '/ExitException.php'); 104c3437056SNickeaurequire_once(__DIR__ . '/ExceptionCombo.php'); 105*4cadd4f8SNickeaurequire_once(__DIR__ . '/ExceptionComboNotFound.php'); 106c3437056SNickeaurequire_once(__DIR__ . '/ExceptionComboRuntime.php'); 107c3437056SNickeaurequire_once(__DIR__ . '/FileSystems.php'); 10837748cd8SNickeaurequire_once(__DIR__ . '/FloatAttribute.php'); 109c3437056SNickeaurequire_once(__DIR__ . '/FormMeta.php'); 110c3437056SNickeaurequire_once(__DIR__ . '/FormMetaTab.php'); 111c3437056SNickeaurequire_once(__DIR__ . '/FormMetaField.php'); 11237748cd8SNickeaurequire_once(__DIR__ . '/FontSize.php'); 11337748cd8SNickeaurequire_once(__DIR__ . '/FsWikiUtility.php'); 11437748cd8SNickeaurequire_once(__DIR__ . '/HeaderUtility.php'); 115c3437056SNickeaurequire_once(__DIR__ . '/HtmlDocument.php'); 11637748cd8SNickeaurequire_once(__DIR__ . '/HistoricalBreadcrumbMenuItem.php'); 11737748cd8SNickeaurequire_once(__DIR__ . '/Hover.php'); 118c3437056SNickeaurequire_once(__DIR__ . '/Html.php'); 11937748cd8SNickeaurequire_once(__DIR__ . '/Http.php'); 120c3437056SNickeaurequire_once(__DIR__ . '/HttpResponse.php'); 12137748cd8SNickeaurequire_once(__DIR__ . '/Identity.php'); 1221fa8c418SNickeaurequire_once(__DIR__ . '/Image.php'); 1231fa8c418SNickeaurequire_once(__DIR__ . '/ImageLink.php'); 1241fa8c418SNickeaurequire_once(__DIR__ . '/ImageRaster.php'); 1251fa8c418SNickeaurequire_once(__DIR__ . '/ImageSvg.php'); 12682a60d03SNickeaurequire_once(__DIR__ . '/Icon.php'); // icon is an image svg and should be after 127c3437056SNickeaurequire_once(__DIR__ . '/Index.php'); 128c3437056SNickeaurequire_once(__DIR__ . '/InstructionsDocument.php'); 129c3437056SNickeaurequire_once(__DIR__ . '/InternetPath.php'); 130c3437056SNickeaurequire_once(__DIR__ . '/InterWikiPath.php'); 13137748cd8SNickeaurequire_once(__DIR__ . '/Iso8601Date.php'); 1321fa8c418SNickeaurequire_once(__DIR__ . '/Json.php'); 133c3437056SNickeaurequire_once(__DIR__ . '/JavascriptLibrary.php'); 13437748cd8SNickeaurequire_once(__DIR__ . '/Lang.php'); 135c3437056SNickeaurequire_once(__DIR__ . '/LdJson.php'); 13637748cd8SNickeaurequire_once(__DIR__ . '/LineSpacing.php'); 137c3437056SNickeaurequire_once(__DIR__ . '/Locale.php'); 138c3437056SNickeaurequire_once(__DIR__ . '/LocalFs.php'); 139c3437056SNickeaurequire_once(__DIR__ . '/LocalPath.php'); 1401fa8c418SNickeaurequire_once(__DIR__ . '/LogException.php'); 14137748cd8SNickeaurequire_once(__DIR__ . '/LogUtility.php'); 14237748cd8SNickeaurequire_once(__DIR__ . '/LowQualityPage.php'); 143c3437056SNickeaurequire_once(__DIR__ . '/LowQualityPageOverwrite.php'); 144c3437056SNickeaurequire_once(__DIR__ . '/LowQualityCalculatedIndicator.php'); 145*4cadd4f8SNickeaurequire_once(__DIR__ . '/MarkupRef.php'); 146*4cadd4f8SNickeaurequire_once(__DIR__ . '/Math.php'); 147c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerForm.php'); 148c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerMenuItem.php'); 149c3437056SNickeaurequire_once(__DIR__ . '/MetadataDokuWikiStore.php'); 150c3437056SNickeaurequire_once(__DIR__ . '/MetadataFormDataStore.php'); 151c3437056SNickeaurequire_once(__DIR__ . '/MetadataFrontmatterStore.php'); 152c3437056SNickeaurequire_once(__DIR__ . '/MetadataDbStore.php'); 153c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreTransfer.php'); 1541fa8c418SNickeaurequire_once(__DIR__ . '/Message.php'); 1551fa8c418SNickeaurequire_once(__DIR__ . '/Mermaid.php'); 156c3437056SNickeaurequire_once(__DIR__ . '/Mime.php'); 157c3437056SNickeaurequire_once(__DIR__ . '/ModificationDate.php'); 15837748cd8SNickeaurequire_once(__DIR__ . '/NavBarUtility.php'); 15937748cd8SNickeaurequire_once(__DIR__ . '/Opacity.php'); 1601fa8c418SNickeaurequire_once(__DIR__ . '/Os.php'); 16137748cd8SNickeaurequire_once(__DIR__ . '/Page.php'); 162c3437056SNickeaurequire_once(__DIR__ . '/PageDescription.php'); 163*4cadd4f8SNickeaurequire_once(__DIR__ . '/PageEdit.php'); 164c3437056SNickeaurequire_once(__DIR__ . '/PageId.php'); 165c3437056SNickeaurequire_once(__DIR__ . '/PageKeywords.php'); 166c3437056SNickeaurequire_once(__DIR__ . '/PageImages.php'); 167c3437056SNickeaurequire_once(__DIR__ . '/PageImage.php'); 168c3437056SNickeaurequire_once(__DIR__ . '/PageImagePath.php'); 169c3437056SNickeaurequire_once(__DIR__ . '/PageImageUsage.php'); 170c3437056SNickeaurequire_once(__DIR__ . '/PageLayout.php'); 171c3437056SNickeaurequire_once(__DIR__ . '/PagePath.php'); 17237748cd8SNickeaurequire_once(__DIR__ . '/PageProtection.php'); 17337748cd8SNickeaurequire_once(__DIR__ . '/PageRules.php'); 17437748cd8SNickeaurequire_once(__DIR__ . '/PageSql.php'); 17537748cd8SNickeaurequire_once(__DIR__ . '/PageSqlParser/PageSqlLexer.php'); 17637748cd8SNickeaurequire_once(__DIR__ . '/PageSqlParser/PageSqlParser.php'); 17737748cd8SNickeaurequire_once(__DIR__ . '/PageSqlTreeListener.php'); 178c3437056SNickeaurequire_once(__DIR__ . '/PageType.php'); 179c3437056SNickeaurequire_once(__DIR__ . '/PageTitle.php'); 180c3437056SNickeaurequire_once(__DIR__ . '/PageUrlPath.php'); 181c3437056SNickeaurequire_once(__DIR__ . '/PageUrlType.php'); 18237748cd8SNickeaurequire_once(__DIR__ . '/PipelineUtility.php'); 18337748cd8SNickeaurequire_once(__DIR__ . '/Position.php'); 18437748cd8SNickeaurequire_once(__DIR__ . '/Prism.php'); 185c3437056SNickeaurequire_once(__DIR__ . '/PagePublicationDate.php'); 186c3437056SNickeaurequire_once(__DIR__ . '/PageCreationDate.php'); 187c3437056SNickeaurequire_once(__DIR__ . '/PageH1.php'); 188c3437056SNickeaurequire_once(__DIR__ . '/QualityDynamicMonitoringOverwrite.php'); 189c3437056SNickeaurequire_once(__DIR__ . '/QualityMenuItem.php'); 19037748cd8SNickeaurequire_once(__DIR__ . '/RasterImageLink.php'); 191c3437056SNickeaurequire_once(__DIR__ . '/Region.php'); 19237748cd8SNickeaurequire_once(__DIR__ . '/RenderUtility.php'); 193c3437056SNickeaurequire_once(__DIR__ . '/ReplicationDate.php'); 194c3437056SNickeaurequire_once(__DIR__ . '/ResourceName.php'); 1951fa8c418SNickeaurequire_once(__DIR__ . '/Sanitizer.php'); 19637748cd8SNickeaurequire_once(__DIR__ . '/Shadow.php'); 19737748cd8SNickeaurequire_once(__DIR__ . '/Site.php'); 19837748cd8SNickeaurequire_once(__DIR__ . '/Skin.php'); 199c3437056SNickeaurequire_once(__DIR__ . '/Slug.php'); 20037748cd8SNickeaurequire_once(__DIR__ . '/Snippet.php'); 20137748cd8SNickeaurequire_once(__DIR__ . '/SnippetManager.php'); 20237748cd8SNickeaurequire_once(__DIR__ . '/Spacing.php'); 20337748cd8SNickeaurequire_once(__DIR__ . '/Sqlite.php'); 204c3437056SNickeaurequire_once(__DIR__ . '/SqliteRequest.php'); 205c3437056SNickeaurequire_once(__DIR__ . '/SqliteResult.php'); 20637748cd8SNickeaurequire_once(__DIR__ . '/StringUtility.php'); 207c3437056SNickeaurequire_once(__DIR__ . '/StartDate.php'); 20837748cd8SNickeaurequire_once(__DIR__ . '/StyleUtility.php'); 20937748cd8SNickeaurequire_once(__DIR__ . '/SvgDocument.php'); 21037748cd8SNickeaurequire_once(__DIR__ . '/SvgImageLink.php'); 21137748cd8SNickeaurequire_once(__DIR__ . '/Syntax.php'); 21237748cd8SNickeaurequire_once(__DIR__ . '/TableUtility.php'); 21337748cd8SNickeaurequire_once(__DIR__ . '/Tag.php'); 21437748cd8SNickeaurequire_once(__DIR__ . '/TagAttributes.php'); 21537748cd8SNickeaurequire_once(__DIR__ . '/Template.php'); 216c3437056SNickeaurequire_once(__DIR__ . '/TemplateStore.php'); 21737748cd8SNickeaurequire_once(__DIR__ . '/TemplateUtility.php'); 21837748cd8SNickeaurequire_once(__DIR__ . '/TextAlign.php'); 21937748cd8SNickeaurequire_once(__DIR__ . '/TextColor.php'); 220c3437056SNickeaurequire_once(__DIR__ . '/ThirdMedia.php'); 22137748cd8SNickeaurequire_once(__DIR__ . '/ThirdMediaLink.php'); 22237748cd8SNickeaurequire_once(__DIR__ . '/ThirdPartyPlugins.php'); 22337748cd8SNickeaurequire_once(__DIR__ . '/TocUtility.php'); 22437748cd8SNickeaurequire_once(__DIR__ . '/Toggle.php'); 225*4cadd4f8SNickeaurequire_once(__DIR__ . '/Tooltip.php'); 226c3437056SNickeaurequire_once(__DIR__ . '/References.php'); 227c3437056SNickeaurequire_once(__DIR__ . '/Reference.php'); 22837748cd8SNickeaurequire_once(__DIR__ . '/Underline.php'); 22937748cd8SNickeaurequire_once(__DIR__ . '/Unit.php'); 230c3437056SNickeaurequire_once(__DIR__ . '/Url.php'); 23137748cd8SNickeaurequire_once(__DIR__ . '/UrlManagerBestEndPage.php'); 23237748cd8SNickeaurequire_once(__DIR__ . '/XhtmlUtility.php'); 23337748cd8SNickeaurequire_once(__DIR__ . '/XmlDocument.php'); 23437748cd8SNickeaurequire_once(__DIR__ . '/XmlUtility.php'); 23537748cd8SNickeau 23637748cd8SNickeau 23737748cd8SNickeau/** 23837748cd8SNickeau * Class url static 23937748cd8SNickeau * List of static utilities 24037748cd8SNickeau */ 24137748cd8SNickeauclass PluginUtility 24237748cd8SNickeau{ 24337748cd8SNickeau 24437748cd8SNickeau const DOKU_DATA_DIR = '/dokudata/pages'; 24537748cd8SNickeau const DOKU_CACHE_DIR = '/dokudata/cache'; 24637748cd8SNickeau 24737748cd8SNickeau /** 24837748cd8SNickeau * Key in the data array between the handle and render function 24937748cd8SNickeau */ 25037748cd8SNickeau const STATE = "state"; 25137748cd8SNickeau const PAYLOAD = "payload"; // The html or text 25237748cd8SNickeau const ATTRIBUTES = "attributes"; 25337748cd8SNickeau // The context is generally the parent tag but it may be also the grandfather. 25437748cd8SNickeau // It permits to determine the HTML that is outputted 25537748cd8SNickeau const CONTEXT = 'context'; 25637748cd8SNickeau const TAG = "tag"; 25737748cd8SNickeau 25837748cd8SNickeau /** 25937748cd8SNickeau * The name of the hidden/private namespace 26037748cd8SNickeau * where the icon and other artifactory are stored 26137748cd8SNickeau */ 26237748cd8SNickeau const COMBOSTRAP_NAMESPACE_NAME = "combostrap"; 26337748cd8SNickeau 26437748cd8SNickeau const PARENT = "parent"; 26537748cd8SNickeau const POSITION = "position"; 26637748cd8SNickeau 26737748cd8SNickeau /** 26837748cd8SNickeau * Class to center an element 26937748cd8SNickeau */ 27037748cd8SNickeau const CENTER_CLASS = "mx-auto"; 27137748cd8SNickeau 27237748cd8SNickeau 27337748cd8SNickeau const EDIT_SECTION_TARGET = 'section'; 274*4cadd4f8SNickeau const EXIT_MESSAGE = "errorAtt"; 275*4cadd4f8SNickeau const EXIT_CODE = "exit_code"; 2761fa8c418SNickeau const DISPLAY = "display"; 27737748cd8SNickeau 27837748cd8SNickeau /** 27937748cd8SNickeau * The URL base of the documentation 28037748cd8SNickeau */ 281c3437056SNickeau static $URL_APEX; 28237748cd8SNickeau 28337748cd8SNickeau 28437748cd8SNickeau /** 28537748cd8SNickeau * @var string - the plugin base name (ie the directory) 28637748cd8SNickeau * ie $INFO_PLUGIN['base']; 28737748cd8SNickeau * This is a constant because it permits code analytics 28837748cd8SNickeau * such as verification of a path 28937748cd8SNickeau */ 29037748cd8SNickeau const PLUGIN_BASE_NAME = "combo"; 29137748cd8SNickeau 29237748cd8SNickeau /** 29337748cd8SNickeau * The name of the template plugin 29437748cd8SNickeau */ 29537748cd8SNickeau const TEMPLATE_STRAP_NAME = "strap"; 29637748cd8SNickeau 29737748cd8SNickeau /** 29837748cd8SNickeau * @var array 29937748cd8SNickeau */ 30037748cd8SNickeau static $INFO_PLUGIN; 30137748cd8SNickeau 30237748cd8SNickeau static $PLUGIN_LANG; 30337748cd8SNickeau 30437748cd8SNickeau /** 30537748cd8SNickeau * The plugin name 30637748cd8SNickeau * (not the same than the base as it's not related to the directory 30737748cd8SNickeau * @var string 30837748cd8SNickeau */ 30937748cd8SNickeau public static $PLUGIN_NAME; 31037748cd8SNickeau /** 31137748cd8SNickeau * @var mixed the version 31237748cd8SNickeau */ 31337748cd8SNickeau private static $VERSION; 31437748cd8SNickeau 31537748cd8SNickeau 31637748cd8SNickeau /** 31737748cd8SNickeau * Initiate the static variable 31837748cd8SNickeau * See the call after this class 31937748cd8SNickeau */ 32037748cd8SNickeau static function init() 32137748cd8SNickeau { 32237748cd8SNickeau 32337748cd8SNickeau $pluginInfoFile = __DIR__ . '/../plugin.info.txt'; 32437748cd8SNickeau self::$INFO_PLUGIN = confToHash($pluginInfoFile); 32537748cd8SNickeau self::$PLUGIN_NAME = 'ComboStrap'; 32637748cd8SNickeau global $lang; 32737748cd8SNickeau self::$PLUGIN_LANG = $lang[self::PLUGIN_BASE_NAME]; 328c3437056SNickeau self::$URL_APEX = "https://" . parse_url(self::$INFO_PLUGIN['url'], PHP_URL_HOST); 32937748cd8SNickeau self::$VERSION = self::$INFO_PLUGIN['version']; 33037748cd8SNickeau 33137748cd8SNickeau } 33237748cd8SNickeau 33337748cd8SNickeau /** 33437748cd8SNickeau * @param $inputExpression 33537748cd8SNickeau * @return false|int 1|0 33637748cd8SNickeau * returns: 33737748cd8SNickeau * - 1 if the input expression is a pattern, 33837748cd8SNickeau * - 0 if not, 33937748cd8SNickeau * - FALSE if an error occurred. 34037748cd8SNickeau */ 34137748cd8SNickeau static function isRegularExpression($inputExpression) 34237748cd8SNickeau { 34337748cd8SNickeau 34437748cd8SNickeau $regularExpressionPattern = "/(\\/.*\\/[gmixXsuUAJ]?)/"; 34537748cd8SNickeau return preg_match($regularExpressionPattern, $inputExpression); 34637748cd8SNickeau 34737748cd8SNickeau } 34837748cd8SNickeau 34937748cd8SNickeau /** 35037748cd8SNickeau * Return a mode from a tag (ie from a {@link Plugin::getPluginComponent()} 35137748cd8SNickeau * @param $tag 35237748cd8SNickeau * @return string 35337748cd8SNickeau * 35437748cd8SNickeau * A mode is just a name for a class 35537748cd8SNickeau * Example: $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock()); 35637748cd8SNickeau */ 35737748cd8SNickeau public static function getModeFromTag($tag) 35837748cd8SNickeau { 35937748cd8SNickeau return "plugin_" . self::getComponentName($tag); 36037748cd8SNickeau } 36137748cd8SNickeau 36237748cd8SNickeau /** 36337748cd8SNickeau * @param $tag 36437748cd8SNickeau * @return string 36537748cd8SNickeau * 36637748cd8SNickeau * Create a lookahead pattern for a container tag used to enter in a mode 36737748cd8SNickeau */ 36837748cd8SNickeau public static function getContainerTagPattern($tag) 36937748cd8SNickeau { 37037748cd8SNickeau // this pattern ensure that the tag 37137748cd8SNickeau // `accordion` will not intercept also the tag `accordionitem` 37237748cd8SNickeau // where: 37337748cd8SNickeau // ?: means non capturing group (to not capture the last >) 37437748cd8SNickeau // (\s.*?): is a capturing group that starts with a space 37537748cd8SNickeau $pattern = "(?:\s.*?>|>)"; 37637748cd8SNickeau return '<' . $tag . $pattern . '(?=.*?<\/' . $tag . '>)'; 37737748cd8SNickeau } 37837748cd8SNickeau 37937748cd8SNickeau /** 38037748cd8SNickeau * This pattern allows space after the tag name 38137748cd8SNickeau * for an end tag 38237748cd8SNickeau * As XHTML (https://www.w3.org/TR/REC-xml/#dt-etag) 38337748cd8SNickeau * @param $tag 38437748cd8SNickeau * @return string 38537748cd8SNickeau */ 38637748cd8SNickeau public static function getEndTagPattern($tag) 38737748cd8SNickeau { 38837748cd8SNickeau return "</$tag\s*>"; 38937748cd8SNickeau } 39037748cd8SNickeau 39137748cd8SNickeau /** 39237748cd8SNickeau * @param $tag 39337748cd8SNickeau * @return string 39437748cd8SNickeau * 39537748cd8SNickeau * Create a open tag pattern without lookahead. 396c3437056SNickeau * Used for 397c3437056SNickeau * @link https://dev.w3.org/html5/html-author/#void-elements-0 39837748cd8SNickeau */ 39937748cd8SNickeau public static function getVoidElementTagPattern($tag) 40037748cd8SNickeau { 40137748cd8SNickeau return '<' . $tag . '.*?>'; 40237748cd8SNickeau } 40337748cd8SNickeau 40437748cd8SNickeau 40537748cd8SNickeau /** 40637748cd8SNickeau * Take an array where the key is the attribute name 40737748cd8SNickeau * and return a HTML tag string 40837748cd8SNickeau * 40937748cd8SNickeau * The attribute name and value are escaped 41037748cd8SNickeau * 41137748cd8SNickeau * @param $attributes - combo attributes 41237748cd8SNickeau * @return string 41337748cd8SNickeau * @deprecated to allowed background and other metadata, use {@link TagAttributes::toHtmlEnterTag()} 41437748cd8SNickeau */ 41537748cd8SNickeau public static function array2HTMLAttributesAsString($attributes) 41637748cd8SNickeau { 41737748cd8SNickeau 41837748cd8SNickeau $tagAttributes = TagAttributes::createFromCallStackArray($attributes); 41937748cd8SNickeau return $tagAttributes->toHTMLAttributeString(); 42037748cd8SNickeau 42137748cd8SNickeau } 42237748cd8SNickeau 42337748cd8SNickeau /** 42437748cd8SNickeau * 42537748cd8SNickeau * Parse the attributes part of a match 42637748cd8SNickeau * 42737748cd8SNickeau * Example: 42837748cd8SNickeau * line-numbers="value" 42937748cd8SNickeau * line-numbers='value' 43037748cd8SNickeau * 43137748cd8SNickeau * This value may be in: 43237748cd8SNickeau * * configuration value 43337748cd8SNickeau * * as well as in the match of a {@link SyntaxPlugin} 43437748cd8SNickeau * 43537748cd8SNickeau * @param $string 43637748cd8SNickeau * @return array 43737748cd8SNickeau * 43837748cd8SNickeau * To parse a match, use {@link PluginUtility::getTagAttributes()} 43937748cd8SNickeau * 44037748cd8SNickeau * 44137748cd8SNickeau */ 44237748cd8SNickeau public static function parseAttributes($string) 44337748cd8SNickeau { 44437748cd8SNickeau 44537748cd8SNickeau $parameters = array(); 44637748cd8SNickeau 44737748cd8SNickeau // Rules 44837748cd8SNickeau // * name may be alone (ie true boolean attribute) 44937748cd8SNickeau // * a name may get a `-` 45037748cd8SNickeau // * there may be space every everywhere when the value is enclosed with a quote 45137748cd8SNickeau // * there may be no space in the value and between the equal sign when the value is not enclosed 45237748cd8SNickeau // 45337748cd8SNickeau // /i not case sensitive 45437748cd8SNickeau $attributePattern = '\s*([-\w]+)\s*(?:=(\s*[\'"]([^`"]*)[\'"]\s*|[^\s]*))?'; 45537748cd8SNickeau $result = preg_match_all('/' . $attributePattern . '/i', $string, $matches); 45637748cd8SNickeau if ($result != 0) { 45737748cd8SNickeau foreach ($matches[1] as $key => $parameterKey) { 45837748cd8SNickeau 45937748cd8SNickeau // group 3 (ie the value between quotes) 46037748cd8SNickeau $value = $matches[3][$key]; 46137748cd8SNickeau if ($value == "") { 46237748cd8SNickeau // check the value without quotes 46337748cd8SNickeau $value = $matches[2][$key]; 46437748cd8SNickeau } 46537748cd8SNickeau // if there is no value, this is a boolean 46637748cd8SNickeau if ($value == "") { 46737748cd8SNickeau $value = true; 46837748cd8SNickeau } else { 46937748cd8SNickeau $value = hsc($value); 47037748cd8SNickeau } 47137748cd8SNickeau $parameters[hsc(strtolower($parameterKey))] = $value; 47237748cd8SNickeau } 47337748cd8SNickeau } 47437748cd8SNickeau return $parameters; 47537748cd8SNickeau 47637748cd8SNickeau } 47737748cd8SNickeau 478*4cadd4f8SNickeau public static function getTagAttributes($match, $knownTypes = null): array 47937748cd8SNickeau { 480*4cadd4f8SNickeau return self::getQualifiedTagAttributes($match, false, "", $knownTypes); 48137748cd8SNickeau } 48237748cd8SNickeau 48337748cd8SNickeau /** 48437748cd8SNickeau * Return the attribute of a tag 48537748cd8SNickeau * Because they are users input, they are all escaped 48637748cd8SNickeau * @param $match 48737748cd8SNickeau * @param $hasThirdValue - if true, the third parameter is treated as value, not a property and returned in the `third` key 48837748cd8SNickeau * use for the code/file/console where they accept a name as third value 48937748cd8SNickeau * @param $keyThirdArgument - if a third argument is found, return it with this key 490*4cadd4f8SNickeau * @param array|null $knownTypes 49137748cd8SNickeau * @return array 49237748cd8SNickeau */ 493*4cadd4f8SNickeau public static function getQualifiedTagAttributes($match, $hasThirdValue, $keyThirdArgument, array $knownTypes = null): array 49437748cd8SNickeau { 49537748cd8SNickeau 49637748cd8SNickeau $match = PluginUtility::getPreprocessEnterTag($match); 49737748cd8SNickeau 49837748cd8SNickeau // Suppress the tag name (ie until the first blank) 49937748cd8SNickeau $spacePosition = strpos($match, " "); 50037748cd8SNickeau if (!$spacePosition) { 50137748cd8SNickeau // No space, meaning this is only the tag name 50237748cd8SNickeau return array(); 50337748cd8SNickeau } 50437748cd8SNickeau $match = trim(substr($match, $spacePosition)); 50537748cd8SNickeau if ($match == "") { 50637748cd8SNickeau return array(); 50737748cd8SNickeau } 50837748cd8SNickeau 50937748cd8SNickeau // Do we have a type as first argument ? 51037748cd8SNickeau $attributes = array(); 51137748cd8SNickeau $spacePosition = strpos($match, " "); 51237748cd8SNickeau if ($spacePosition) { 51337748cd8SNickeau $nextArgument = substr($match, 0, $spacePosition); 51437748cd8SNickeau } else { 51537748cd8SNickeau $nextArgument = $match; 51637748cd8SNickeau } 517*4cadd4f8SNickeau 518*4cadd4f8SNickeau $isType = !strpos($nextArgument, "="); 519*4cadd4f8SNickeau if ($knownTypes !== null) { 520*4cadd4f8SNickeau if (!in_array($nextArgument, $knownTypes)) { 521*4cadd4f8SNickeau $isType = false; 522*4cadd4f8SNickeau } 523*4cadd4f8SNickeau } 524*4cadd4f8SNickeau if ($isType) { 525*4cadd4f8SNickeau 52637748cd8SNickeau $attributes["type"] = $nextArgument; 52737748cd8SNickeau // Suppress the type 52837748cd8SNickeau $match = substr($match, strlen($nextArgument)); 52937748cd8SNickeau $match = trim($match); 53037748cd8SNickeau 53137748cd8SNickeau // Do we have a value as first argument ? 53237748cd8SNickeau if (!empty($hasThirdValue)) { 53337748cd8SNickeau $spacePosition = strpos($match, " "); 53437748cd8SNickeau if ($spacePosition) { 53537748cd8SNickeau $nextArgument = substr($match, 0, $spacePosition); 53637748cd8SNickeau } else { 53737748cd8SNickeau $nextArgument = $match; 53837748cd8SNickeau } 53937748cd8SNickeau if (!strpos($nextArgument, "=") && !empty($nextArgument)) { 54037748cd8SNickeau $attributes[$keyThirdArgument] = $nextArgument; 54137748cd8SNickeau // Suppress the third argument 54237748cd8SNickeau $match = substr($match, strlen($nextArgument)); 54337748cd8SNickeau $match = trim($match); 54437748cd8SNickeau } 54537748cd8SNickeau } 54637748cd8SNickeau } 54737748cd8SNickeau 54837748cd8SNickeau // Parse the remaining attributes 54937748cd8SNickeau $parsedAttributes = self::parseAttributes($match); 55037748cd8SNickeau 55137748cd8SNickeau // Merge 55237748cd8SNickeau $attributes = array_merge($attributes, $parsedAttributes);; 55337748cd8SNickeau 55437748cd8SNickeau return $attributes; 55537748cd8SNickeau 55637748cd8SNickeau } 55737748cd8SNickeau 55837748cd8SNickeau /** 55937748cd8SNickeau * @param array $styleProperties - an array of CSS properties with key, value 56037748cd8SNickeau * @return string - the value for the style attribute (ie all rules where joined with the comma) 56137748cd8SNickeau */ 56237748cd8SNickeau public static function array2InlineStyle(array $styleProperties) 56337748cd8SNickeau { 56437748cd8SNickeau $inlineCss = ""; 56537748cd8SNickeau foreach ($styleProperties as $key => $value) { 56637748cd8SNickeau $inlineCss .= "$key:$value;"; 56737748cd8SNickeau } 56837748cd8SNickeau // Suppress the last ; 56937748cd8SNickeau if ($inlineCss[strlen($inlineCss) - 1] == ";") { 57037748cd8SNickeau $inlineCss = substr($inlineCss, 0, -1); 57137748cd8SNickeau } 57237748cd8SNickeau return $inlineCss; 57337748cd8SNickeau } 57437748cd8SNickeau 57537748cd8SNickeau /** 57637748cd8SNickeau * @param $tag 57737748cd8SNickeau * @return string 57837748cd8SNickeau * Create a pattern used where the tag is not a container. 57937748cd8SNickeau * ie 58037748cd8SNickeau * <br/> 58137748cd8SNickeau * <icon/> 58237748cd8SNickeau * This is generally used with a subtition plugin 58337748cd8SNickeau * and a {@link Lexer::addSpecialPattern} state 58437748cd8SNickeau * where the tag is just replaced 58537748cd8SNickeau */ 58619494974Sgerardnico public static function getEmptyTagPattern($tag): string 58737748cd8SNickeau { 58819494974Sgerardnico 589*4cadd4f8SNickeau /** 590*4cadd4f8SNickeau * A tag should start with the tag 591*4cadd4f8SNickeau * `(?=[/ ]{1})` - a space or the / (lookahead) => to allow allow tag name with minus character 592*4cadd4f8SNickeau * `(?![^/]>)` - it's not a normal tag (ie a > with the previous character that is not /) 593*4cadd4f8SNickeau * `[^>]*` then until the > is found (dokuwiki capture greedy, don't use the point character) 594*4cadd4f8SNickeau * then until the close `/>` character 595*4cadd4f8SNickeau */ 596*4cadd4f8SNickeau return '<' . $tag . '(?=[/ ]{1})(?![^/]>)[^>]*\/>'; 59737748cd8SNickeau } 59837748cd8SNickeau 59937748cd8SNickeau /** 60037748cd8SNickeau * Just call this function from a class like that 60137748cd8SNickeau * getTageName(get_called_class()) 60237748cd8SNickeau * to get the tag name (ie the component plugin) 60337748cd8SNickeau * of a syntax plugin 60437748cd8SNickeau * 60537748cd8SNickeau * @param $get_called_class 60637748cd8SNickeau * @return string 60737748cd8SNickeau */ 60837748cd8SNickeau public static function getTagName($get_called_class) 60937748cd8SNickeau { 61037748cd8SNickeau list(/* $t */, /* $p */, /* $n */, $c) = explode('_', $get_called_class, 4); 61137748cd8SNickeau return (isset($c) ? $c : ''); 61237748cd8SNickeau } 61337748cd8SNickeau 61437748cd8SNickeau /** 61537748cd8SNickeau * Just call this function from a class like that 61637748cd8SNickeau * getAdminPageName(get_called_class()) 61737748cd8SNickeau * to get the page name of a admin plugin 61837748cd8SNickeau * 61937748cd8SNickeau * @param $get_called_class 62037748cd8SNickeau * @return string - the admin page name 62137748cd8SNickeau */ 62237748cd8SNickeau public static function getAdminPageName($get_called_class) 62337748cd8SNickeau { 62437748cd8SNickeau $names = explode('_', $get_called_class); 62537748cd8SNickeau $names = array_slice($names, -2); 62637748cd8SNickeau return implode('_', $names); 62737748cd8SNickeau } 62837748cd8SNickeau 62937748cd8SNickeau public static function getNameSpace() 63037748cd8SNickeau { 63137748cd8SNickeau // No : at the begin of the namespace please 63237748cd8SNickeau return self::PLUGIN_BASE_NAME . ':'; 63337748cd8SNickeau } 63437748cd8SNickeau 63537748cd8SNickeau /** 63637748cd8SNickeau * @param $get_called_class - the plugin class 63737748cd8SNickeau * @return array 63837748cd8SNickeau */ 63937748cd8SNickeau public static function getTags($get_called_class) 64037748cd8SNickeau { 64137748cd8SNickeau $elements = array(); 64237748cd8SNickeau $elementName = PluginUtility::getTagName($get_called_class); 64337748cd8SNickeau $elements[] = $elementName; 64437748cd8SNickeau $elements[] = strtoupper($elementName); 64537748cd8SNickeau return $elements; 64637748cd8SNickeau } 64737748cd8SNickeau 64837748cd8SNickeau /** 64937748cd8SNickeau * Render a text 65037748cd8SNickeau * @param $pageContent 65137748cd8SNickeau * @return string|null 65237748cd8SNickeau */ 65337748cd8SNickeau public static function render($pageContent) 65437748cd8SNickeau { 65537748cd8SNickeau return RenderUtility::renderText2XhtmlAndStripPEventually($pageContent, false); 65637748cd8SNickeau } 65737748cd8SNickeau 65837748cd8SNickeau 65937748cd8SNickeau /** 66037748cd8SNickeau * This method will takes attributes 66137748cd8SNickeau * and process the plugin styling attribute such as width and height 66237748cd8SNickeau * to put them in a style HTML attribute 66337748cd8SNickeau * @param TagAttributes $attributes 66437748cd8SNickeau */ 66537748cd8SNickeau public static function processStyle(&$attributes) 66637748cd8SNickeau { 66737748cd8SNickeau // Style 66837748cd8SNickeau $styleAttributeName = "style"; 66937748cd8SNickeau if ($attributes->hasComponentAttribute($styleAttributeName)) { 67037748cd8SNickeau $properties = explode(";", $attributes->getValueAndRemove($styleAttributeName)); 67137748cd8SNickeau foreach ($properties as $property) { 67237748cd8SNickeau list($key, $value) = explode(":", $property); 67337748cd8SNickeau if ($key != "") { 67482a60d03SNickeau $attributes->addStyleDeclarationIfNotSet($key, $value); 67537748cd8SNickeau } 67637748cd8SNickeau } 67737748cd8SNickeau } 67837748cd8SNickeau 67937748cd8SNickeau 68037748cd8SNickeau /** 68137748cd8SNickeau * Border Color 68237748cd8SNickeau * For background color, see {@link TagAttributes::processBackground()} 68337748cd8SNickeau * For text color, see {@link TextColor} 68437748cd8SNickeau */ 68537748cd8SNickeau 686*4cadd4f8SNickeau if ($attributes->hasComponentAttribute(ColorRgb::BORDER_COLOR)) { 687*4cadd4f8SNickeau $colorValue = $attributes->getValueAndRemove(ColorRgb::BORDER_COLOR); 688*4cadd4f8SNickeau $attributes->addStyleDeclarationIfNotSet(ColorRgb::BORDER_COLOR, ColorRgb::createFromString($colorValue)->toCssValue()); 68937748cd8SNickeau self::checkDefaultBorderColorAttributes($attributes); 69037748cd8SNickeau } 69137748cd8SNickeau 69237748cd8SNickeau 69337748cd8SNickeau } 69437748cd8SNickeau 69537748cd8SNickeau /** 69637748cd8SNickeau * Return the name of the requested script 69737748cd8SNickeau */ 69837748cd8SNickeau public 69937748cd8SNickeau static function getRequestScript() 70037748cd8SNickeau { 70137748cd8SNickeau $scriptPath = null; 70237748cd8SNickeau $testPropertyValue = self::getPropertyValue("SCRIPT_NAME"); 70337748cd8SNickeau if (defined('DOKU_UNITTEST') && $testPropertyValue != null) { 70437748cd8SNickeau return $testPropertyValue; 70537748cd8SNickeau } 70637748cd8SNickeau if (array_key_exists("DOCUMENT_URI", $_SERVER)) { 70737748cd8SNickeau $scriptPath = $_SERVER["DOCUMENT_URI"]; 70837748cd8SNickeau } 70937748cd8SNickeau if ($scriptPath == null && array_key_exists("SCRIPT_NAME", $_SERVER)) { 71037748cd8SNickeau $scriptPath = $_SERVER["SCRIPT_NAME"]; 71137748cd8SNickeau } 71237748cd8SNickeau if ($scriptPath == null) { 71337748cd8SNickeau msg("Unable to find the main script", LogUtility::LVL_MSG_ERROR); 71437748cd8SNickeau } 71537748cd8SNickeau $path_parts = pathinfo($scriptPath); 71637748cd8SNickeau return $path_parts['basename']; 71737748cd8SNickeau } 71837748cd8SNickeau 71937748cd8SNickeau /** 72037748cd8SNickeau * 72137748cd8SNickeau * @param $name 72237748cd8SNickeau * @param $default 72337748cd8SNickeau * @return string - the value of a query string property or if in test mode, the value of a test variable 72437748cd8SNickeau * set with {@link self::setTestProperty} 72537748cd8SNickeau * This is used to test script that are not supported by the dokuwiki test framework 72637748cd8SNickeau * such as css.php 72737748cd8SNickeau */ 72837748cd8SNickeau public 72937748cd8SNickeau static function getPropertyValue($name, $default = null) 73037748cd8SNickeau { 73137748cd8SNickeau global $INPUT; 73237748cd8SNickeau $value = $INPUT->str($name); 73337748cd8SNickeau if ($value == null && defined('DOKU_UNITTEST')) { 73437748cd8SNickeau global $COMBO; 73537748cd8SNickeau $value = $COMBO[$name]; 73637748cd8SNickeau } 73737748cd8SNickeau if ($value == null) { 73837748cd8SNickeau return $default; 73937748cd8SNickeau } else { 74037748cd8SNickeau return $value; 74137748cd8SNickeau } 74237748cd8SNickeau 74337748cd8SNickeau } 74437748cd8SNickeau 74537748cd8SNickeau /** 74637748cd8SNickeau * Create an URL to the documentation website 74737748cd8SNickeau * @param $canonical - canonical id or slug 748c3437056SNickeau * @param $label - the text of the link 74937748cd8SNickeau * @param bool $withIcon - used to break the recursion with the message in the {@link Icon} 75037748cd8SNickeau * @return string - an url 75137748cd8SNickeau */ 75237748cd8SNickeau public 753c3437056SNickeau static function getDocumentationHyperLink($canonical, $label, $withIcon = true, $tooltip = ""): string 75437748cd8SNickeau { 75537748cd8SNickeau /** @noinspection SpellCheckingInspection */ 75637748cd8SNickeau 75737748cd8SNickeau $xhtmlIcon = ""; 75837748cd8SNickeau if ($withIcon) { 75937748cd8SNickeau 76037748cd8SNickeau /** 76137748cd8SNickeau * We don't include it as an external resource via url 76237748cd8SNickeau * because it then make a http request for every logo 76337748cd8SNickeau * in the configuration page and makes it really slow 764c3437056SNickeau * TODO: when we have made a special fetch ajax with cache 765c3437056SNickeau * for application resource, we can serve it statically 76637748cd8SNickeau */ 767*4cadd4f8SNickeau $path = Site::getComboImagesDirectory()->resolve("logo.svg"); 768*4cadd4f8SNickeau try { 76937748cd8SNickeau $tagAttributes = TagAttributes::createEmpty(SvgImageLink::CANONICAL); 77037748cd8SNickeau $tagAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, SvgDocument::ICON_TYPE); 77137748cd8SNickeau $tagAttributes->addComponentAttributeValue(Dimension::WIDTH_KEY, "20"); 77237748cd8SNickeau $cache = new CacheMedia($path, $tagAttributes); 77337748cd8SNickeau if (!$cache->isCacheUsable()) { 774c3437056SNickeau $xhtmlIcon = SvgDocument::createSvgDocumentFromPath($path) 77537748cd8SNickeau ->setShouldBeOptimized(true) 77637748cd8SNickeau ->getXmlText($tagAttributes); 77737748cd8SNickeau $cache->storeCache($xhtmlIcon); 77837748cd8SNickeau } 779c3437056SNickeau $xhtmlIcon = FileSystems::getContent($cache->getFile()); 780*4cadd4f8SNickeau } catch (ExceptionCombo $e) { 781*4cadd4f8SNickeau LogUtility::msg("The logo ($path) is not valid and could not be added to the documentation link. Error: {$e->getMessage()}"); 782*4cadd4f8SNickeau } 78337748cd8SNickeau 78437748cd8SNickeau } 785c3437056SNickeau $urlApex = self::$URL_APEX; 786c3437056SNickeau $path = str_replace(":", "/", $canonical); 787c3437056SNickeau if (empty($tooltip)) { 788c3437056SNickeau $title = $label; 789c3437056SNickeau } else { 790c3437056SNickeau $title = $tooltip; 791c3437056SNickeau } 792c3437056SNickeau $htmlToolTip = ""; 793c3437056SNickeau if (!empty($tooltip)) { 794c3437056SNickeau $dataAttributeNamespace = Bootstrap::getDataNamespace(); 795c3437056SNickeau $htmlToolTip = "data{$dataAttributeNamespace}-toggle=\"tooltip\""; 796c3437056SNickeau } 797c3437056SNickeau return "$xhtmlIcon<a href=\"$urlApex/$path\" title=\"$title\" $htmlToolTip style=\"text-decoration:none;\">$label</a>"; 79837748cd8SNickeau } 79937748cd8SNickeau 80037748cd8SNickeau /** 80137748cd8SNickeau * An utility function to not search every time which array should be first 80237748cd8SNickeau * @param array $inlineAttributes - the component inline attributes 80337748cd8SNickeau * @param array $defaultAttributes - the default configuration attributes 80437748cd8SNickeau * @return array - a merged array 80537748cd8SNickeau */ 80637748cd8SNickeau public 80737748cd8SNickeau static function mergeAttributes(array $inlineAttributes, array $defaultAttributes = array()) 80837748cd8SNickeau { 80937748cd8SNickeau return array_merge($defaultAttributes, $inlineAttributes); 81037748cd8SNickeau } 81137748cd8SNickeau 81237748cd8SNickeau /** 81337748cd8SNickeau * A pattern for a container tag 81437748cd8SNickeau * that needs to catch the content 81537748cd8SNickeau * 81637748cd8SNickeau * Use as a special pattern (substition) 81737748cd8SNickeau * 81837748cd8SNickeau * The {@link \syntax_plugin_combo_math} use it 81937748cd8SNickeau * @param $tag 82037748cd8SNickeau * @return string - a pattern 82137748cd8SNickeau */ 82237748cd8SNickeau public 82337748cd8SNickeau static function getLeafContainerTagPattern($tag) 82437748cd8SNickeau { 82537748cd8SNickeau return '<' . $tag . '.*?>.*?<\/' . $tag . '>'; 82637748cd8SNickeau } 82737748cd8SNickeau 82837748cd8SNickeau /** 82937748cd8SNickeau * Return the content of a tag 83037748cd8SNickeau * <math>Content</math> 83137748cd8SNickeau * @param $match 83237748cd8SNickeau * @return string the content 83337748cd8SNickeau */ 83437748cd8SNickeau public 83537748cd8SNickeau static function getTagContent($match) 83637748cd8SNickeau { 83737748cd8SNickeau // From the first > 83837748cd8SNickeau $start = strpos($match, ">"); 83937748cd8SNickeau if ($start == false) { 84037748cd8SNickeau LogUtility::msg("The match does not contain any opening tag. Match: {$match}", LogUtility::LVL_MSG_ERROR); 84137748cd8SNickeau return ""; 84237748cd8SNickeau } 84337748cd8SNickeau $match = substr($match, $start + 1); 84437748cd8SNickeau // If this is the last character, we get a false 84537748cd8SNickeau if ($match == false) { 84637748cd8SNickeau LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR); 84737748cd8SNickeau return ""; 84837748cd8SNickeau } 84937748cd8SNickeau 85037748cd8SNickeau $end = strrpos($match, "</"); 85137748cd8SNickeau if ($end == false) { 85237748cd8SNickeau LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR); 85337748cd8SNickeau return ""; 85437748cd8SNickeau } 85537748cd8SNickeau 85637748cd8SNickeau return substr($match, 0, $end); 85737748cd8SNickeau } 85837748cd8SNickeau 85937748cd8SNickeau /** 86037748cd8SNickeau * 86137748cd8SNickeau * Check if a HTML tag was already added for a request 86237748cd8SNickeau * The request id is just the timestamp 86337748cd8SNickeau * An indicator array should be provided 86437748cd8SNickeau * @return string 86537748cd8SNickeau */ 86637748cd8SNickeau public 86737748cd8SNickeau static function getRequestId() 86837748cd8SNickeau { 86937748cd8SNickeau 87037748cd8SNickeau if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { 87137748cd8SNickeau // since php 5.4 87237748cd8SNickeau $requestTime = $_SERVER['REQUEST_TIME_FLOAT']; 87337748cd8SNickeau } else { 87437748cd8SNickeau // DokuWiki test framework use this 87537748cd8SNickeau $requestTime = $_SERVER['REQUEST_TIME']; 87637748cd8SNickeau } 87737748cd8SNickeau $keyPrefix = 'combo_'; 87837748cd8SNickeau 87937748cd8SNickeau global $ID; 88037748cd8SNickeau return $keyPrefix . hash('crc32b', $_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT'] . $requestTime . $ID); 88137748cd8SNickeau 88237748cd8SNickeau } 88337748cd8SNickeau 88437748cd8SNickeau /** 88537748cd8SNickeau * Get the page id 88637748cd8SNickeau * If the page is a sidebar, it will not return the id of the sidebar 88737748cd8SNickeau * but the one of the page 888c3437056SNickeau * Return the main/requested page id 889c3437056SNickeau * (Not the sidebar) 890c3437056SNickeau * @return string|null - null in test 89137748cd8SNickeau */ 89237748cd8SNickeau public 893*4cadd4f8SNickeau static function getRequestedWikiId(): ?string 89437748cd8SNickeau { 895c3437056SNickeau global $ID; 896c3437056SNickeau global $INFO; 897c3437056SNickeau $callingId = $ID; 898c3437056SNickeau // If the component is in a sidebar, we don't want the ID of the sidebar 899c3437056SNickeau // but the ID of the page. 900*4cadd4f8SNickeau if ($INFO !== null) { 901c3437056SNickeau $callingId = $INFO['id']; 902c3437056SNickeau } 903c3437056SNickeau /** 904c3437056SNickeau * This is the case with event triggered 905c3437056SNickeau * before DokuWiki such as 906c3437056SNickeau * https://www.dokuwiki.org/devel:event:init_lang_load 907c3437056SNickeau */ 908c3437056SNickeau if ($callingId == null) { 909c3437056SNickeau global $_REQUEST; 910*4cadd4f8SNickeau if (isset($_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE])) { 911*4cadd4f8SNickeau $callingId = $_REQUEST[DokuwikiId::DOKUWIKI_ID_ATTRIBUTE]; 912c3437056SNickeau } 913c3437056SNickeau } 914*4cadd4f8SNickeau 915c3437056SNickeau return $callingId; 916c3437056SNickeau 91737748cd8SNickeau } 91837748cd8SNickeau 91937748cd8SNickeau /** 920*4cadd4f8SNickeau * Encode special HTML characters to entity 921*4cadd4f8SNickeau * (ie escaping) 922*4cadd4f8SNickeau * 923*4cadd4f8SNickeau * This is used to transform text that may be interpreted as HTML 924*4cadd4f8SNickeau * into a text 925*4cadd4f8SNickeau * * that will not be interpreted as HTML 926*4cadd4f8SNickeau * * that may be added in html attribute 927*4cadd4f8SNickeau * 928*4cadd4f8SNickeau * For instance: 929*4cadd4f8SNickeau * * text that should go in attribute with special HTML characters (such as title) 930*4cadd4f8SNickeau * * text that we don't create (to prevent HTML injection) 931*4cadd4f8SNickeau * 93237748cd8SNickeau * Example: 933*4cadd4f8SNickeau * 934*4cadd4f8SNickeau * <script>...</script> 93537748cd8SNickeau * to 936*4cadd4f8SNickeau * "<script>...</hello>" 937*4cadd4f8SNickeau * 93837748cd8SNickeau * 93937748cd8SNickeau * @param $text 94037748cd8SNickeau * @return string 94137748cd8SNickeau */ 94237748cd8SNickeau public 943c3437056SNickeau static function htmlEncode($text): string 94437748cd8SNickeau { 94537748cd8SNickeau /** 94637748cd8SNickeau * See https://stackoverflow.com/questions/46483/htmlentities-vs-htmlspecialchars/3614344 947*4cadd4f8SNickeau * 948*4cadd4f8SNickeau * Not {@link htmlentities } htmlentities($text, ENT_QUOTES); 949*4cadd4f8SNickeau * Otherwise we get `Error while loading HTMLError: Entity 'hellip' not defined` 950*4cadd4f8SNickeau * when loading HTML with {@link XmlDocument} 951*4cadd4f8SNickeau * 952*4cadd4f8SNickeau * See also {@link PluginUtility::htmlDecode()} 953*4cadd4f8SNickeau * 954*4cadd4f8SNickeau * Without ENT_QUOTES 955*4cadd4f8SNickeau * <h4 class="heading-combo"> 956*4cadd4f8SNickeau * is encoded as 957*4cadd4f8SNickeau * >h4 class="heading-combo"< 958*4cadd4f8SNickeau * and cannot be added in a attribute because of the quote 959*4cadd4f8SNickeau * This is used for {@link Tooltip} 96037748cd8SNickeau */ 961*4cadd4f8SNickeau return htmlspecialchars($text, ENT_XHTML | ENT_QUOTES); 962*4cadd4f8SNickeau 96337748cd8SNickeau } 96437748cd8SNickeau 965c3437056SNickeau public 966c3437056SNickeau static function xmlEncode($text) 967c3437056SNickeau { 968c3437056SNickeau /** 969c3437056SNickeau * {@link htmlentities } 970c3437056SNickeau */ 971c3437056SNickeau return htmlentities($text, ENT_XML1); 972c3437056SNickeau } 973c3437056SNickeau 97437748cd8SNickeau 97537748cd8SNickeau /** 97637748cd8SNickeau * Add a class 97737748cd8SNickeau * @param $classValue 97837748cd8SNickeau * @param array $attributes 97937748cd8SNickeau */ 98037748cd8SNickeau public 98137748cd8SNickeau static function addClass2Attributes($classValue, array &$attributes) 98237748cd8SNickeau { 98337748cd8SNickeau self::addAttributeValue("class", $classValue, $attributes); 98437748cd8SNickeau } 98537748cd8SNickeau 98637748cd8SNickeau /** 98737748cd8SNickeau * Add a style property to the attributes 98837748cd8SNickeau * @param $property 98937748cd8SNickeau * @param $value 99037748cd8SNickeau * @param array $attributes 99182a60d03SNickeau * @deprecated use {@link TagAttributes::addStyleDeclarationIfNotSet()} instead 99237748cd8SNickeau */ 99337748cd8SNickeau public 99437748cd8SNickeau static function addStyleProperty($property, $value, array &$attributes) 99537748cd8SNickeau { 99637748cd8SNickeau if (isset($attributes["style"])) { 99737748cd8SNickeau $attributes["style"] .= ";$property:$value"; 99837748cd8SNickeau } else { 99937748cd8SNickeau $attributes["style"] = "$property:$value"; 100037748cd8SNickeau } 100137748cd8SNickeau 100237748cd8SNickeau } 100337748cd8SNickeau 100437748cd8SNickeau /** 100537748cd8SNickeau * Add default border attributes 100637748cd8SNickeau * to see a border 100737748cd8SNickeau * Doc 100837748cd8SNickeau * https://combostrap.com/styling/color#border_color 100937748cd8SNickeau * @param TagAttributes $tagAttributes 101037748cd8SNickeau */ 101137748cd8SNickeau private 101237748cd8SNickeau static function checkDefaultBorderColorAttributes(&$tagAttributes) 101337748cd8SNickeau { 101437748cd8SNickeau /** 101537748cd8SNickeau * border color was set without the width 101637748cd8SNickeau * setting the width 101737748cd8SNickeau */ 101837748cd8SNickeau if (!( 101937748cd8SNickeau $tagAttributes->hasStyleDeclaration("border") 102037748cd8SNickeau || 102137748cd8SNickeau $tagAttributes->hasStyleDeclaration("border-width") 102237748cd8SNickeau ) 102337748cd8SNickeau ) { 102482a60d03SNickeau $tagAttributes->addStyleDeclarationIfNotSet("border-width", "1px"); 102537748cd8SNickeau } 102637748cd8SNickeau /** 102737748cd8SNickeau * border color was set without the style 102837748cd8SNickeau * setting the style 102937748cd8SNickeau */ 103037748cd8SNickeau if (! 103137748cd8SNickeau ( 103237748cd8SNickeau $tagAttributes->hasStyleDeclaration("border") 103337748cd8SNickeau || 103437748cd8SNickeau $tagAttributes->hasStyleDeclaration("border-style") 103537748cd8SNickeau ) 103637748cd8SNickeau ) { 103782a60d03SNickeau $tagAttributes->addStyleDeclarationIfNotSet("border-style", "solid"); 103837748cd8SNickeau 103937748cd8SNickeau } 104037748cd8SNickeau if (!$tagAttributes->hasStyleDeclaration("border-radius")) { 104182a60d03SNickeau $tagAttributes->addStyleDeclarationIfNotSet("border-radius", ".25rem"); 104237748cd8SNickeau } 104337748cd8SNickeau 104437748cd8SNickeau } 104537748cd8SNickeau 104637748cd8SNickeau public 104737748cd8SNickeau static function getConfValue($confName, $defaultValue = null) 104837748cd8SNickeau { 104937748cd8SNickeau global $conf; 1050*4cadd4f8SNickeau $value = $conf['plugin'][PluginUtility::PLUGIN_BASE_NAME][$confName]; 1051*4cadd4f8SNickeau if ($value === null || trim($value) === "") { 105237748cd8SNickeau return $defaultValue; 105337748cd8SNickeau } 1054*4cadd4f8SNickeau return $value; 105537748cd8SNickeau } 105637748cd8SNickeau 105737748cd8SNickeau /** 105837748cd8SNickeau * @param $match 105937748cd8SNickeau * @return null|string - return the tag name or null if not found 106037748cd8SNickeau */ 106137748cd8SNickeau public 106237748cd8SNickeau static function getTag($match) 106337748cd8SNickeau { 106437748cd8SNickeau 106537748cd8SNickeau // Trim to start clean 106637748cd8SNickeau $match = trim($match); 106737748cd8SNickeau 106837748cd8SNickeau // Until the first > 106937748cd8SNickeau $pos = strpos($match, ">"); 107037748cd8SNickeau if ($pos == false) { 107137748cd8SNickeau LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_ERROR); 107237748cd8SNickeau return null; 107337748cd8SNickeau } 107437748cd8SNickeau $match = substr($match, 0, $pos); 107537748cd8SNickeau 107637748cd8SNickeau // Suppress the < 107737748cd8SNickeau if ($match[0] == "<") { 107837748cd8SNickeau $match = substr($match, 1); 107937748cd8SNickeau } else { 108037748cd8SNickeau LogUtility::msg("This is not a text tag because it does not start with the character `>`"); 108137748cd8SNickeau } 108237748cd8SNickeau 108337748cd8SNickeau // Suppress the tag name (ie until the first blank) 108437748cd8SNickeau $spacePosition = strpos($match, " "); 108537748cd8SNickeau if (!$spacePosition) { 108637748cd8SNickeau // No space, meaning this is only the tag name 108737748cd8SNickeau return $match; 108837748cd8SNickeau } else { 108937748cd8SNickeau return substr($match, 0, $spacePosition); 109037748cd8SNickeau } 109137748cd8SNickeau 109237748cd8SNickeau } 109337748cd8SNickeau 109437748cd8SNickeau 109537748cd8SNickeau /** 109637748cd8SNickeau * @param string $string add a command into HTML 109737748cd8SNickeau */ 109837748cd8SNickeau public 109937748cd8SNickeau static function addAsHtmlComment($string) 110037748cd8SNickeau { 110137748cd8SNickeau print_r('<!-- ' . self::htmlEncode($string) . '-->'); 110237748cd8SNickeau } 110337748cd8SNickeau 110437748cd8SNickeau public 110537748cd8SNickeau static function getResourceBaseUrl() 110637748cd8SNickeau { 110737748cd8SNickeau return DOKU_URL . 'lib/plugins/' . PluginUtility::PLUGIN_BASE_NAME . '/resources'; 110837748cd8SNickeau } 110937748cd8SNickeau 111037748cd8SNickeau 111137748cd8SNickeau public 111237748cd8SNickeau static function getComponentName($tag) 111337748cd8SNickeau { 111437748cd8SNickeau return strtolower(PluginUtility::PLUGIN_BASE_NAME) . "_" . $tag; 111537748cd8SNickeau } 111637748cd8SNickeau 111737748cd8SNickeau public 111837748cd8SNickeau static function addAttributeValue($attribute, $value, array &$attributes) 111937748cd8SNickeau { 112037748cd8SNickeau if (array_key_exists($attribute, $attributes) && $attributes[$attribute] !== "") { 112137748cd8SNickeau $attributes[$attribute] .= " {$value}"; 112237748cd8SNickeau } else { 112337748cd8SNickeau $attributes[$attribute] = "{$value}"; 112437748cd8SNickeau } 112537748cd8SNickeau } 112637748cd8SNickeau 112737748cd8SNickeau /** 112837748cd8SNickeau * Plugin Utility is available to all plugin, 112937748cd8SNickeau * this is a convenient way to the the snippet manager 113037748cd8SNickeau * @return SnippetManager 113137748cd8SNickeau */ 113237748cd8SNickeau public 1133c3437056SNickeau static function getSnippetManager(): SnippetManager 113437748cd8SNickeau { 1135*4cadd4f8SNickeau return SnippetManager::getOrCreate(); 113637748cd8SNickeau } 113737748cd8SNickeau 1138c3437056SNickeau 113937748cd8SNickeau /** 114037748cd8SNickeau * Function used in a render 114137748cd8SNickeau * @param $data - the data from {@link PluginUtility::handleAndReturnUnmatchedData()} 114237748cd8SNickeau * @return string 114337748cd8SNickeau */ 114437748cd8SNickeau public 1145*4cadd4f8SNickeau static function renderUnmatched($data): string 114637748cd8SNickeau { 114737748cd8SNickeau /** 114837748cd8SNickeau * Attributes 114937748cd8SNickeau */ 115037748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 115137748cd8SNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 115237748cd8SNickeau } else { 115337748cd8SNickeau $attributes = []; 115437748cd8SNickeau } 115537748cd8SNickeau $tagAttributes = TagAttributes::createFromCallStackArray($attributes); 1156*4cadd4f8SNickeau $display = $tagAttributes->getValue(Display::DISPLAY); 1157*4cadd4f8SNickeau if ($display !== "none") { 115837748cd8SNickeau $payload = $data[self::PAYLOAD]; 11591fa8c418SNickeau $previousTagDisplayType = $data[self::CONTEXT]; 11601fa8c418SNickeau if ($previousTagDisplayType !== Call::INLINE_DISPLAY) { 116137748cd8SNickeau $payload = ltrim($payload); 116237748cd8SNickeau } 116337748cd8SNickeau return PluginUtility::htmlEncode($payload); 116437748cd8SNickeau } else { 116537748cd8SNickeau return ""; 116637748cd8SNickeau } 116737748cd8SNickeau } 116837748cd8SNickeau 1169c3437056SNickeau public 1170c3437056SNickeau static function renderUnmatchedXml($data) 1171c3437056SNickeau { 1172c3437056SNickeau $payload = $data[self::PAYLOAD]; 1173c3437056SNickeau $previousTagDisplayType = $data[self::CONTEXT]; 1174c3437056SNickeau if ($previousTagDisplayType !== Call::INLINE_DISPLAY) { 1175c3437056SNickeau $payload = ltrim($payload); 1176c3437056SNickeau } 1177c3437056SNickeau return PluginUtility::xmlEncode($payload); 1178c3437056SNickeau 1179c3437056SNickeau } 1180c3437056SNickeau 118137748cd8SNickeau /** 118237748cd8SNickeau * Function used in a handle function of a syntax plugin for 118337748cd8SNickeau * unmatched context 118437748cd8SNickeau * @param $tagName 118537748cd8SNickeau * @param $match 118637748cd8SNickeau * @param \Doku_Handler $handler 118737748cd8SNickeau * @return array 118837748cd8SNickeau */ 118937748cd8SNickeau public 11901fa8c418SNickeau static function handleAndReturnUnmatchedData($tagName, $match, \Doku_Handler $handler): array 119137748cd8SNickeau { 11921fa8c418SNickeau $callStack = CallStack::createFromHandler($handler); 11931fa8c418SNickeau $sibling = $callStack->previous(); 119437748cd8SNickeau $context = null; 119537748cd8SNickeau if (!empty($sibling)) { 11961fa8c418SNickeau $context = $sibling->getDisplay(); 119737748cd8SNickeau } 119837748cd8SNickeau return array( 119937748cd8SNickeau PluginUtility::STATE => DOKU_LEXER_UNMATCHED, 120037748cd8SNickeau PluginUtility::PAYLOAD => $match, 120137748cd8SNickeau PluginUtility::CONTEXT => $context 120237748cd8SNickeau ); 120337748cd8SNickeau } 120437748cd8SNickeau 120537748cd8SNickeau public 120637748cd8SNickeau static function setConf($key, $value, $namespace = 'plugin') 120737748cd8SNickeau { 120837748cd8SNickeau global $conf; 1209c3437056SNickeau if ($namespace !== null) { 121037748cd8SNickeau $conf[$namespace][PluginUtility::PLUGIN_BASE_NAME][$key] = $value; 121137748cd8SNickeau } else { 121237748cd8SNickeau $conf[$key] = $value; 121337748cd8SNickeau } 121437748cd8SNickeau 121537748cd8SNickeau } 121637748cd8SNickeau 121737748cd8SNickeau /** 121837748cd8SNickeau * Utility methodPreprocess a start tag to be able to extract the name 121937748cd8SNickeau * and the attributes easily 122037748cd8SNickeau * 122137748cd8SNickeau * It will delete: 122237748cd8SNickeau * * the characters <> and the /> if present 122337748cd8SNickeau * * and trim 122437748cd8SNickeau * 122537748cd8SNickeau * It will remain the tagname and its attributes 122637748cd8SNickeau * @param $match 122737748cd8SNickeau * @return false|string|null 122837748cd8SNickeau */ 122937748cd8SNickeau private 123037748cd8SNickeau static function getPreprocessEnterTag($match) 123137748cd8SNickeau { 123237748cd8SNickeau // Until the first > 123337748cd8SNickeau $pos = strpos($match, ">"); 123437748cd8SNickeau if ($pos == false) { 123537748cd8SNickeau LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_WARNING); 123637748cd8SNickeau return null; 123737748cd8SNickeau } 123837748cd8SNickeau $match = substr($match, 0, $pos); 123937748cd8SNickeau 124037748cd8SNickeau 124137748cd8SNickeau // Trim to start clean 124237748cd8SNickeau $match = trim($match); 124337748cd8SNickeau 124437748cd8SNickeau // Suppress the < 124537748cd8SNickeau if ($match[0] == "<") { 124637748cd8SNickeau $match = substr($match, 1); 124737748cd8SNickeau } 124837748cd8SNickeau 124937748cd8SNickeau // Suppress the / for a leaf tag 125037748cd8SNickeau if ($match[strlen($match) - 1] == "/") { 125137748cd8SNickeau $match = substr($match, 0, strlen($match) - 1); 125237748cd8SNickeau } 125337748cd8SNickeau return $match; 125437748cd8SNickeau } 125537748cd8SNickeau 125637748cd8SNickeau /** 125737748cd8SNickeau * Retrieve the tag name used in the text document 125837748cd8SNickeau * @param $match 125937748cd8SNickeau * @return false|string|null 126037748cd8SNickeau */ 126137748cd8SNickeau public 126237748cd8SNickeau static function getSyntaxTagNameFromMatch($match) 126337748cd8SNickeau { 126437748cd8SNickeau $preprocessMatch = PluginUtility::getPreprocessEnterTag($match); 126537748cd8SNickeau 126637748cd8SNickeau // Tag name (ie until the first blank) 126737748cd8SNickeau $spacePosition = strpos($match, " "); 126837748cd8SNickeau if (!$spacePosition) { 126937748cd8SNickeau // No space, meaning this is only the tag name 127037748cd8SNickeau return $preprocessMatch; 127137748cd8SNickeau } else { 127237748cd8SNickeau return trim(substr(0, $spacePosition)); 127337748cd8SNickeau } 127437748cd8SNickeau 127537748cd8SNickeau } 127637748cd8SNickeau 127737748cd8SNickeau /** 127837748cd8SNickeau * @param \Doku_Renderer_xhtml $renderer 127937748cd8SNickeau * @param $position 128037748cd8SNickeau * @param $name 128137748cd8SNickeau */ 128237748cd8SNickeau public 128337748cd8SNickeau static function startSection($renderer, $position, $name) 128437748cd8SNickeau { 128537748cd8SNickeau 128637748cd8SNickeau 128737748cd8SNickeau if (empty($position)) { 128837748cd8SNickeau LogUtility::msg("The position for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support"); 128937748cd8SNickeau } 129037748cd8SNickeau if (empty($name)) { 129137748cd8SNickeau LogUtility::msg("The name for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support"); 129237748cd8SNickeau } 129337748cd8SNickeau 129437748cd8SNickeau /** 129537748cd8SNickeau * New Dokuwiki Version 129637748cd8SNickeau * for DokuWiki Greebo and more recent versions 129737748cd8SNickeau */ 129837748cd8SNickeau if (defined('SEC_EDIT_PATTERN')) { 129937748cd8SNickeau $renderer->startSectionEdit($position, array('target' => self::EDIT_SECTION_TARGET, 'name' => $name)); 130037748cd8SNickeau } else { 130137748cd8SNickeau /** 130237748cd8SNickeau * Old version 130337748cd8SNickeau */ 130437748cd8SNickeau /** @noinspection PhpParamsInspection */ 130537748cd8SNickeau $renderer->startSectionEdit($position, self::EDIT_SECTION_TARGET, $name); 130637748cd8SNickeau } 130737748cd8SNickeau } 130837748cd8SNickeau 130937748cd8SNickeau /** 131037748cd8SNickeau * Add an enter call to the stack 131137748cd8SNickeau * @param \Doku_Handler $handler 131237748cd8SNickeau * @param $tagName 131337748cd8SNickeau * @param array $callStackArray 131437748cd8SNickeau */ 131537748cd8SNickeau public 131637748cd8SNickeau static function addEnterCall( 131737748cd8SNickeau \Doku_Handler &$handler, 131837748cd8SNickeau $tagName, 131937748cd8SNickeau $callStackArray = array() 132037748cd8SNickeau ) 132137748cd8SNickeau { 132237748cd8SNickeau $pluginName = PluginUtility::getComponentName($tagName); 132337748cd8SNickeau $handler->addPluginCall( 132437748cd8SNickeau $pluginName, 132537748cd8SNickeau $callStackArray, 132637748cd8SNickeau DOKU_LEXER_ENTER, 132737748cd8SNickeau null, 132837748cd8SNickeau null 132937748cd8SNickeau ); 133037748cd8SNickeau } 133137748cd8SNickeau 133237748cd8SNickeau /** 133337748cd8SNickeau * Add an end call dynamically 133437748cd8SNickeau * @param \Doku_Handler $handler 133537748cd8SNickeau * @param $tagName 133637748cd8SNickeau * @param array $callStackArray 133737748cd8SNickeau */ 133837748cd8SNickeau public 133937748cd8SNickeau static function addEndCall(\Doku_Handler $handler, $tagName, $callStackArray = array()) 134037748cd8SNickeau { 134137748cd8SNickeau $pluginName = PluginUtility::getComponentName($tagName); 134237748cd8SNickeau $handler->addPluginCall( 134337748cd8SNickeau $pluginName, 134437748cd8SNickeau $callStackArray, 134537748cd8SNickeau DOKU_LEXER_END, 134637748cd8SNickeau null, 134737748cd8SNickeau null 134837748cd8SNickeau ); 134937748cd8SNickeau } 135037748cd8SNickeau 135137748cd8SNickeau /** 135237748cd8SNickeau * General Debug 135337748cd8SNickeau */ 135437748cd8SNickeau public 135537748cd8SNickeau static function isDebug() 135637748cd8SNickeau { 135737748cd8SNickeau global $conf; 135837748cd8SNickeau return $conf["allowdebug"] === 1; 135937748cd8SNickeau 136037748cd8SNickeau } 136137748cd8SNickeau 136237748cd8SNickeau 136337748cd8SNickeau /** 136437748cd8SNickeau * 136537748cd8SNickeau * See also dev.md file 136637748cd8SNickeau */ 136737748cd8SNickeau public static function isDevOrTest() 136837748cd8SNickeau { 136937748cd8SNickeau if (self::isDev()) { 137037748cd8SNickeau return true; 137137748cd8SNickeau } 137237748cd8SNickeau return self::isTest(); 137337748cd8SNickeau } 137437748cd8SNickeau 1375*4cadd4f8SNickeau /** 1376*4cadd4f8SNickeau * Is this a dev environment (ie laptop where the dev is working) 1377*4cadd4f8SNickeau * @return bool 1378*4cadd4f8SNickeau */ 1379*4cadd4f8SNickeau public static function isDev(): bool 138037748cd8SNickeau { 138137748cd8SNickeau global $_SERVER; 138237748cd8SNickeau if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1") { 138337748cd8SNickeau return true; 138437748cd8SNickeau } 1385*4cadd4f8SNickeau if ($_SERVER["COMPUTERNAME"] === "NICO") { 1386*4cadd4f8SNickeau return true; 1387*4cadd4f8SNickeau } 138837748cd8SNickeau return false; 138937748cd8SNickeau } 139037748cd8SNickeau 139137748cd8SNickeau public static function getInstructions($markiCode) 139237748cd8SNickeau { 139337748cd8SNickeau return p_get_instructions($markiCode); 139437748cd8SNickeau } 139537748cd8SNickeau 139637748cd8SNickeau public static function getInstructionsWithoutRoot($markiCode) 139737748cd8SNickeau { 139837748cd8SNickeau return RenderUtility::getInstructionsAndStripPEventually($markiCode); 139937748cd8SNickeau } 140037748cd8SNickeau 140137748cd8SNickeau public static function isTest() 140237748cd8SNickeau { 140337748cd8SNickeau return defined('DOKU_UNITTEST'); 140437748cd8SNickeau } 140537748cd8SNickeau 140637748cd8SNickeau 1407c3437056SNickeau public static function getCacheManager(): CacheManager 140837748cd8SNickeau { 1409c3437056SNickeau return CacheManager::getOrCreate(); 141037748cd8SNickeau } 141137748cd8SNickeau 141237748cd8SNickeau public static function getModeFromPluginName($name) 141337748cd8SNickeau { 141437748cd8SNickeau return "plugin_$name"; 141537748cd8SNickeau } 141637748cd8SNickeau 141737748cd8SNickeau public static function isCi(): bool 141837748cd8SNickeau { 141937748cd8SNickeau // https://docs.travis-ci.com/user/environment-variables/#default-environment-variables 142037748cd8SNickeau return getenv("CI") === "true"; 142137748cd8SNickeau } 142237748cd8SNickeau 1423*4cadd4f8SNickeau public static function htmlDecode($int): string 1424*4cadd4f8SNickeau { 1425*4cadd4f8SNickeau return htmlspecialchars_decode($int, ENT_XHTML | ENT_QUOTES); 1426*4cadd4f8SNickeau } 1427*4cadd4f8SNickeau 1428*4cadd4f8SNickeau /** 1429*4cadd4f8SNickeau * Tells if the process is to output a page 1430*4cadd4f8SNickeau * @return bool 1431*4cadd4f8SNickeau */ 1432*4cadd4f8SNickeau public static function isRenderingRequestedPageProcess(): bool 1433*4cadd4f8SNickeau { 1434*4cadd4f8SNickeau 1435*4cadd4f8SNickeau global $ID; 1436*4cadd4f8SNickeau if (empty($ID)) { 1437*4cadd4f8SNickeau // $ID is null 1438*4cadd4f8SNickeau // case on "/lib/exe/mediamanager.php" 1439*4cadd4f8SNickeau return false; 1440*4cadd4f8SNickeau } 1441*4cadd4f8SNickeau 1442*4cadd4f8SNickeau $page = Page::createPageFromId($ID); 1443*4cadd4f8SNickeau if (!$page->exists()) { 1444*4cadd4f8SNickeau return false; 1445*4cadd4f8SNickeau } 1446*4cadd4f8SNickeau 1447*4cadd4f8SNickeau /** 1448*4cadd4f8SNickeau * No metadata for bars 1449*4cadd4f8SNickeau */ 1450*4cadd4f8SNickeau if ($page->isSecondarySlot()) { 1451*4cadd4f8SNickeau return false; 1452*4cadd4f8SNickeau } 1453*4cadd4f8SNickeau return true; 1454*4cadd4f8SNickeau 1455*4cadd4f8SNickeau } 1456*4cadd4f8SNickeau 1457*4cadd4f8SNickeau /** 1458*4cadd4f8SNickeau * @throws ExceptionCombo 1459*4cadd4f8SNickeau */ 1460*4cadd4f8SNickeau public static function renderInstructionsToXhtml($callStackHeaderInstructions): ?string 1461*4cadd4f8SNickeau { 1462*4cadd4f8SNickeau return RenderUtility::renderInstructionsToXhtml($callStackHeaderInstructions); 1463*4cadd4f8SNickeau } 1464*4cadd4f8SNickeau 1465*4cadd4f8SNickeau /** 1466*4cadd4f8SNickeau */ 1467*4cadd4f8SNickeau public static function getCurrentSlotId() 1468*4cadd4f8SNickeau { 1469*4cadd4f8SNickeau global $ID; 1470*4cadd4f8SNickeau $slot = $ID; 1471*4cadd4f8SNickeau if ($slot === null) { 1472*4cadd4f8SNickeau if (!PluginUtility::isTest()) { 1473*4cadd4f8SNickeau LogUtility::msg("The slot could not be identified (global ID is null)"); 1474*4cadd4f8SNickeau } 1475*4cadd4f8SNickeau return RenderUtility::DEFAULT_SLOT_ID_FOR_TEST; 1476*4cadd4f8SNickeau } 1477*4cadd4f8SNickeau return $slot; 1478*4cadd4f8SNickeau } 1479*4cadd4f8SNickeau 148037748cd8SNickeau 148137748cd8SNickeau} 148237748cd8SNickeau 148337748cd8SNickeauPluginUtility::init(); 1484