xref: /plugin/combo/ComboStrap/PluginUtility.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
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     * "&lt;script&gt;...&lt;/hello&gt;"
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         * &gt;h4 class="heading-combo"&lt;
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