xref: /plugin/combo/ComboStrap/PluginUtility.php (revision 0e43c1db59ebeeac06e9a22249bf3806a94553d4)
137748cd8SNickeau<?php
237748cd8SNickeau
337748cd8SNickeau
437748cd8SNickeaunamespace ComboStrap;
537748cd8SNickeau
637748cd8SNickeau
737748cd8SNickeauuse dokuwiki\Extension\Plugin;
837748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin;
937748cd8SNickeau
1037748cd8SNickeaurequire_once(__DIR__ . '/../vendor/autoload.php');
1137748cd8SNickeau
1237748cd8SNickeau/**
131fa8c418SNickeau * Parent in th hierarchy should be first
141fa8c418SNickeau * Ie before {@link ImageLink, SvgImageLink, RasterImageLink)
151fa8c418SNickeau */
16c3437056SNickeaurequire_once(__DIR__ . '/CachedDocument.php');
17c3437056SNickeaurequire_once(__DIR__ . '/PageCompilerDocument.php');
18c3437056SNickeaurequire_once(__DIR__ . '/OutputDocument.php');
19c3437056SNickeaurequire_once(__DIR__ . '/FileSystem.php');
20c3437056SNickeaurequire_once(__DIR__ . '/Path.php');
21c3437056SNickeaurequire_once(__DIR__ . '/PathAbs.php');
22c3437056SNickeaurequire_once(__DIR__ . '/File.php');
23c3437056SNickeaurequire_once(__DIR__ . '/DokuFs.php');
241fa8c418SNickeaurequire_once(__DIR__ . '/DokuPath.php');
25c3437056SNickeaurequire_once(__DIR__ . '/ResourceCombo.php');
26c3437056SNickeaurequire_once(__DIR__ . '/ResourceComboAbs.php');
271fa8c418SNickeaurequire_once(__DIR__ . '/Media.php');
281fa8c418SNickeaurequire_once(__DIR__ . '/MediaLink.php');
29c3437056SNickeaurequire_once(__DIR__ . '/Metadata.php');
30c3437056SNickeaurequire_once(__DIR__ . '/MetadataBoolean.php');
31c3437056SNickeaurequire_once(__DIR__ . '/MetadataDateTime.php');
32c3437056SNickeaurequire_once(__DIR__ . '/MetadataMultiple.php');
33c3437056SNickeaurequire_once(__DIR__ . '/MetadataTabular.php');
34c3437056SNickeaurequire_once(__DIR__ . '/MetadataText.php');
35c3437056SNickeaurequire_once(__DIR__ . '/MetadataJson.php');
36c3437056SNickeaurequire_once(__DIR__ . '/MetadataWikiPath.php');
37c3437056SNickeaurequire_once(__DIR__ . '/MetadataStore.php');
38c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreAbs.php');
39c3437056SNickeaurequire_once(__DIR__ . '/MetadataSingleArrayStore.php');
401fa8c418SNickeau
411fa8c418SNickeau/**
4237748cd8SNickeau * Plugin Utility is added in all Dokuwiki extension
4337748cd8SNickeau * and
4437748cd8SNickeau * all classes are added in plugin utility
4537748cd8SNickeau *
4637748cd8SNickeau * This is an utility master and the class loader
4737748cd8SNickeau *
4837748cd8SNickeau * If the load is relative, the load path is used
4937748cd8SNickeau * and the bad php file may be loaded
5037748cd8SNickeau * Furthermore, the absolute path helps
5137748cd8SNickeau * the IDE when refactoring
5237748cd8SNickeau */
5337748cd8SNickeaurequire_once(__DIR__ . '/AdsUtility.php');
54c3437056SNickeaurequire_once(__DIR__ . '/Alias.php');
55c3437056SNickeaurequire_once(__DIR__ . '/AliasPath.php');
56c3437056SNickeaurequire_once(__DIR__ . '/AliasType.php');
57c3437056SNickeaurequire_once(__DIR__ . '/Aliases.php');
5837748cd8SNickeaurequire_once(__DIR__ . '/Align.php');
59c3437056SNickeaurequire_once(__DIR__ . '/AnalyticsDocument.php');
6037748cd8SNickeaurequire_once(__DIR__ . '/AnalyticsMenuItem.php');
6137748cd8SNickeaurequire_once(__DIR__ . '/Animation.php');
6237748cd8SNickeaurequire_once(__DIR__ . '/ArrayCaseInsensitive.php');
6337748cd8SNickeaurequire_once(__DIR__ . '/ArrayUtility.php');
6437748cd8SNickeaurequire_once(__DIR__ . '/Background.php');
65c3437056SNickeaurequire_once(__DIR__ . '/BacklinkCount.php');
66c3437056SNickeaurequire_once(__DIR__ . '/BacklinkMenuItem.php');
6737748cd8SNickeaurequire_once(__DIR__ . '/Boldness.php');
68c3437056SNickeaurequire_once(__DIR__ . '/Boolean.php');
6937748cd8SNickeaurequire_once(__DIR__ . '/Bootstrap.php');
7037748cd8SNickeaurequire_once(__DIR__ . '/BreadcrumbHierarchical.php');
71c3437056SNickeaurequire_once(__DIR__ . '/CacheExpirationDate.php');
72c3437056SNickeaurequire_once(__DIR__ . '/CacheExpirationFrequency.php');
7337748cd8SNickeaurequire_once(__DIR__ . '/CacheByLogicalKey.php');
7437748cd8SNickeaurequire_once(__DIR__ . '/CacheInstructionsByLogicalKey.php');
7537748cd8SNickeaurequire_once(__DIR__ . '/CacheManager.php');
7637748cd8SNickeaurequire_once(__DIR__ . '/CacheMedia.php');
7737748cd8SNickeaurequire_once(__DIR__ . '/Call.php');
7837748cd8SNickeaurequire_once(__DIR__ . '/CallStack.php');
79c3437056SNickeaurequire_once(__DIR__ . '/Canonical.php');
8037748cd8SNickeaurequire_once(__DIR__ . '/ColorUtility.php');
8137748cd8SNickeaurequire_once(__DIR__ . '/ConditionalValue.php');
82c3437056SNickeaurequire_once(__DIR__ . '/Console.php');
83c3437056SNickeaurequire_once(__DIR__ . '/Cron.php');
84c3437056SNickeaurequire_once(__DIR__ . '/DatabasePageRow.php');
85c3437056SNickeaurequire_once(__DIR__ . '/DataType.php');
8637748cd8SNickeaurequire_once(__DIR__ . '/Dimension.php');
87c3437056SNickeaurequire_once(__DIR__ . '/DisqusIdentifier.php');
8837748cd8SNickeaurequire_once(__DIR__ . '/DokuwikiUrl.php');
89c3437056SNickeaurequire_once(__DIR__ . '/DokuwikiId.php');
90c3437056SNickeaurequire_once(__DIR__ . '/EndDate.php');
91c3437056SNickeaurequire_once(__DIR__ . '/Event.php');
921fa8c418SNickeaurequire_once(__DIR__ . '/ExitException.php');
93c3437056SNickeaurequire_once(__DIR__ . '/ExceptionCombo.php');
94c3437056SNickeaurequire_once(__DIR__ . '/ExceptionComboRuntime.php');
95c3437056SNickeaurequire_once(__DIR__ . '/FileSystems.php');
9637748cd8SNickeaurequire_once(__DIR__ . '/FloatAttribute.php');
97c3437056SNickeaurequire_once(__DIR__ . '/FormMeta.php');
98c3437056SNickeaurequire_once(__DIR__ . '/FormMetaTab.php');
99c3437056SNickeaurequire_once(__DIR__ . '/FormMetaField.php');
10037748cd8SNickeaurequire_once(__DIR__ . '/FontSize.php');
10137748cd8SNickeaurequire_once(__DIR__ . '/FsWikiUtility.php');
10237748cd8SNickeaurequire_once(__DIR__ . '/HeaderUtility.php');
103c3437056SNickeaurequire_once(__DIR__ . '/HtmlDocument.php');
10437748cd8SNickeaurequire_once(__DIR__ . '/HistoricalBreadcrumbMenuItem.php');
10537748cd8SNickeaurequire_once(__DIR__ . '/Hover.php');
106c3437056SNickeaurequire_once(__DIR__ . '/Html.php');
10737748cd8SNickeaurequire_once(__DIR__ . '/Http.php');
108c3437056SNickeaurequire_once(__DIR__ . '/HttpResponse.php');
10937748cd8SNickeaurequire_once(__DIR__ . '/Icon.php');
11037748cd8SNickeaurequire_once(__DIR__ . '/Identity.php');
1111fa8c418SNickeaurequire_once(__DIR__ . '/Image.php');
1121fa8c418SNickeaurequire_once(__DIR__ . '/ImageLink.php');
1131fa8c418SNickeaurequire_once(__DIR__ . '/ImageRaster.php');
1141fa8c418SNickeaurequire_once(__DIR__ . '/ImageSvg.php');
115c3437056SNickeaurequire_once(__DIR__ . '/Index.php');
116c3437056SNickeaurequire_once(__DIR__ . '/InstructionsDocument.php');
117c3437056SNickeaurequire_once(__DIR__ . '/InternetPath.php');
118c3437056SNickeaurequire_once(__DIR__ . '/InterWikiPath.php');
11937748cd8SNickeaurequire_once(__DIR__ . '/Iso8601Date.php');
1201fa8c418SNickeaurequire_once(__DIR__ . '/Json.php');
121c3437056SNickeaurequire_once(__DIR__ . '/JavascriptLibrary.php');
12237748cd8SNickeaurequire_once(__DIR__ . '/Lang.php');
123c3437056SNickeaurequire_once(__DIR__ . '/LdJson.php');
12437748cd8SNickeaurequire_once(__DIR__ . '/LineSpacing.php');
125c3437056SNickeaurequire_once(__DIR__ . '/Locale.php');
126c3437056SNickeaurequire_once(__DIR__ . '/LocalFs.php');
127c3437056SNickeaurequire_once(__DIR__ . '/LocalPath.php');
1281fa8c418SNickeaurequire_once(__DIR__ . '/LogException.php');
12937748cd8SNickeaurequire_once(__DIR__ . '/LogUtility.php');
13037748cd8SNickeaurequire_once(__DIR__ . '/LowQualityPage.php');
131c3437056SNickeaurequire_once(__DIR__ . '/LowQualityPageOverwrite.php');
132c3437056SNickeaurequire_once(__DIR__ . '/LowQualityCalculatedIndicator.php');
133c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerForm.php');
134c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerMenuItem.php');
135c3437056SNickeaurequire_once(__DIR__ . '/MetadataDokuWikiStore.php');
136c3437056SNickeaurequire_once(__DIR__ . '/MetadataFormDataStore.php');
137c3437056SNickeaurequire_once(__DIR__ . '/MetadataFrontmatterStore.php');
138c3437056SNickeaurequire_once(__DIR__ . '/MetadataDbStore.php');
139c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreTransfer.php');
1401fa8c418SNickeaurequire_once(__DIR__ . '/Message.php');
1411fa8c418SNickeaurequire_once(__DIR__ . '/Mermaid.php');
142c3437056SNickeaurequire_once(__DIR__ . '/Mime.php');
143c3437056SNickeaurequire_once(__DIR__ . '/ModificationDate.php');
14437748cd8SNickeaurequire_once(__DIR__ . '/NavBarUtility.php');
14537748cd8SNickeaurequire_once(__DIR__ . '/Opacity.php');
1461fa8c418SNickeaurequire_once(__DIR__ . '/Os.php');
14737748cd8SNickeaurequire_once(__DIR__ . '/Page.php');
148c3437056SNickeaurequire_once(__DIR__ . '/PageDescription.php');
149c3437056SNickeaurequire_once(__DIR__ . '/PageId.php');
150c3437056SNickeaurequire_once(__DIR__ . '/PageKeywords.php');
151c3437056SNickeaurequire_once(__DIR__ . '/PageImages.php');
152c3437056SNickeaurequire_once(__DIR__ . '/PageImage.php');
153c3437056SNickeaurequire_once(__DIR__ . '/PageImagePath.php');
154c3437056SNickeaurequire_once(__DIR__ . '/PageImageUsage.php');
155c3437056SNickeaurequire_once(__DIR__ . '/PageLayout.php');
156c3437056SNickeaurequire_once(__DIR__ . '/PagePath.php');
15737748cd8SNickeaurequire_once(__DIR__ . '/PageProtection.php');
15837748cd8SNickeaurequire_once(__DIR__ . '/PageRules.php');
159c3437056SNickeaurequire_once(__DIR__ . '/PageScope.php');
16037748cd8SNickeaurequire_once(__DIR__ . '/PageSql.php');
16137748cd8SNickeaurequire_once(__DIR__ . '/PageSqlParser/PageSqlLexer.php');
16237748cd8SNickeaurequire_once(__DIR__ . '/PageSqlParser/PageSqlParser.php');
16337748cd8SNickeaurequire_once(__DIR__ . '/PageSqlTreeListener.php');
164c3437056SNickeaurequire_once(__DIR__ . '/PageType.php');
165c3437056SNickeaurequire_once(__DIR__ . '/PageTitle.php');
166c3437056SNickeaurequire_once(__DIR__ . '/PageUrlPath.php');
167c3437056SNickeaurequire_once(__DIR__ . '/PageUrlType.php');
16837748cd8SNickeaurequire_once(__DIR__ . '/PipelineUtility.php');
16937748cd8SNickeaurequire_once(__DIR__ . '/Position.php');
17037748cd8SNickeaurequire_once(__DIR__ . '/Prism.php');
171c3437056SNickeaurequire_once(__DIR__ . '/PagePublicationDate.php');
172c3437056SNickeaurequire_once(__DIR__ . '/PageCreationDate.php');
173c3437056SNickeaurequire_once(__DIR__ . '/PageH1.php');
174c3437056SNickeaurequire_once(__DIR__ . '/QualityDynamicMonitoringOverwrite.php');
175c3437056SNickeaurequire_once(__DIR__ . '/QualityMenuItem.php');
17637748cd8SNickeaurequire_once(__DIR__ . '/RasterImageLink.php');
177c3437056SNickeaurequire_once(__DIR__ . '/Region.php');
17837748cd8SNickeaurequire_once(__DIR__ . '/RenderUtility.php');
179c3437056SNickeaurequire_once(__DIR__ . '/ReplicationDate.php');
18037748cd8SNickeaurequire_once(__DIR__ . '/Resources.php');
181c3437056SNickeaurequire_once(__DIR__ . '/ResourceName.php');
1821fa8c418SNickeaurequire_once(__DIR__ . '/Sanitizer.php');
18337748cd8SNickeaurequire_once(__DIR__ . '/Shadow.php');
18437748cd8SNickeaurequire_once(__DIR__ . '/Site.php');
18537748cd8SNickeaurequire_once(__DIR__ . '/Skin.php');
186c3437056SNickeaurequire_once(__DIR__ . '/Slug.php');
18737748cd8SNickeaurequire_once(__DIR__ . '/Snippet.php');
18837748cd8SNickeaurequire_once(__DIR__ . '/SnippetManager.php');
18937748cd8SNickeaurequire_once(__DIR__ . '/Spacing.php');
19037748cd8SNickeaurequire_once(__DIR__ . '/Sqlite.php');
191c3437056SNickeaurequire_once(__DIR__ . '/SqliteRequest.php');
192c3437056SNickeaurequire_once(__DIR__ . '/SqliteResult.php');
19337748cd8SNickeaurequire_once(__DIR__ . '/StringUtility.php');
194c3437056SNickeaurequire_once(__DIR__ . '/StartDate.php');
19537748cd8SNickeaurequire_once(__DIR__ . '/StyleUtility.php');
19637748cd8SNickeaurequire_once(__DIR__ . '/SvgDocument.php');
19737748cd8SNickeaurequire_once(__DIR__ . '/SvgImageLink.php');
19837748cd8SNickeaurequire_once(__DIR__ . '/Syntax.php');
19937748cd8SNickeaurequire_once(__DIR__ . '/TableUtility.php');
20037748cd8SNickeaurequire_once(__DIR__ . '/Tag.php');
20137748cd8SNickeaurequire_once(__DIR__ . '/TagAttributes.php');
20237748cd8SNickeaurequire_once(__DIR__ . '/Template.php');
203c3437056SNickeaurequire_once(__DIR__ . '/TemplateStore.php');
20437748cd8SNickeaurequire_once(__DIR__ . '/TemplateUtility.php');
20537748cd8SNickeaurequire_once(__DIR__ . '/TextAlign.php');
20637748cd8SNickeaurequire_once(__DIR__ . '/TextColor.php');
207c3437056SNickeaurequire_once(__DIR__ . '/ThirdMedia.php');
20837748cd8SNickeaurequire_once(__DIR__ . '/ThirdMediaLink.php');
20937748cd8SNickeaurequire_once(__DIR__ . '/ThirdPartyPlugins.php');
21037748cd8SNickeaurequire_once(__DIR__ . '/TocUtility.php');
21137748cd8SNickeaurequire_once(__DIR__ . '/Toggle.php');
212c3437056SNickeaurequire_once(__DIR__ . '/References.php');
213c3437056SNickeaurequire_once(__DIR__ . '/Reference.php');
21437748cd8SNickeaurequire_once(__DIR__ . '/Underline.php');
21537748cd8SNickeaurequire_once(__DIR__ . '/Unit.php');
216c3437056SNickeaurequire_once(__DIR__ . '/Url.php');
21737748cd8SNickeaurequire_once(__DIR__ . '/UrlManagerBestEndPage.php');
21837748cd8SNickeaurequire_once(__DIR__ . '/XhtmlUtility.php');
21937748cd8SNickeaurequire_once(__DIR__ . '/XmlDocument.php');
22037748cd8SNickeaurequire_once(__DIR__ . '/XmlUtility.php');
22137748cd8SNickeau
22237748cd8SNickeau
22337748cd8SNickeau/**
22437748cd8SNickeau * Class url static
22537748cd8SNickeau * List of static utilities
22637748cd8SNickeau */
22737748cd8SNickeauclass PluginUtility
22837748cd8SNickeau{
22937748cd8SNickeau
23037748cd8SNickeau    const DOKU_DATA_DIR = '/dokudata/pages';
23137748cd8SNickeau    const DOKU_CACHE_DIR = '/dokudata/cache';
23237748cd8SNickeau
23337748cd8SNickeau    /**
23437748cd8SNickeau     * Key in the data array between the handle and render function
23537748cd8SNickeau     */
23637748cd8SNickeau    const STATE = "state";
23737748cd8SNickeau    const PAYLOAD = "payload"; // The html or text
23837748cd8SNickeau    const ATTRIBUTES = "attributes";
23937748cd8SNickeau    // The context is generally the parent tag but it may be also the grandfather.
24037748cd8SNickeau    // It permits to determine the HTML that is outputted
24137748cd8SNickeau    const CONTEXT = 'context';
24237748cd8SNickeau    const TAG = "tag";
24337748cd8SNickeau
24437748cd8SNickeau    /**
24537748cd8SNickeau     * The name of the hidden/private namespace
24637748cd8SNickeau     * where the icon and other artifactory are stored
24737748cd8SNickeau     */
24837748cd8SNickeau    const COMBOSTRAP_NAMESPACE_NAME = "combostrap";
24937748cd8SNickeau
25037748cd8SNickeau    const PARENT = "parent";
25137748cd8SNickeau    const POSITION = "position";
25237748cd8SNickeau
25337748cd8SNickeau    /**
25437748cd8SNickeau     * Class to center an element
25537748cd8SNickeau     */
25637748cd8SNickeau    const CENTER_CLASS = "mx-auto";
25737748cd8SNickeau
25837748cd8SNickeau
25937748cd8SNickeau    const EDIT_SECTION_TARGET = 'section';
26037748cd8SNickeau    const ERROR_MESSAGE = "errorAtt";
2611fa8c418SNickeau    const ERROR_LEVEL = "errorLevel";
2621fa8c418SNickeau    const DISPLAY = "display";
26337748cd8SNickeau
26437748cd8SNickeau    /**
26537748cd8SNickeau     * The URL base of the documentation
26637748cd8SNickeau     */
267c3437056SNickeau    static $URL_APEX;
26837748cd8SNickeau
26937748cd8SNickeau
27037748cd8SNickeau    /**
27137748cd8SNickeau     * @var string - the plugin base name (ie the directory)
27237748cd8SNickeau     * ie $INFO_PLUGIN['base'];
27337748cd8SNickeau     * This is a constant because it permits code analytics
27437748cd8SNickeau     * such as verification of a path
27537748cd8SNickeau     */
27637748cd8SNickeau    const PLUGIN_BASE_NAME = "combo";
27737748cd8SNickeau
27837748cd8SNickeau    /**
27937748cd8SNickeau     * The name of the template plugin
28037748cd8SNickeau     */
28137748cd8SNickeau    const TEMPLATE_STRAP_NAME = "strap";
28237748cd8SNickeau
28337748cd8SNickeau    /**
28437748cd8SNickeau     * @var array
28537748cd8SNickeau     */
28637748cd8SNickeau    static $INFO_PLUGIN;
28737748cd8SNickeau
28837748cd8SNickeau    static $PLUGIN_LANG;
28937748cd8SNickeau
29037748cd8SNickeau    /**
29137748cd8SNickeau     * The plugin name
29237748cd8SNickeau     * (not the same than the base as it's not related to the directory
29337748cd8SNickeau     * @var string
29437748cd8SNickeau     */
29537748cd8SNickeau    public static $PLUGIN_NAME;
29637748cd8SNickeau    /**
29737748cd8SNickeau     * @var mixed the version
29837748cd8SNickeau     */
29937748cd8SNickeau    private static $VERSION;
30037748cd8SNickeau
30137748cd8SNickeau
30237748cd8SNickeau    /**
30337748cd8SNickeau     * Initiate the static variable
30437748cd8SNickeau     * See the call after this class
30537748cd8SNickeau     */
30637748cd8SNickeau    static function init()
30737748cd8SNickeau    {
30837748cd8SNickeau
30937748cd8SNickeau        $pluginInfoFile = __DIR__ . '/../plugin.info.txt';
31037748cd8SNickeau        self::$INFO_PLUGIN = confToHash($pluginInfoFile);
31137748cd8SNickeau        self::$PLUGIN_NAME = 'ComboStrap';
31237748cd8SNickeau        global $lang;
31337748cd8SNickeau        self::$PLUGIN_LANG = $lang[self::PLUGIN_BASE_NAME];
314c3437056SNickeau        self::$URL_APEX = "https://" . parse_url(self::$INFO_PLUGIN['url'], PHP_URL_HOST);
31537748cd8SNickeau        self::$VERSION = self::$INFO_PLUGIN['version'];
31637748cd8SNickeau
31737748cd8SNickeau    }
31837748cd8SNickeau
31937748cd8SNickeau    /**
32037748cd8SNickeau     * @param $inputExpression
32137748cd8SNickeau     * @return false|int 1|0
32237748cd8SNickeau     * returns:
32337748cd8SNickeau     *    - 1 if the input expression is a pattern,
32437748cd8SNickeau     *    - 0 if not,
32537748cd8SNickeau     *    - FALSE if an error occurred.
32637748cd8SNickeau     */
32737748cd8SNickeau    static function isRegularExpression($inputExpression)
32837748cd8SNickeau    {
32937748cd8SNickeau
33037748cd8SNickeau        $regularExpressionPattern = "/(\\/.*\\/[gmixXsuUAJ]?)/";
33137748cd8SNickeau        return preg_match($regularExpressionPattern, $inputExpression);
33237748cd8SNickeau
33337748cd8SNickeau    }
33437748cd8SNickeau
33537748cd8SNickeau    /**
33637748cd8SNickeau     * Return a mode from a tag (ie from a {@link Plugin::getPluginComponent()}
33737748cd8SNickeau     * @param $tag
33837748cd8SNickeau     * @return string
33937748cd8SNickeau     *
34037748cd8SNickeau     * A mode is just a name for a class
34137748cd8SNickeau     * Example: $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock());
34237748cd8SNickeau     */
34337748cd8SNickeau    public static function getModeFromTag($tag)
34437748cd8SNickeau    {
34537748cd8SNickeau        return "plugin_" . self::getComponentName($tag);
34637748cd8SNickeau    }
34737748cd8SNickeau
34837748cd8SNickeau    /**
34937748cd8SNickeau     * @param $tag
35037748cd8SNickeau     * @return string
35137748cd8SNickeau     *
35237748cd8SNickeau     * Create a lookahead pattern for a container tag used to enter in a mode
35337748cd8SNickeau     */
35437748cd8SNickeau    public static function getContainerTagPattern($tag)
35537748cd8SNickeau    {
35637748cd8SNickeau        // this pattern ensure that the tag
35737748cd8SNickeau        // `accordion` will not intercept also the tag `accordionitem`
35837748cd8SNickeau        // where:
35937748cd8SNickeau        // ?: means non capturing group (to not capture the last >)
36037748cd8SNickeau        // (\s.*?): is a capturing group that starts with a space
36137748cd8SNickeau        $pattern = "(?:\s.*?>|>)";
36237748cd8SNickeau        return '<' . $tag . $pattern . '(?=.*?<\/' . $tag . '>)';
36337748cd8SNickeau    }
36437748cd8SNickeau
36537748cd8SNickeau    /**
36637748cd8SNickeau     * This pattern allows space after the tag name
36737748cd8SNickeau     * for an end tag
36837748cd8SNickeau     * As XHTML (https://www.w3.org/TR/REC-xml/#dt-etag)
36937748cd8SNickeau     * @param $tag
37037748cd8SNickeau     * @return string
37137748cd8SNickeau     */
37237748cd8SNickeau    public static function getEndTagPattern($tag)
37337748cd8SNickeau    {
37437748cd8SNickeau        return "</$tag\s*>";
37537748cd8SNickeau    }
37637748cd8SNickeau
37737748cd8SNickeau    /**
37837748cd8SNickeau     * @param $tag
37937748cd8SNickeau     * @return string
38037748cd8SNickeau     *
38137748cd8SNickeau     * Create a open tag pattern without lookahead.
382c3437056SNickeau     * Used for
383c3437056SNickeau     * @link https://dev.w3.org/html5/html-author/#void-elements-0
38437748cd8SNickeau     */
38537748cd8SNickeau    public static function getVoidElementTagPattern($tag)
38637748cd8SNickeau    {
38737748cd8SNickeau        return '<' . $tag . '.*?>';
38837748cd8SNickeau    }
38937748cd8SNickeau
39037748cd8SNickeau
39137748cd8SNickeau    /**
39237748cd8SNickeau     * Take an array  where the key is the attribute name
39337748cd8SNickeau     * and return a HTML tag string
39437748cd8SNickeau     *
39537748cd8SNickeau     * The attribute name and value are escaped
39637748cd8SNickeau     *
39737748cd8SNickeau     * @param $attributes - combo attributes
39837748cd8SNickeau     * @return string
39937748cd8SNickeau     * @deprecated to allowed background and other metadata, use {@link TagAttributes::toHtmlEnterTag()}
40037748cd8SNickeau     */
40137748cd8SNickeau    public static function array2HTMLAttributesAsString($attributes)
40237748cd8SNickeau    {
40337748cd8SNickeau
40437748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
40537748cd8SNickeau        return $tagAttributes->toHTMLAttributeString();
40637748cd8SNickeau
40737748cd8SNickeau    }
40837748cd8SNickeau
40937748cd8SNickeau    /**
41037748cd8SNickeau     *
41137748cd8SNickeau     * Parse the attributes part of a match
41237748cd8SNickeau     *
41337748cd8SNickeau     * Example:
41437748cd8SNickeau     *   line-numbers="value"
41537748cd8SNickeau     *   line-numbers='value'
41637748cd8SNickeau     *
41737748cd8SNickeau     * This value may be in:
41837748cd8SNickeau     *   * configuration value
41937748cd8SNickeau     *   * as well as in the match of a {@link SyntaxPlugin}
42037748cd8SNickeau     *
42137748cd8SNickeau     * @param $string
42237748cd8SNickeau     * @return array
42337748cd8SNickeau     *
42437748cd8SNickeau     * To parse a match, use {@link PluginUtility::getTagAttributes()}
42537748cd8SNickeau     *
42637748cd8SNickeau     *
42737748cd8SNickeau     */
42837748cd8SNickeau    public static function parseAttributes($string)
42937748cd8SNickeau    {
43037748cd8SNickeau
43137748cd8SNickeau        $parameters = array();
43237748cd8SNickeau
43337748cd8SNickeau        // Rules
43437748cd8SNickeau        //  * name may be alone (ie true boolean attribute)
43537748cd8SNickeau        //  * a name may get a `-`
43637748cd8SNickeau        //  * there may be space every everywhere when the value is enclosed with a quote
43737748cd8SNickeau        //  * there may be no space in the value and between the equal sign when the value is not enclosed
43837748cd8SNickeau        //
43937748cd8SNickeau        // /i not case sensitive
44037748cd8SNickeau        $attributePattern = '\s*([-\w]+)\s*(?:=(\s*[\'"]([^`"]*)[\'"]\s*|[^\s]*))?';
44137748cd8SNickeau        $result = preg_match_all('/' . $attributePattern . '/i', $string, $matches);
44237748cd8SNickeau        if ($result != 0) {
44337748cd8SNickeau            foreach ($matches[1] as $key => $parameterKey) {
44437748cd8SNickeau
44537748cd8SNickeau                // group 3 (ie the value between quotes)
44637748cd8SNickeau                $value = $matches[3][$key];
44737748cd8SNickeau                if ($value == "") {
44837748cd8SNickeau                    // check the value without quotes
44937748cd8SNickeau                    $value = $matches[2][$key];
45037748cd8SNickeau                }
45137748cd8SNickeau                // if there is no value, this is a boolean
45237748cd8SNickeau                if ($value == "") {
45337748cd8SNickeau                    $value = true;
45437748cd8SNickeau                } else {
45537748cd8SNickeau                    $value = hsc($value);
45637748cd8SNickeau                }
45737748cd8SNickeau                $parameters[hsc(strtolower($parameterKey))] = $value;
45837748cd8SNickeau            }
45937748cd8SNickeau        }
46037748cd8SNickeau        return $parameters;
46137748cd8SNickeau
46237748cd8SNickeau    }
46337748cd8SNickeau
46437748cd8SNickeau    public static function getTagAttributes($match)
46537748cd8SNickeau    {
46637748cd8SNickeau        return self::getQualifiedTagAttributes($match, false, "");
46737748cd8SNickeau    }
46837748cd8SNickeau
46937748cd8SNickeau    /**
47037748cd8SNickeau     * Return the attribute of a tag
47137748cd8SNickeau     * Because they are users input, they are all escaped
47237748cd8SNickeau     * @param $match
47337748cd8SNickeau     * @param $hasThirdValue - if true, the third parameter is treated as value, not a property and returned in the `third` key
47437748cd8SNickeau     * use for the code/file/console where they accept a name as third value
47537748cd8SNickeau     * @param $keyThirdArgument - if a third argument is found, return it with this key
47637748cd8SNickeau     * @return array
47737748cd8SNickeau     */
47837748cd8SNickeau    public static function getQualifiedTagAttributes($match, $hasThirdValue, $keyThirdArgument)
47937748cd8SNickeau    {
48037748cd8SNickeau
48137748cd8SNickeau        $match = PluginUtility::getPreprocessEnterTag($match);
48237748cd8SNickeau
48337748cd8SNickeau        // Suppress the tag name (ie until the first blank)
48437748cd8SNickeau        $spacePosition = strpos($match, " ");
48537748cd8SNickeau        if (!$spacePosition) {
48637748cd8SNickeau            // No space, meaning this is only the tag name
48737748cd8SNickeau            return array();
48837748cd8SNickeau        }
48937748cd8SNickeau        $match = trim(substr($match, $spacePosition));
49037748cd8SNickeau        if ($match == "") {
49137748cd8SNickeau            return array();
49237748cd8SNickeau        }
49337748cd8SNickeau
49437748cd8SNickeau        // Do we have a type as first argument ?
49537748cd8SNickeau        $attributes = array();
49637748cd8SNickeau        $spacePosition = strpos($match, " ");
49737748cd8SNickeau        if ($spacePosition) {
49837748cd8SNickeau            $nextArgument = substr($match, 0, $spacePosition);
49937748cd8SNickeau        } else {
50037748cd8SNickeau            $nextArgument = $match;
50137748cd8SNickeau        }
50237748cd8SNickeau        if (!strpos($nextArgument, "=")) {
50337748cd8SNickeau            $attributes["type"] = $nextArgument;
50437748cd8SNickeau            // Suppress the type
50537748cd8SNickeau            $match = substr($match, strlen($nextArgument));
50637748cd8SNickeau            $match = trim($match);
50737748cd8SNickeau
50837748cd8SNickeau            // Do we have a value as first argument ?
50937748cd8SNickeau            if (!empty($hasThirdValue)) {
51037748cd8SNickeau                $spacePosition = strpos($match, " ");
51137748cd8SNickeau                if ($spacePosition) {
51237748cd8SNickeau                    $nextArgument = substr($match, 0, $spacePosition);
51337748cd8SNickeau                } else {
51437748cd8SNickeau                    $nextArgument = $match;
51537748cd8SNickeau                }
51637748cd8SNickeau                if (!strpos($nextArgument, "=") && !empty($nextArgument)) {
51737748cd8SNickeau                    $attributes[$keyThirdArgument] = $nextArgument;
51837748cd8SNickeau                    // Suppress the third argument
51937748cd8SNickeau                    $match = substr($match, strlen($nextArgument));
52037748cd8SNickeau                    $match = trim($match);
52137748cd8SNickeau                }
52237748cd8SNickeau            }
52337748cd8SNickeau        }
52437748cd8SNickeau
52537748cd8SNickeau        // Parse the remaining attributes
52637748cd8SNickeau        $parsedAttributes = self::parseAttributes($match);
52737748cd8SNickeau
52837748cd8SNickeau        // Merge
52937748cd8SNickeau        $attributes = array_merge($attributes, $parsedAttributes);;
53037748cd8SNickeau
53137748cd8SNickeau        return $attributes;
53237748cd8SNickeau
53337748cd8SNickeau    }
53437748cd8SNickeau
53537748cd8SNickeau    /**
53637748cd8SNickeau     * @param array $styleProperties - an array of CSS properties with key, value
53737748cd8SNickeau     * @return string - the value for the style attribute (ie all rules where joined with the comma)
53837748cd8SNickeau     */
53937748cd8SNickeau    public static function array2InlineStyle(array $styleProperties)
54037748cd8SNickeau    {
54137748cd8SNickeau        $inlineCss = "";
54237748cd8SNickeau        foreach ($styleProperties as $key => $value) {
54337748cd8SNickeau            $inlineCss .= "$key:$value;";
54437748cd8SNickeau        }
54537748cd8SNickeau        // Suppress the last ;
54637748cd8SNickeau        if ($inlineCss[strlen($inlineCss) - 1] == ";") {
54737748cd8SNickeau            $inlineCss = substr($inlineCss, 0, -1);
54837748cd8SNickeau        }
54937748cd8SNickeau        return $inlineCss;
55037748cd8SNickeau    }
55137748cd8SNickeau
55237748cd8SNickeau    /**
55337748cd8SNickeau     * @param $tag
55437748cd8SNickeau     * @return string
55537748cd8SNickeau     * Create a pattern used where the tag is not a container.
55637748cd8SNickeau     * ie
55737748cd8SNickeau     * <br/>
55837748cd8SNickeau     * <icon/>
55937748cd8SNickeau     * This is generally used with a subtition plugin
56037748cd8SNickeau     * and a {@link Lexer::addSpecialPattern} state
56137748cd8SNickeau     * where the tag is just replaced
56237748cd8SNickeau     */
56319494974Sgerardnico    public static function getEmptyTagPattern($tag): string
56437748cd8SNickeau    {
56519494974Sgerardnico
56619494974Sgerardnico        return '<' . $tag . '[^>]*/>';
56737748cd8SNickeau    }
56837748cd8SNickeau
56937748cd8SNickeau    /**
57037748cd8SNickeau     * Just call this function from a class like that
57137748cd8SNickeau     *     getTageName(get_called_class())
57237748cd8SNickeau     * to get the tag name (ie the component plugin)
57337748cd8SNickeau     * of a syntax plugin
57437748cd8SNickeau     *
57537748cd8SNickeau     * @param $get_called_class
57637748cd8SNickeau     * @return string
57737748cd8SNickeau     */
57837748cd8SNickeau    public static function getTagName($get_called_class)
57937748cd8SNickeau    {
58037748cd8SNickeau        list(/* $t */, /* $p */, /* $n */, $c) = explode('_', $get_called_class, 4);
58137748cd8SNickeau        return (isset($c) ? $c : '');
58237748cd8SNickeau    }
58337748cd8SNickeau
58437748cd8SNickeau    /**
58537748cd8SNickeau     * Just call this function from a class like that
58637748cd8SNickeau     *     getAdminPageName(get_called_class())
58737748cd8SNickeau     * to get the page name of a admin plugin
58837748cd8SNickeau     *
58937748cd8SNickeau     * @param $get_called_class
59037748cd8SNickeau     * @return string - the admin page name
59137748cd8SNickeau     */
59237748cd8SNickeau    public static function getAdminPageName($get_called_class)
59337748cd8SNickeau    {
59437748cd8SNickeau        $names = explode('_', $get_called_class);
59537748cd8SNickeau        $names = array_slice($names, -2);
59637748cd8SNickeau        return implode('_', $names);
59737748cd8SNickeau    }
59837748cd8SNickeau
59937748cd8SNickeau    public static function getNameSpace()
60037748cd8SNickeau    {
60137748cd8SNickeau        // No : at the begin of the namespace please
60237748cd8SNickeau        return self::PLUGIN_BASE_NAME . ':';
60337748cd8SNickeau    }
60437748cd8SNickeau
60537748cd8SNickeau    /**
60637748cd8SNickeau     * @param $get_called_class - the plugin class
60737748cd8SNickeau     * @return array
60837748cd8SNickeau     */
60937748cd8SNickeau    public static function getTags($get_called_class)
61037748cd8SNickeau    {
61137748cd8SNickeau        $elements = array();
61237748cd8SNickeau        $elementName = PluginUtility::getTagName($get_called_class);
61337748cd8SNickeau        $elements[] = $elementName;
61437748cd8SNickeau        $elements[] = strtoupper($elementName);
61537748cd8SNickeau        return $elements;
61637748cd8SNickeau    }
61737748cd8SNickeau
61837748cd8SNickeau    /**
61937748cd8SNickeau     * Render a text
62037748cd8SNickeau     * @param $pageContent
62137748cd8SNickeau     * @return string|null
62237748cd8SNickeau     */
62337748cd8SNickeau    public static function render($pageContent)
62437748cd8SNickeau    {
62537748cd8SNickeau        return RenderUtility::renderText2XhtmlAndStripPEventually($pageContent, false);
62637748cd8SNickeau    }
62737748cd8SNickeau
62837748cd8SNickeau
62937748cd8SNickeau    /**
63037748cd8SNickeau     * This method will takes attributes
63137748cd8SNickeau     * and process the plugin styling attribute such as width and height
63237748cd8SNickeau     * to put them in a style HTML attribute
63337748cd8SNickeau     * @param TagAttributes $attributes
63437748cd8SNickeau     */
63537748cd8SNickeau    public static function processStyle(&$attributes)
63637748cd8SNickeau    {
63737748cd8SNickeau        // Style
63837748cd8SNickeau        $styleAttributeName = "style";
63937748cd8SNickeau        if ($attributes->hasComponentAttribute($styleAttributeName)) {
64037748cd8SNickeau            $properties = explode(";", $attributes->getValueAndRemove($styleAttributeName));
64137748cd8SNickeau            foreach ($properties as $property) {
64237748cd8SNickeau                list($key, $value) = explode(":", $property);
64337748cd8SNickeau                if ($key != "") {
64437748cd8SNickeau                    $attributes->addStyleDeclaration($key, $value);
64537748cd8SNickeau                }
64637748cd8SNickeau            }
64737748cd8SNickeau        }
64837748cd8SNickeau
64937748cd8SNickeau
65037748cd8SNickeau        /**
65137748cd8SNickeau         * Border Color
65237748cd8SNickeau         * For background color, see {@link TagAttributes::processBackground()}
65337748cd8SNickeau         * For text color, see {@link TextColor}
65437748cd8SNickeau         */
65537748cd8SNickeau
65637748cd8SNickeau        if ($attributes->hasComponentAttribute(ColorUtility::BORDER_COLOR)) {
65737748cd8SNickeau            $colorValue = $attributes->getValueAndRemove(ColorUtility::BORDER_COLOR);
65837748cd8SNickeau            $attributes->addStyleDeclaration(ColorUtility::BORDER_COLOR, ColorUtility::getColorValue($colorValue));
65937748cd8SNickeau            self::checkDefaultBorderColorAttributes($attributes);
66037748cd8SNickeau        }
66137748cd8SNickeau
66237748cd8SNickeau
66337748cd8SNickeau    }
66437748cd8SNickeau
66537748cd8SNickeau    /**
66637748cd8SNickeau     * Return the name of the requested script
66737748cd8SNickeau     */
66837748cd8SNickeau    public
66937748cd8SNickeau    static function getRequestScript()
67037748cd8SNickeau    {
67137748cd8SNickeau        $scriptPath = null;
67237748cd8SNickeau        $testPropertyValue = self::getPropertyValue("SCRIPT_NAME");
67337748cd8SNickeau        if (defined('DOKU_UNITTEST') && $testPropertyValue != null) {
67437748cd8SNickeau            return $testPropertyValue;
67537748cd8SNickeau        }
67637748cd8SNickeau        if (array_key_exists("DOCUMENT_URI", $_SERVER)) {
67737748cd8SNickeau            $scriptPath = $_SERVER["DOCUMENT_URI"];
67837748cd8SNickeau        }
67937748cd8SNickeau        if ($scriptPath == null && array_key_exists("SCRIPT_NAME", $_SERVER)) {
68037748cd8SNickeau            $scriptPath = $_SERVER["SCRIPT_NAME"];
68137748cd8SNickeau        }
68237748cd8SNickeau        if ($scriptPath == null) {
68337748cd8SNickeau            msg("Unable to find the main script", LogUtility::LVL_MSG_ERROR);
68437748cd8SNickeau        }
68537748cd8SNickeau        $path_parts = pathinfo($scriptPath);
68637748cd8SNickeau        return $path_parts['basename'];
68737748cd8SNickeau    }
68837748cd8SNickeau
68937748cd8SNickeau    /**
69037748cd8SNickeau     *
69137748cd8SNickeau     * @param $name
69237748cd8SNickeau     * @param $default
69337748cd8SNickeau     * @return string - the value of a query string property or if in test mode, the value of a test variable
69437748cd8SNickeau     * set with {@link self::setTestProperty}
69537748cd8SNickeau     * This is used to test script that are not supported by the dokuwiki test framework
69637748cd8SNickeau     * such as css.php
69737748cd8SNickeau     */
69837748cd8SNickeau    public
69937748cd8SNickeau    static function getPropertyValue($name, $default = null)
70037748cd8SNickeau    {
70137748cd8SNickeau        global $INPUT;
70237748cd8SNickeau        $value = $INPUT->str($name);
70337748cd8SNickeau        if ($value == null && defined('DOKU_UNITTEST')) {
70437748cd8SNickeau            global $COMBO;
70537748cd8SNickeau            $value = $COMBO[$name];
70637748cd8SNickeau        }
70737748cd8SNickeau        if ($value == null) {
70837748cd8SNickeau            return $default;
70937748cd8SNickeau        } else {
71037748cd8SNickeau            return $value;
71137748cd8SNickeau        }
71237748cd8SNickeau
71337748cd8SNickeau    }
71437748cd8SNickeau
71537748cd8SNickeau    /**
71637748cd8SNickeau     * Create an URL to the documentation website
71737748cd8SNickeau     * @param $canonical - canonical id or slug
718c3437056SNickeau     * @param $label -  the text of the link
71937748cd8SNickeau     * @param bool $withIcon - used to break the recursion with the message in the {@link Icon}
72037748cd8SNickeau     * @return string - an url
72137748cd8SNickeau     */
72237748cd8SNickeau    public
723c3437056SNickeau    static function getDocumentationHyperLink($canonical, $label, $withIcon = true, $tooltip = ""): string
72437748cd8SNickeau    {
72537748cd8SNickeau        /** @noinspection SpellCheckingInspection */
72637748cd8SNickeau
72737748cd8SNickeau        $xhtmlIcon = "";
72837748cd8SNickeau        if ($withIcon) {
72937748cd8SNickeau
73037748cd8SNickeau            /**
73137748cd8SNickeau             * We don't include it as an external resource via url
73237748cd8SNickeau             * because it then make a http request for every logo
73337748cd8SNickeau             * in the configuration page and makes it really slow
734c3437056SNickeau             * TODO: when we have made a special fetch ajax with cache
735c3437056SNickeau             * for application resource, we can serve it statically
73637748cd8SNickeau             */
737c3437056SNickeau            $path = LocalPath::createFromPath(Resources::getImagesDirectory() . "/logo.svg");
73837748cd8SNickeau            $tagAttributes = TagAttributes::createEmpty(SvgImageLink::CANONICAL);
73937748cd8SNickeau            $tagAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, SvgDocument::ICON_TYPE);
74037748cd8SNickeau            $tagAttributes->addComponentAttributeValue(Dimension::WIDTH_KEY, "20");
74137748cd8SNickeau            $cache = new CacheMedia($path, $tagAttributes);
74237748cd8SNickeau            if (!$cache->isCacheUsable()) {
743c3437056SNickeau                $xhtmlIcon = SvgDocument::createSvgDocumentFromPath($path)
74437748cd8SNickeau                    ->setShouldBeOptimized(true)
74537748cd8SNickeau                    ->getXmlText($tagAttributes);
74637748cd8SNickeau                $cache->storeCache($xhtmlIcon);
74737748cd8SNickeau            }
748c3437056SNickeau            $xhtmlIcon = FileSystems::getContent($cache->getFile());
74937748cd8SNickeau
75037748cd8SNickeau        }
751c3437056SNickeau        $urlApex = self::$URL_APEX;
752c3437056SNickeau        $path = str_replace(":", "/", $canonical);
753c3437056SNickeau        if (empty($tooltip)) {
754c3437056SNickeau            $title = $label;
755c3437056SNickeau        } else {
756c3437056SNickeau            $title = $tooltip;
757c3437056SNickeau        }
758c3437056SNickeau        $htmlToolTip = "";
759c3437056SNickeau        if (!empty($tooltip)) {
760c3437056SNickeau            $dataAttributeNamespace = Bootstrap::getDataNamespace();
761c3437056SNickeau            $htmlToolTip = "data{$dataAttributeNamespace}-toggle=\"tooltip\"";
762c3437056SNickeau        }
763c3437056SNickeau        return "$xhtmlIcon<a href=\"$urlApex/$path\" title=\"$title\" $htmlToolTip style=\"text-decoration:none;\">$label</a>";
76437748cd8SNickeau    }
76537748cd8SNickeau
76637748cd8SNickeau    /**
76737748cd8SNickeau     * An utility function to not search every time which array should be first
76837748cd8SNickeau     * @param array $inlineAttributes - the component inline attributes
76937748cd8SNickeau     * @param array $defaultAttributes - the default configuration attributes
77037748cd8SNickeau     * @return array - a merged array
77137748cd8SNickeau     */
77237748cd8SNickeau    public
77337748cd8SNickeau    static function mergeAttributes(array $inlineAttributes, array $defaultAttributes = array())
77437748cd8SNickeau    {
77537748cd8SNickeau        return array_merge($defaultAttributes, $inlineAttributes);
77637748cd8SNickeau    }
77737748cd8SNickeau
77837748cd8SNickeau    /**
77937748cd8SNickeau     * A pattern for a container tag
78037748cd8SNickeau     * that needs to catch the content
78137748cd8SNickeau     *
78237748cd8SNickeau     * Use as a special pattern (substition)
78337748cd8SNickeau     *
78437748cd8SNickeau     * The {@link \syntax_plugin_combo_math} use it
78537748cd8SNickeau     * @param $tag
78637748cd8SNickeau     * @return string - a pattern
78737748cd8SNickeau     */
78837748cd8SNickeau    public
78937748cd8SNickeau    static function getLeafContainerTagPattern($tag)
79037748cd8SNickeau    {
79137748cd8SNickeau        return '<' . $tag . '.*?>.*?<\/' . $tag . '>';
79237748cd8SNickeau    }
79337748cd8SNickeau
79437748cd8SNickeau    /**
79537748cd8SNickeau     * Return the content of a tag
79637748cd8SNickeau     * <math>Content</math>
79737748cd8SNickeau     * @param $match
79837748cd8SNickeau     * @return string the content
79937748cd8SNickeau     */
80037748cd8SNickeau    public
80137748cd8SNickeau    static function getTagContent($match)
80237748cd8SNickeau    {
80337748cd8SNickeau        // From the first >
80437748cd8SNickeau        $start = strpos($match, ">");
80537748cd8SNickeau        if ($start == false) {
80637748cd8SNickeau            LogUtility::msg("The match does not contain any opening tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
80737748cd8SNickeau            return "";
80837748cd8SNickeau        }
80937748cd8SNickeau        $match = substr($match, $start + 1);
81037748cd8SNickeau        // If this is the last character, we get a false
81137748cd8SNickeau        if ($match == false) {
81237748cd8SNickeau            LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
81337748cd8SNickeau            return "";
81437748cd8SNickeau        }
81537748cd8SNickeau
81637748cd8SNickeau        $end = strrpos($match, "</");
81737748cd8SNickeau        if ($end == false) {
81837748cd8SNickeau            LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
81937748cd8SNickeau            return "";
82037748cd8SNickeau        }
82137748cd8SNickeau
82237748cd8SNickeau        return substr($match, 0, $end);
82337748cd8SNickeau    }
82437748cd8SNickeau
82537748cd8SNickeau    /**
82637748cd8SNickeau     *
82737748cd8SNickeau     * Check if a HTML tag was already added for a request
82837748cd8SNickeau     * The request id is just the timestamp
82937748cd8SNickeau     * An indicator array should be provided
83037748cd8SNickeau     * @return string
83137748cd8SNickeau     */
83237748cd8SNickeau    public
83337748cd8SNickeau    static function getRequestId()
83437748cd8SNickeau    {
83537748cd8SNickeau
83637748cd8SNickeau        if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
83737748cd8SNickeau            // since php 5.4
83837748cd8SNickeau            $requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
83937748cd8SNickeau        } else {
84037748cd8SNickeau            // DokuWiki test framework use this
84137748cd8SNickeau            $requestTime = $_SERVER['REQUEST_TIME'];
84237748cd8SNickeau        }
84337748cd8SNickeau        $keyPrefix = 'combo_';
84437748cd8SNickeau
84537748cd8SNickeau        global $ID;
84637748cd8SNickeau        return $keyPrefix . hash('crc32b', $_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT'] . $requestTime . $ID);
84737748cd8SNickeau
84837748cd8SNickeau    }
84937748cd8SNickeau
85037748cd8SNickeau    /**
85137748cd8SNickeau     * Get the page id
85237748cd8SNickeau     * If the page is a sidebar, it will not return the id of the sidebar
85337748cd8SNickeau     * but the one of the page
854c3437056SNickeau     * Return the main/requested page id
855c3437056SNickeau     * (Not the sidebar)
856c3437056SNickeau     * @return string|null - null in test
85737748cd8SNickeau     */
85837748cd8SNickeau    public
859c3437056SNickeau    static function getMainPageDokuwikiId(): ?string
86037748cd8SNickeau    {
861c3437056SNickeau        global $ID;
862c3437056SNickeau        global $INFO;
863c3437056SNickeau        $callingId = $ID;
864c3437056SNickeau        // If the component is in a sidebar, we don't want the ID of the sidebar
865c3437056SNickeau        // but the ID of the page.
866c3437056SNickeau        if ($INFO != null) {
867c3437056SNickeau            $callingId = $INFO['id'];
868c3437056SNickeau        }
869c3437056SNickeau        /**
870c3437056SNickeau         * This is the case with event triggered
871c3437056SNickeau         * before DokuWiki such as
872c3437056SNickeau         * https://www.dokuwiki.org/devel:event:init_lang_load
873c3437056SNickeau         */
874c3437056SNickeau        if ($callingId == null) {
875c3437056SNickeau            global $_REQUEST;
876c3437056SNickeau            if (isset($_REQUEST["id"])) {
877c3437056SNickeau                $callingId = $_REQUEST["id"];
878c3437056SNickeau            }
879c3437056SNickeau        }
880c3437056SNickeau        return $callingId;
881c3437056SNickeau
88237748cd8SNickeau    }
88337748cd8SNickeau
88437748cd8SNickeau    /**
88537748cd8SNickeau     * Transform special HTML characters to entity
88637748cd8SNickeau     * Example:
88737748cd8SNickeau     * <hello>world</hello>
88837748cd8SNickeau     * to
88937748cd8SNickeau     * "&lt;hello&gt;world&lt;/hello&gt;"
89037748cd8SNickeau     *
89137748cd8SNickeau     * @param $text
89237748cd8SNickeau     * @return string
89337748cd8SNickeau     */
89437748cd8SNickeau    public
895c3437056SNickeau    static function htmlEncode($text): string
89637748cd8SNickeau    {
89737748cd8SNickeau        /**
89837748cd8SNickeau         * See https://stackoverflow.com/questions/46483/htmlentities-vs-htmlspecialchars/3614344
89937748cd8SNickeau         * {@link htmlentities }
90037748cd8SNickeau         */
90137748cd8SNickeau        //return htmlspecialchars($text, ENT_QUOTES);
90237748cd8SNickeau        return htmlentities($text);
90337748cd8SNickeau    }
90437748cd8SNickeau
905c3437056SNickeau    public
906c3437056SNickeau    static function xmlEncode($text)
907c3437056SNickeau    {
908c3437056SNickeau        /**
909c3437056SNickeau         * {@link htmlentities }
910c3437056SNickeau         */
911c3437056SNickeau        return htmlentities($text, ENT_XML1);
912c3437056SNickeau    }
913c3437056SNickeau
91437748cd8SNickeau
91537748cd8SNickeau    /**
91637748cd8SNickeau     * Add a class
91737748cd8SNickeau     * @param $classValue
91837748cd8SNickeau     * @param array $attributes
91937748cd8SNickeau     */
92037748cd8SNickeau    public
92137748cd8SNickeau    static function addClass2Attributes($classValue, array &$attributes)
92237748cd8SNickeau    {
92337748cd8SNickeau        self::addAttributeValue("class", $classValue, $attributes);
92437748cd8SNickeau    }
92537748cd8SNickeau
92637748cd8SNickeau    /**
92737748cd8SNickeau     * Add a style property to the attributes
92837748cd8SNickeau     * @param $property
92937748cd8SNickeau     * @param $value
93037748cd8SNickeau     * @param array $attributes
93137748cd8SNickeau     * @deprecated use {@link TagAttributes::addStyleDeclaration()} instead
93237748cd8SNickeau     */
93337748cd8SNickeau    public
93437748cd8SNickeau    static function addStyleProperty($property, $value, array &$attributes)
93537748cd8SNickeau    {
93637748cd8SNickeau        if (isset($attributes["style"])) {
93737748cd8SNickeau            $attributes["style"] .= ";$property:$value";
93837748cd8SNickeau        } else {
93937748cd8SNickeau            $attributes["style"] = "$property:$value";
94037748cd8SNickeau        }
94137748cd8SNickeau
94237748cd8SNickeau    }
94337748cd8SNickeau
94437748cd8SNickeau    /**
94537748cd8SNickeau     * Add default border attributes
94637748cd8SNickeau     * to see a border
94737748cd8SNickeau     * Doc
94837748cd8SNickeau     * https://combostrap.com/styling/color#border_color
94937748cd8SNickeau     * @param TagAttributes $tagAttributes
95037748cd8SNickeau     */
95137748cd8SNickeau    private
95237748cd8SNickeau    static function checkDefaultBorderColorAttributes(&$tagAttributes)
95337748cd8SNickeau    {
95437748cd8SNickeau        /**
95537748cd8SNickeau         * border color was set without the width
95637748cd8SNickeau         * setting the width
95737748cd8SNickeau         */
95837748cd8SNickeau        if (!(
95937748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border")
96037748cd8SNickeau            ||
96137748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border-width")
96237748cd8SNickeau        )
96337748cd8SNickeau        ) {
96437748cd8SNickeau            $tagAttributes->addStyleDeclaration("border-width", "1px");
96537748cd8SNickeau        }
96637748cd8SNickeau        /**
96737748cd8SNickeau         * border color was set without the style
96837748cd8SNickeau         * setting the style
96937748cd8SNickeau         */
97037748cd8SNickeau        if (!
97137748cd8SNickeau        (
97237748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border")
97337748cd8SNickeau            ||
97437748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border-style")
97537748cd8SNickeau        )
97637748cd8SNickeau        ) {
97737748cd8SNickeau            $tagAttributes->addStyleDeclaration("border-style", "solid");
97837748cd8SNickeau
97937748cd8SNickeau        }
98037748cd8SNickeau        if (!$tagAttributes->hasStyleDeclaration("border-radius")) {
98137748cd8SNickeau            $tagAttributes->addStyleDeclaration("border-radius", ".25rem");
98237748cd8SNickeau        }
98337748cd8SNickeau
98437748cd8SNickeau    }
98537748cd8SNickeau
98637748cd8SNickeau    public
98737748cd8SNickeau    static function getConfValue($confName, $defaultValue = null)
98837748cd8SNickeau    {
98937748cd8SNickeau        global $conf;
99037748cd8SNickeau        if (isset($conf['plugin'][PluginUtility::PLUGIN_BASE_NAME][$confName])) {
99137748cd8SNickeau            return $conf['plugin'][PluginUtility::PLUGIN_BASE_NAME][$confName];
99237748cd8SNickeau        } else {
99337748cd8SNickeau            return $defaultValue;
99437748cd8SNickeau        }
99537748cd8SNickeau    }
99637748cd8SNickeau
99737748cd8SNickeau    /**
99837748cd8SNickeau     * @param $match
99937748cd8SNickeau     * @return null|string - return the tag name or null if not found
100037748cd8SNickeau     */
100137748cd8SNickeau    public
100237748cd8SNickeau    static function getTag($match)
100337748cd8SNickeau    {
100437748cd8SNickeau
100537748cd8SNickeau        // Trim to start clean
100637748cd8SNickeau        $match = trim($match);
100737748cd8SNickeau
100837748cd8SNickeau        // Until the first >
100937748cd8SNickeau        $pos = strpos($match, ">");
101037748cd8SNickeau        if ($pos == false) {
101137748cd8SNickeau            LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
101237748cd8SNickeau            return null;
101337748cd8SNickeau        }
101437748cd8SNickeau        $match = substr($match, 0, $pos);
101537748cd8SNickeau
101637748cd8SNickeau        // Suppress the <
101737748cd8SNickeau        if ($match[0] == "<") {
101837748cd8SNickeau            $match = substr($match, 1);
101937748cd8SNickeau        } else {
102037748cd8SNickeau            LogUtility::msg("This is not a text tag because it does not start with the character `>`");
102137748cd8SNickeau        }
102237748cd8SNickeau
102337748cd8SNickeau        // Suppress the tag name (ie until the first blank)
102437748cd8SNickeau        $spacePosition = strpos($match, " ");
102537748cd8SNickeau        if (!$spacePosition) {
102637748cd8SNickeau            // No space, meaning this is only the tag name
102737748cd8SNickeau            return $match;
102837748cd8SNickeau        } else {
102937748cd8SNickeau            return substr($match, 0, $spacePosition);
103037748cd8SNickeau        }
103137748cd8SNickeau
103237748cd8SNickeau    }
103337748cd8SNickeau
103437748cd8SNickeau
103537748cd8SNickeau    /**
103637748cd8SNickeau     * @param string $string add a command into HTML
103737748cd8SNickeau     */
103837748cd8SNickeau    public
103937748cd8SNickeau    static function addAsHtmlComment($string)
104037748cd8SNickeau    {
104137748cd8SNickeau        print_r('<!-- ' . self::htmlEncode($string) . '-->');
104237748cd8SNickeau    }
104337748cd8SNickeau
104437748cd8SNickeau    public
104537748cd8SNickeau    static function getResourceBaseUrl()
104637748cd8SNickeau    {
104737748cd8SNickeau        return DOKU_URL . 'lib/plugins/' . PluginUtility::PLUGIN_BASE_NAME . '/resources';
104837748cd8SNickeau    }
104937748cd8SNickeau
105037748cd8SNickeau
105137748cd8SNickeau    public
105237748cd8SNickeau    static function getComponentName($tag)
105337748cd8SNickeau    {
105437748cd8SNickeau        return strtolower(PluginUtility::PLUGIN_BASE_NAME) . "_" . $tag;
105537748cd8SNickeau    }
105637748cd8SNickeau
105737748cd8SNickeau    public
105837748cd8SNickeau    static function addAttributeValue($attribute, $value, array &$attributes)
105937748cd8SNickeau    {
106037748cd8SNickeau        if (array_key_exists($attribute, $attributes) && $attributes[$attribute] !== "") {
106137748cd8SNickeau            $attributes[$attribute] .= " {$value}";
106237748cd8SNickeau        } else {
106337748cd8SNickeau            $attributes[$attribute] = "{$value}";
106437748cd8SNickeau        }
106537748cd8SNickeau    }
106637748cd8SNickeau
106737748cd8SNickeau    /**
106837748cd8SNickeau     * Plugin Utility is available to all plugin,
106937748cd8SNickeau     * this is a convenient way to the the snippet manager
107037748cd8SNickeau     * @return SnippetManager
107137748cd8SNickeau     */
107237748cd8SNickeau    public
1073c3437056SNickeau    static function getSnippetManager(): SnippetManager
107437748cd8SNickeau    {
107537748cd8SNickeau        return SnippetManager::get();
107637748cd8SNickeau    }
107737748cd8SNickeau
1078c3437056SNickeau
107937748cd8SNickeau    /**
108037748cd8SNickeau     * Function used in a render
108137748cd8SNickeau     * @param $data - the data from {@link PluginUtility::handleAndReturnUnmatchedData()}
108237748cd8SNickeau     * @return string
108337748cd8SNickeau     */
108437748cd8SNickeau    public
108537748cd8SNickeau    static function renderUnmatched($data)
108637748cd8SNickeau    {
108737748cd8SNickeau        /**
108837748cd8SNickeau         * Attributes
108937748cd8SNickeau         */
109037748cd8SNickeau        if (isset($data[PluginUtility::ATTRIBUTES])) {
109137748cd8SNickeau            $attributes = $data[PluginUtility::ATTRIBUTES];
109237748cd8SNickeau        } else {
109337748cd8SNickeau            $attributes = [];
109437748cd8SNickeau        }
109537748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
109637748cd8SNickeau        $display = $tagAttributes->getValue(TagAttributes::DISPLAY);
109737748cd8SNickeau        if ($display != "none") {
109837748cd8SNickeau            $payload = $data[self::PAYLOAD];
10991fa8c418SNickeau            $previousTagDisplayType = $data[self::CONTEXT];
11001fa8c418SNickeau            if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
110137748cd8SNickeau                $payload = ltrim($payload);
110237748cd8SNickeau            }
110337748cd8SNickeau            return PluginUtility::htmlEncode($payload);
110437748cd8SNickeau        } else {
110537748cd8SNickeau            return "";
110637748cd8SNickeau        }
110737748cd8SNickeau    }
110837748cd8SNickeau
1109c3437056SNickeau    public
1110c3437056SNickeau    static function renderUnmatchedXml($data)
1111c3437056SNickeau    {
1112c3437056SNickeau        $payload = $data[self::PAYLOAD];
1113c3437056SNickeau        $previousTagDisplayType = $data[self::CONTEXT];
1114c3437056SNickeau        if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
1115c3437056SNickeau            $payload = ltrim($payload);
1116c3437056SNickeau        }
1117c3437056SNickeau        return PluginUtility::xmlEncode($payload);
1118c3437056SNickeau
1119c3437056SNickeau    }
1120c3437056SNickeau
112137748cd8SNickeau    /**
112237748cd8SNickeau     * Function used in a handle function of a syntax plugin for
112337748cd8SNickeau     * unmatched context
112437748cd8SNickeau     * @param $tagName
112537748cd8SNickeau     * @param $match
112637748cd8SNickeau     * @param \Doku_Handler $handler
112737748cd8SNickeau     * @return array
112837748cd8SNickeau     */
112937748cd8SNickeau    public
11301fa8c418SNickeau    static function handleAndReturnUnmatchedData($tagName, $match, \Doku_Handler $handler): array
113137748cd8SNickeau    {
11321fa8c418SNickeau        $callStack = CallStack::createFromHandler($handler);
11331fa8c418SNickeau        $sibling = $callStack->previous();
113437748cd8SNickeau        $context = null;
113537748cd8SNickeau        if (!empty($sibling)) {
11361fa8c418SNickeau            $context = $sibling->getDisplay();
113737748cd8SNickeau        }
113837748cd8SNickeau        return array(
113937748cd8SNickeau            PluginUtility::STATE => DOKU_LEXER_UNMATCHED,
114037748cd8SNickeau            PluginUtility::PAYLOAD => $match,
114137748cd8SNickeau            PluginUtility::CONTEXT => $context
114237748cd8SNickeau        );
114337748cd8SNickeau    }
114437748cd8SNickeau
114537748cd8SNickeau    public
114637748cd8SNickeau    static function setConf($key, $value, $namespace = 'plugin')
114737748cd8SNickeau    {
114837748cd8SNickeau        global $conf;
1149c3437056SNickeau        if ($namespace !== null) {
115037748cd8SNickeau            $conf[$namespace][PluginUtility::PLUGIN_BASE_NAME][$key] = $value;
115137748cd8SNickeau        } else {
115237748cd8SNickeau            $conf[$key] = $value;
115337748cd8SNickeau        }
115437748cd8SNickeau
115537748cd8SNickeau    }
115637748cd8SNickeau
115737748cd8SNickeau    /**
115837748cd8SNickeau     * Utility methodPreprocess a start tag to be able to extract the name
115937748cd8SNickeau     * and the attributes easily
116037748cd8SNickeau     *
116137748cd8SNickeau     * It will delete:
116237748cd8SNickeau     *   * the characters <> and the /> if present
116337748cd8SNickeau     *   * and trim
116437748cd8SNickeau     *
116537748cd8SNickeau     * It will remain the tagname and its attributes
116637748cd8SNickeau     * @param $match
116737748cd8SNickeau     * @return false|string|null
116837748cd8SNickeau     */
116937748cd8SNickeau    private
117037748cd8SNickeau    static function getPreprocessEnterTag($match)
117137748cd8SNickeau    {
117237748cd8SNickeau        // Until the first >
117337748cd8SNickeau        $pos = strpos($match, ">");
117437748cd8SNickeau        if ($pos == false) {
117537748cd8SNickeau            LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_WARNING);
117637748cd8SNickeau            return null;
117737748cd8SNickeau        }
117837748cd8SNickeau        $match = substr($match, 0, $pos);
117937748cd8SNickeau
118037748cd8SNickeau
118137748cd8SNickeau        // Trim to start clean
118237748cd8SNickeau        $match = trim($match);
118337748cd8SNickeau
118437748cd8SNickeau        // Suppress the <
118537748cd8SNickeau        if ($match[0] == "<") {
118637748cd8SNickeau            $match = substr($match, 1);
118737748cd8SNickeau        }
118837748cd8SNickeau
118937748cd8SNickeau        // Suppress the / for a leaf tag
119037748cd8SNickeau        if ($match[strlen($match) - 1] == "/") {
119137748cd8SNickeau            $match = substr($match, 0, strlen($match) - 1);
119237748cd8SNickeau        }
119337748cd8SNickeau        return $match;
119437748cd8SNickeau    }
119537748cd8SNickeau
119637748cd8SNickeau    /**
119737748cd8SNickeau     * Retrieve the tag name used in the text document
119837748cd8SNickeau     * @param $match
119937748cd8SNickeau     * @return false|string|null
120037748cd8SNickeau     */
120137748cd8SNickeau    public
120237748cd8SNickeau    static function getSyntaxTagNameFromMatch($match)
120337748cd8SNickeau    {
120437748cd8SNickeau        $preprocessMatch = PluginUtility::getPreprocessEnterTag($match);
120537748cd8SNickeau
120637748cd8SNickeau        // Tag name (ie until the first blank)
120737748cd8SNickeau        $spacePosition = strpos($match, " ");
120837748cd8SNickeau        if (!$spacePosition) {
120937748cd8SNickeau            // No space, meaning this is only the tag name
121037748cd8SNickeau            return $preprocessMatch;
121137748cd8SNickeau        } else {
121237748cd8SNickeau            return trim(substr(0, $spacePosition));
121337748cd8SNickeau        }
121437748cd8SNickeau
121537748cd8SNickeau    }
121637748cd8SNickeau
121737748cd8SNickeau    /**
121837748cd8SNickeau     * @param \Doku_Renderer_xhtml $renderer
121937748cd8SNickeau     * @param $position
122037748cd8SNickeau     * @param $name
122137748cd8SNickeau     */
122237748cd8SNickeau    public
122337748cd8SNickeau    static function startSection($renderer, $position, $name)
122437748cd8SNickeau    {
122537748cd8SNickeau
122637748cd8SNickeau
122737748cd8SNickeau        if (empty($position)) {
122837748cd8SNickeau            LogUtility::msg("The position for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support");
122937748cd8SNickeau        }
123037748cd8SNickeau        if (empty($name)) {
123137748cd8SNickeau            LogUtility::msg("The name for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support");
123237748cd8SNickeau        }
123337748cd8SNickeau
123437748cd8SNickeau        /**
123537748cd8SNickeau         * New Dokuwiki Version
123637748cd8SNickeau         * for DokuWiki Greebo and more recent versions
123737748cd8SNickeau         */
123837748cd8SNickeau        if (defined('SEC_EDIT_PATTERN')) {
123937748cd8SNickeau            $renderer->startSectionEdit($position, array('target' => self::EDIT_SECTION_TARGET, 'name' => $name));
124037748cd8SNickeau        } else {
124137748cd8SNickeau            /**
124237748cd8SNickeau             * Old version
124337748cd8SNickeau             */
124437748cd8SNickeau            /** @noinspection PhpParamsInspection */
124537748cd8SNickeau            $renderer->startSectionEdit($position, self::EDIT_SECTION_TARGET, $name);
124637748cd8SNickeau        }
124737748cd8SNickeau    }
124837748cd8SNickeau
124937748cd8SNickeau    /**
125037748cd8SNickeau     * Add an enter call to the stack
125137748cd8SNickeau     * @param \Doku_Handler $handler
125237748cd8SNickeau     * @param $tagName
125337748cd8SNickeau     * @param array $callStackArray
125437748cd8SNickeau     */
125537748cd8SNickeau    public
125637748cd8SNickeau    static function addEnterCall(
125737748cd8SNickeau        \Doku_Handler &$handler,
125837748cd8SNickeau        $tagName,
125937748cd8SNickeau        $callStackArray = array()
126037748cd8SNickeau    )
126137748cd8SNickeau    {
126237748cd8SNickeau        $pluginName = PluginUtility::getComponentName($tagName);
126337748cd8SNickeau        $handler->addPluginCall(
126437748cd8SNickeau            $pluginName,
126537748cd8SNickeau            $callStackArray,
126637748cd8SNickeau            DOKU_LEXER_ENTER,
126737748cd8SNickeau            null,
126837748cd8SNickeau            null
126937748cd8SNickeau        );
127037748cd8SNickeau    }
127137748cd8SNickeau
127237748cd8SNickeau    /**
127337748cd8SNickeau     * Add an end call dynamically
127437748cd8SNickeau     * @param \Doku_Handler $handler
127537748cd8SNickeau     * @param $tagName
127637748cd8SNickeau     * @param array $callStackArray
127737748cd8SNickeau     */
127837748cd8SNickeau    public
127937748cd8SNickeau    static function addEndCall(\Doku_Handler $handler, $tagName, $callStackArray = array())
128037748cd8SNickeau    {
128137748cd8SNickeau        $pluginName = PluginUtility::getComponentName($tagName);
128237748cd8SNickeau        $handler->addPluginCall(
128337748cd8SNickeau            $pluginName,
128437748cd8SNickeau            $callStackArray,
128537748cd8SNickeau            DOKU_LEXER_END,
128637748cd8SNickeau            null,
128737748cd8SNickeau            null
128837748cd8SNickeau        );
128937748cd8SNickeau    }
129037748cd8SNickeau
129137748cd8SNickeau    /**
129237748cd8SNickeau     * General Debug
129337748cd8SNickeau     */
129437748cd8SNickeau    public
129537748cd8SNickeau    static function isDebug()
129637748cd8SNickeau    {
129737748cd8SNickeau        global $conf;
129837748cd8SNickeau        return $conf["allowdebug"] === 1;
129937748cd8SNickeau
130037748cd8SNickeau    }
130137748cd8SNickeau
130237748cd8SNickeau    /**
130337748cd8SNickeau     * @return bool true if loaded, false otherwise
130437748cd8SNickeau     * Strap is loaded only if this is the same version
130537748cd8SNickeau     * to avoid function, class, or members that does not exist
130637748cd8SNickeau     */
130737748cd8SNickeau    public
1308*0e43c1dbSgerardnico    static function loadStrapUtilityTemplateIfPresentAndSameVersion(): bool
130937748cd8SNickeau    {
131037748cd8SNickeau        $templateUtilityFile = __DIR__ . '/../../../tpl/strap/class/TplUtility.php';
131137748cd8SNickeau        if (file_exists($templateUtilityFile)) {
131237748cd8SNickeau            /**
131337748cd8SNickeau             * Check the version
131437748cd8SNickeau             */
131537748cd8SNickeau            $templateInfo = confToHash(__DIR__ . '/../../../tpl/strap/template.info.txt');
131637748cd8SNickeau            $templateVersion = $templateInfo['version'];
131737748cd8SNickeau            $comboVersion = self::$INFO_PLUGIN['version'];
131837748cd8SNickeau            if ($templateVersion != $comboVersion) {
1319*0e43c1dbSgerardnico                $strapName = "Strap";
1320*0e43c1dbSgerardnico                $comboName = "Combo";
1321*0e43c1dbSgerardnico                $strapLink = "<a href=\"https://www.dokuwiki.org/template:strap\">$strapName</a>";
1322*0e43c1dbSgerardnico                $comboLink = "<a href=\"https://www.dokuwiki.org/plugin:combo\">$comboName</a>";
132337748cd8SNickeau                if ($comboVersion > $templateVersion) {
1324*0e43c1dbSgerardnico                    $upgradeTarget = $strapName;
132537748cd8SNickeau                } else {
1326*0e43c1dbSgerardnico                    $upgradeTarget = $comboName;
132737748cd8SNickeau                }
1328*0e43c1dbSgerardnico                $upgradeLink = "<a href=\"" . wl() . "&do=admin&page=extension" . "\">upgrade <b>$upgradeTarget</b> via the extension manager</a>";
1329*0e43c1dbSgerardnico                $message = "You should $upgradeLink to the latest version to get a fully functional experience. The version of $comboLink is ($comboVersion) while the version of $strapLink is ($templateVersion).";
1330*0e43c1dbSgerardnico                LogUtility::msg($message);
133137748cd8SNickeau                return false;
133237748cd8SNickeau            } else {
133337748cd8SNickeau                /** @noinspection PhpIncludeInspection */
133437748cd8SNickeau                require_once($templateUtilityFile);
133537748cd8SNickeau                return true;
133637748cd8SNickeau            }
133737748cd8SNickeau        } else {
133837748cd8SNickeau            $level = LogUtility::LVL_MSG_DEBUG;
133937748cd8SNickeau            if (defined('DOKU_UNITTEST')) {
134037748cd8SNickeau                // fail
134137748cd8SNickeau                $level = LogUtility::LVL_MSG_ERROR;
134237748cd8SNickeau            }
134337748cd8SNickeau            if (Site::getTemplate() != "strap") {
134437748cd8SNickeau                LogUtility::msg("The strap template is not installed", $level);
134537748cd8SNickeau            } else {
134637748cd8SNickeau                LogUtility::msg("The file ($templateUtilityFile) was not found", $level);
134737748cd8SNickeau            }
134837748cd8SNickeau            return false;
134937748cd8SNickeau        }
135037748cd8SNickeau    }
135137748cd8SNickeau
135237748cd8SNickeau
135337748cd8SNickeau    /**
135437748cd8SNickeau     *
135537748cd8SNickeau     * See also dev.md file
135637748cd8SNickeau     */
135737748cd8SNickeau    public static function isDevOrTest()
135837748cd8SNickeau    {
135937748cd8SNickeau        if (self::isDev()) {
136037748cd8SNickeau            return true;
136137748cd8SNickeau        }
136237748cd8SNickeau        return self::isTest();
136337748cd8SNickeau    }
136437748cd8SNickeau
136537748cd8SNickeau    public static function isDev()
136637748cd8SNickeau    {
136737748cd8SNickeau        global $_SERVER;
136837748cd8SNickeau        if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1") {
136937748cd8SNickeau            return true;
137037748cd8SNickeau        }
137137748cd8SNickeau        return false;
137237748cd8SNickeau    }
137337748cd8SNickeau
137437748cd8SNickeau    public static function getInstructions($markiCode)
137537748cd8SNickeau    {
137637748cd8SNickeau        return p_get_instructions($markiCode);
137737748cd8SNickeau    }
137837748cd8SNickeau
137937748cd8SNickeau    public static function getInstructionsWithoutRoot($markiCode)
138037748cd8SNickeau    {
138137748cd8SNickeau        return RenderUtility::getInstructionsAndStripPEventually($markiCode);
138237748cd8SNickeau    }
138337748cd8SNickeau
138437748cd8SNickeau    /**
138537748cd8SNickeau     * Transform a text into a valid HTML id
138637748cd8SNickeau     * @param $string
138737748cd8SNickeau     * @return string
138837748cd8SNickeau     */
138937748cd8SNickeau    public static function toHtmlId($string)
139037748cd8SNickeau    {
139137748cd8SNickeau        /**
139237748cd8SNickeau         * sectionId calls cleanID
139337748cd8SNickeau         * cleanID delete all things before a ':'
139437748cd8SNickeau         * we do then the replace before to not
139537748cd8SNickeau         * lost a minus '-' separator
139637748cd8SNickeau         */
139737748cd8SNickeau        $string = str_replace(array(':', '.'), '', $string);
139837748cd8SNickeau        return sectionID($string, $check);
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
142337748cd8SNickeau
142437748cd8SNickeau}
142537748cd8SNickeau
142637748cd8SNickeauPluginUtility::init();
1427