xref: /plugin/combo/ComboStrap/PluginUtility.php (revision c3437056399326d621a01da73b649707fbb0ae69)
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 */
16*c3437056SNickeaurequire_once(__DIR__ . '/CachedDocument.php');
17*c3437056SNickeaurequire_once(__DIR__ . '/PageCompilerDocument.php');
18*c3437056SNickeaurequire_once(__DIR__ . '/OutputDocument.php');
19*c3437056SNickeaurequire_once(__DIR__ . '/FileSystem.php');
20*c3437056SNickeaurequire_once(__DIR__ . '/Path.php');
21*c3437056SNickeaurequire_once(__DIR__ . '/PathAbs.php');
22*c3437056SNickeaurequire_once(__DIR__ . '/File.php');
23*c3437056SNickeaurequire_once(__DIR__ . '/DokuFs.php');
241fa8c418SNickeaurequire_once(__DIR__ . '/DokuPath.php');
25*c3437056SNickeaurequire_once(__DIR__ . '/ResourceCombo.php');
26*c3437056SNickeaurequire_once(__DIR__ . '/ResourceComboAbs.php');
271fa8c418SNickeaurequire_once(__DIR__ . '/Media.php');
281fa8c418SNickeaurequire_once(__DIR__ . '/MediaLink.php');
29*c3437056SNickeaurequire_once(__DIR__ . '/Metadata.php');
30*c3437056SNickeaurequire_once(__DIR__ . '/MetadataBoolean.php');
31*c3437056SNickeaurequire_once(__DIR__ . '/MetadataDateTime.php');
32*c3437056SNickeaurequire_once(__DIR__ . '/MetadataMultiple.php');
33*c3437056SNickeaurequire_once(__DIR__ . '/MetadataTabular.php');
34*c3437056SNickeaurequire_once(__DIR__ . '/MetadataText.php');
35*c3437056SNickeaurequire_once(__DIR__ . '/MetadataJson.php');
36*c3437056SNickeaurequire_once(__DIR__ . '/MetadataWikiPath.php');
37*c3437056SNickeaurequire_once(__DIR__ . '/MetadataStore.php');
38*c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreAbs.php');
39*c3437056SNickeaurequire_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');
54*c3437056SNickeaurequire_once(__DIR__ . '/Alias.php');
55*c3437056SNickeaurequire_once(__DIR__ . '/AliasPath.php');
56*c3437056SNickeaurequire_once(__DIR__ . '/AliasType.php');
57*c3437056SNickeaurequire_once(__DIR__ . '/Aliases.php');
5837748cd8SNickeaurequire_once(__DIR__ . '/Align.php');
59*c3437056SNickeaurequire_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');
65*c3437056SNickeaurequire_once(__DIR__ . '/BacklinkCount.php');
66*c3437056SNickeaurequire_once(__DIR__ . '/BacklinkMenuItem.php');
6737748cd8SNickeaurequire_once(__DIR__ . '/Boldness.php');
68*c3437056SNickeaurequire_once(__DIR__ . '/Boolean.php');
6937748cd8SNickeaurequire_once(__DIR__ . '/Bootstrap.php');
7037748cd8SNickeaurequire_once(__DIR__ . '/BreadcrumbHierarchical.php');
71*c3437056SNickeaurequire_once(__DIR__ . '/CacheExpirationDate.php');
72*c3437056SNickeaurequire_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');
79*c3437056SNickeaurequire_once(__DIR__ . '/Canonical.php');
8037748cd8SNickeaurequire_once(__DIR__ . '/ColorUtility.php');
8137748cd8SNickeaurequire_once(__DIR__ . '/ConditionalValue.php');
82*c3437056SNickeaurequire_once(__DIR__ . '/Console.php');
83*c3437056SNickeaurequire_once(__DIR__ . '/Cron.php');
84*c3437056SNickeaurequire_once(__DIR__ . '/DatabasePageRow.php');
85*c3437056SNickeaurequire_once(__DIR__ . '/DataType.php');
8637748cd8SNickeaurequire_once(__DIR__ . '/Dimension.php');
87*c3437056SNickeaurequire_once(__DIR__ . '/DisqusIdentifier.php');
8837748cd8SNickeaurequire_once(__DIR__ . '/DokuwikiUrl.php');
89*c3437056SNickeaurequire_once(__DIR__ . '/DokuwikiId.php');
90*c3437056SNickeaurequire_once(__DIR__ . '/EndDate.php');
91*c3437056SNickeaurequire_once(__DIR__ . '/Event.php');
921fa8c418SNickeaurequire_once(__DIR__ . '/ExitException.php');
93*c3437056SNickeaurequire_once(__DIR__ . '/ExceptionCombo.php');
94*c3437056SNickeaurequire_once(__DIR__ . '/ExceptionComboRuntime.php');
95*c3437056SNickeaurequire_once(__DIR__ . '/FileSystems.php');
9637748cd8SNickeaurequire_once(__DIR__ . '/FloatAttribute.php');
97*c3437056SNickeaurequire_once(__DIR__ . '/FormMeta.php');
98*c3437056SNickeaurequire_once(__DIR__ . '/FormMetaTab.php');
99*c3437056SNickeaurequire_once(__DIR__ . '/FormMetaField.php');
10037748cd8SNickeaurequire_once(__DIR__ . '/FontSize.php');
10137748cd8SNickeaurequire_once(__DIR__ . '/FsWikiUtility.php');
10237748cd8SNickeaurequire_once(__DIR__ . '/HeaderUtility.php');
103*c3437056SNickeaurequire_once(__DIR__ . '/HtmlDocument.php');
10437748cd8SNickeaurequire_once(__DIR__ . '/HistoricalBreadcrumbMenuItem.php');
10537748cd8SNickeaurequire_once(__DIR__ . '/Hover.php');
106*c3437056SNickeaurequire_once(__DIR__ . '/Html.php');
10737748cd8SNickeaurequire_once(__DIR__ . '/Http.php');
108*c3437056SNickeaurequire_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');
115*c3437056SNickeaurequire_once(__DIR__ . '/Index.php');
116*c3437056SNickeaurequire_once(__DIR__ . '/InstructionsDocument.php');
117*c3437056SNickeaurequire_once(__DIR__ . '/InternetPath.php');
118*c3437056SNickeaurequire_once(__DIR__ . '/InterWikiPath.php');
11937748cd8SNickeaurequire_once(__DIR__ . '/Iso8601Date.php');
1201fa8c418SNickeaurequire_once(__DIR__ . '/Json.php');
121*c3437056SNickeaurequire_once(__DIR__ . '/JavascriptLibrary.php');
12237748cd8SNickeaurequire_once(__DIR__ . '/Lang.php');
123*c3437056SNickeaurequire_once(__DIR__ . '/LdJson.php');
12437748cd8SNickeaurequire_once(__DIR__ . '/LineSpacing.php');
125*c3437056SNickeaurequire_once(__DIR__ . '/Locale.php');
126*c3437056SNickeaurequire_once(__DIR__ . '/LocalFs.php');
127*c3437056SNickeaurequire_once(__DIR__ . '/LocalPath.php');
1281fa8c418SNickeaurequire_once(__DIR__ . '/LogException.php');
12937748cd8SNickeaurequire_once(__DIR__ . '/LogUtility.php');
13037748cd8SNickeaurequire_once(__DIR__ . '/LowQualityPage.php');
131*c3437056SNickeaurequire_once(__DIR__ . '/LowQualityPageOverwrite.php');
132*c3437056SNickeaurequire_once(__DIR__ . '/LowQualityCalculatedIndicator.php');
133*c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerForm.php');
134*c3437056SNickeaurequire_once(__DIR__ . '/MetaManagerMenuItem.php');
135*c3437056SNickeaurequire_once(__DIR__ . '/MetadataDokuWikiStore.php');
136*c3437056SNickeaurequire_once(__DIR__ . '/MetadataFormDataStore.php');
137*c3437056SNickeaurequire_once(__DIR__ . '/MetadataFrontmatterStore.php');
138*c3437056SNickeaurequire_once(__DIR__ . '/MetadataDbStore.php');
139*c3437056SNickeaurequire_once(__DIR__ . '/MetadataStoreTransfer.php');
1401fa8c418SNickeaurequire_once(__DIR__ . '/Message.php');
1411fa8c418SNickeaurequire_once(__DIR__ . '/Mermaid.php');
142*c3437056SNickeaurequire_once(__DIR__ . '/Mime.php');
143*c3437056SNickeaurequire_once(__DIR__ . '/ModificationDate.php');
14437748cd8SNickeaurequire_once(__DIR__ . '/NavBarUtility.php');
14537748cd8SNickeaurequire_once(__DIR__ . '/Opacity.php');
1461fa8c418SNickeaurequire_once(__DIR__ . '/Os.php');
14737748cd8SNickeaurequire_once(__DIR__ . '/Page.php');
148*c3437056SNickeaurequire_once(__DIR__ . '/PageDescription.php');
149*c3437056SNickeaurequire_once(__DIR__ . '/PageId.php');
150*c3437056SNickeaurequire_once(__DIR__ . '/PageKeywords.php');
151*c3437056SNickeaurequire_once(__DIR__ . '/PageImages.php');
152*c3437056SNickeaurequire_once(__DIR__ . '/PageImage.php');
153*c3437056SNickeaurequire_once(__DIR__ . '/PageImagePath.php');
154*c3437056SNickeaurequire_once(__DIR__ . '/PageImageUsage.php');
155*c3437056SNickeaurequire_once(__DIR__ . '/PageLayout.php');
156*c3437056SNickeaurequire_once(__DIR__ . '/PagePath.php');
15737748cd8SNickeaurequire_once(__DIR__ . '/PageProtection.php');
15837748cd8SNickeaurequire_once(__DIR__ . '/PageRules.php');
159*c3437056SNickeaurequire_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');
164*c3437056SNickeaurequire_once(__DIR__ . '/PageType.php');
165*c3437056SNickeaurequire_once(__DIR__ . '/PageTitle.php');
166*c3437056SNickeaurequire_once(__DIR__ . '/PageUrlPath.php');
167*c3437056SNickeaurequire_once(__DIR__ . '/PageUrlType.php');
16837748cd8SNickeaurequire_once(__DIR__ . '/PipelineUtility.php');
16937748cd8SNickeaurequire_once(__DIR__ . '/Position.php');
17037748cd8SNickeaurequire_once(__DIR__ . '/Prism.php');
171*c3437056SNickeaurequire_once(__DIR__ . '/PagePublicationDate.php');
172*c3437056SNickeaurequire_once(__DIR__ . '/PageCreationDate.php');
173*c3437056SNickeaurequire_once(__DIR__ . '/PageH1.php');
174*c3437056SNickeaurequire_once(__DIR__ . '/QualityDynamicMonitoringOverwrite.php');
175*c3437056SNickeaurequire_once(__DIR__ . '/QualityMenuItem.php');
17637748cd8SNickeaurequire_once(__DIR__ . '/RasterImageLink.php');
177*c3437056SNickeaurequire_once(__DIR__ . '/Region.php');
17837748cd8SNickeaurequire_once(__DIR__ . '/RenderUtility.php');
179*c3437056SNickeaurequire_once(__DIR__ . '/ReplicationDate.php');
18037748cd8SNickeaurequire_once(__DIR__ . '/Resources.php');
181*c3437056SNickeaurequire_once(__DIR__ . '/ResourceName.php');
1821fa8c418SNickeaurequire_once(__DIR__ . '/Sanitizer.php');
18337748cd8SNickeaurequire_once(__DIR__ . '/Shadow.php');
18437748cd8SNickeaurequire_once(__DIR__ . '/Site.php');
18537748cd8SNickeaurequire_once(__DIR__ . '/Skin.php');
186*c3437056SNickeaurequire_once(__DIR__ . '/Slug.php');
18737748cd8SNickeaurequire_once(__DIR__ . '/Snippet.php');
18837748cd8SNickeaurequire_once(__DIR__ . '/SnippetManager.php');
18937748cd8SNickeaurequire_once(__DIR__ . '/Spacing.php');
19037748cd8SNickeaurequire_once(__DIR__ . '/Sqlite.php');
191*c3437056SNickeaurequire_once(__DIR__ . '/SqliteRequest.php');
192*c3437056SNickeaurequire_once(__DIR__ . '/SqliteResult.php');
19337748cd8SNickeaurequire_once(__DIR__ . '/StringUtility.php');
194*c3437056SNickeaurequire_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');
203*c3437056SNickeaurequire_once(__DIR__ . '/TemplateStore.php');
20437748cd8SNickeaurequire_once(__DIR__ . '/TemplateUtility.php');
20537748cd8SNickeaurequire_once(__DIR__ . '/TextAlign.php');
20637748cd8SNickeaurequire_once(__DIR__ . '/TextColor.php');
207*c3437056SNickeaurequire_once(__DIR__ . '/ThirdMedia.php');
20837748cd8SNickeaurequire_once(__DIR__ . '/ThirdMediaLink.php');
20937748cd8SNickeaurequire_once(__DIR__ . '/ThirdPartyPlugins.php');
21037748cd8SNickeaurequire_once(__DIR__ . '/TocUtility.php');
21137748cd8SNickeaurequire_once(__DIR__ . '/Toggle.php');
212*c3437056SNickeaurequire_once(__DIR__ . '/References.php');
213*c3437056SNickeaurequire_once(__DIR__ . '/Reference.php');
21437748cd8SNickeaurequire_once(__DIR__ . '/Underline.php');
21537748cd8SNickeaurequire_once(__DIR__ . '/Unit.php');
216*c3437056SNickeaurequire_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     */
267*c3437056SNickeau    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];
314*c3437056SNickeau        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.
382*c3437056SNickeau     * Used for
383*c3437056SNickeau     * @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
718*c3437056SNickeau     * @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
723*c3437056SNickeau    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
734*c3437056SNickeau             * TODO: when we have made a special fetch ajax with cache
735*c3437056SNickeau             * for application resource, we can serve it statically
73637748cd8SNickeau             */
737*c3437056SNickeau            $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()) {
743*c3437056SNickeau                $xhtmlIcon = SvgDocument::createSvgDocumentFromPath($path)
74437748cd8SNickeau                    ->setShouldBeOptimized(true)
74537748cd8SNickeau                    ->getXmlText($tagAttributes);
74637748cd8SNickeau                $cache->storeCache($xhtmlIcon);
74737748cd8SNickeau            }
748*c3437056SNickeau            $xhtmlIcon = FileSystems::getContent($cache->getFile());
74937748cd8SNickeau
75037748cd8SNickeau        }
751*c3437056SNickeau        $urlApex = self::$URL_APEX;
752*c3437056SNickeau        $path = str_replace(":", "/", $canonical);
753*c3437056SNickeau        if (empty($tooltip)) {
754*c3437056SNickeau            $title = $label;
755*c3437056SNickeau        } else {
756*c3437056SNickeau            $title = $tooltip;
757*c3437056SNickeau        }
758*c3437056SNickeau        $htmlToolTip = "";
759*c3437056SNickeau        if (!empty($tooltip)) {
760*c3437056SNickeau            $dataAttributeNamespace = Bootstrap::getDataNamespace();
761*c3437056SNickeau            $htmlToolTip = "data{$dataAttributeNamespace}-toggle=\"tooltip\"";
762*c3437056SNickeau        }
763*c3437056SNickeau        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
854*c3437056SNickeau     * Return the main/requested page id
855*c3437056SNickeau     * (Not the sidebar)
856*c3437056SNickeau     * @return string|null - null in test
85737748cd8SNickeau     */
85837748cd8SNickeau    public
859*c3437056SNickeau    static function getMainPageDokuwikiId(): ?string
86037748cd8SNickeau    {
861*c3437056SNickeau        global $ID;
862*c3437056SNickeau        global $INFO;
863*c3437056SNickeau        $callingId = $ID;
864*c3437056SNickeau        // If the component is in a sidebar, we don't want the ID of the sidebar
865*c3437056SNickeau        // but the ID of the page.
866*c3437056SNickeau        if ($INFO != null) {
867*c3437056SNickeau            $callingId = $INFO['id'];
868*c3437056SNickeau        }
869*c3437056SNickeau        /**
870*c3437056SNickeau         * This is the case with event triggered
871*c3437056SNickeau         * before DokuWiki such as
872*c3437056SNickeau         * https://www.dokuwiki.org/devel:event:init_lang_load
873*c3437056SNickeau         */
874*c3437056SNickeau        if ($callingId == null) {
875*c3437056SNickeau            global $_REQUEST;
876*c3437056SNickeau            if (isset($_REQUEST["id"])) {
877*c3437056SNickeau                $callingId = $_REQUEST["id"];
878*c3437056SNickeau            }
879*c3437056SNickeau        }
880*c3437056SNickeau        return $callingId;
881*c3437056SNickeau
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
895*c3437056SNickeau    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
905*c3437056SNickeau    public
906*c3437056SNickeau    static function xmlEncode($text)
907*c3437056SNickeau    {
908*c3437056SNickeau        /**
909*c3437056SNickeau         * {@link htmlentities }
910*c3437056SNickeau         */
911*c3437056SNickeau        return htmlentities($text, ENT_XML1);
912*c3437056SNickeau    }
913*c3437056SNickeau
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
105237748cd8SNickeau    public
105337748cd8SNickeau    static function getComponentName($tag)
105437748cd8SNickeau    {
105537748cd8SNickeau        return strtolower(PluginUtility::PLUGIN_BASE_NAME) . "_" . $tag;
105637748cd8SNickeau    }
105737748cd8SNickeau
105837748cd8SNickeau    public
105937748cd8SNickeau    static function addAttributeValue($attribute, $value, array &$attributes)
106037748cd8SNickeau    {
106137748cd8SNickeau        if (array_key_exists($attribute, $attributes) && $attributes[$attribute] !== "") {
106237748cd8SNickeau            $attributes[$attribute] .= " {$value}";
106337748cd8SNickeau        } else {
106437748cd8SNickeau            $attributes[$attribute] = "{$value}";
106537748cd8SNickeau        }
106637748cd8SNickeau    }
106737748cd8SNickeau
106837748cd8SNickeau    /**
106937748cd8SNickeau     * Plugin Utility is available to all plugin,
107037748cd8SNickeau     * this is a convenient way to the the snippet manager
107137748cd8SNickeau     * @return SnippetManager
107237748cd8SNickeau     */
107337748cd8SNickeau    public
1074*c3437056SNickeau    static function getSnippetManager(): SnippetManager
107537748cd8SNickeau    {
107637748cd8SNickeau        return SnippetManager::get();
107737748cd8SNickeau    }
107837748cd8SNickeau
1079*c3437056SNickeau
108037748cd8SNickeau
108137748cd8SNickeau    /**
108237748cd8SNickeau     * Function used in a render
108337748cd8SNickeau     * @param $data - the data from {@link PluginUtility::handleAndReturnUnmatchedData()}
108437748cd8SNickeau     * @return string
108537748cd8SNickeau     */
108637748cd8SNickeau    public
108737748cd8SNickeau    static function renderUnmatched($data)
108837748cd8SNickeau    {
108937748cd8SNickeau        /**
109037748cd8SNickeau         * Attributes
109137748cd8SNickeau         */
109237748cd8SNickeau        if (isset($data[PluginUtility::ATTRIBUTES])) {
109337748cd8SNickeau            $attributes = $data[PluginUtility::ATTRIBUTES];
109437748cd8SNickeau        } else {
109537748cd8SNickeau            $attributes = [];
109637748cd8SNickeau        }
109737748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
109837748cd8SNickeau        $display = $tagAttributes->getValue(TagAttributes::DISPLAY);
109937748cd8SNickeau        if ($display != "none") {
110037748cd8SNickeau            $payload = $data[self::PAYLOAD];
11011fa8c418SNickeau            $previousTagDisplayType = $data[self::CONTEXT];
11021fa8c418SNickeau            if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
110337748cd8SNickeau                $payload = ltrim($payload);
110437748cd8SNickeau            }
110537748cd8SNickeau            return PluginUtility::htmlEncode($payload);
110637748cd8SNickeau        } else {
110737748cd8SNickeau            return "";
110837748cd8SNickeau        }
110937748cd8SNickeau    }
111037748cd8SNickeau
1111*c3437056SNickeau    public
1112*c3437056SNickeau    static function renderUnmatchedXml($data)
1113*c3437056SNickeau    {
1114*c3437056SNickeau        $payload = $data[self::PAYLOAD];
1115*c3437056SNickeau        $previousTagDisplayType = $data[self::CONTEXT];
1116*c3437056SNickeau        if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
1117*c3437056SNickeau            $payload = ltrim($payload);
1118*c3437056SNickeau        }
1119*c3437056SNickeau        return PluginUtility::xmlEncode($payload);
1120*c3437056SNickeau
1121*c3437056SNickeau    }
1122*c3437056SNickeau
112337748cd8SNickeau    /**
112437748cd8SNickeau     * Function used in a handle function of a syntax plugin for
112537748cd8SNickeau     * unmatched context
112637748cd8SNickeau     * @param $tagName
112737748cd8SNickeau     * @param $match
112837748cd8SNickeau     * @param \Doku_Handler $handler
112937748cd8SNickeau     * @return array
113037748cd8SNickeau     */
113137748cd8SNickeau    public
11321fa8c418SNickeau    static function handleAndReturnUnmatchedData($tagName, $match, \Doku_Handler $handler): array
113337748cd8SNickeau    {
11341fa8c418SNickeau        $callStack = CallStack::createFromHandler($handler);
11351fa8c418SNickeau        $sibling = $callStack->previous();
113637748cd8SNickeau        $context = null;
113737748cd8SNickeau        if (!empty($sibling)) {
11381fa8c418SNickeau            $context = $sibling->getDisplay();
113937748cd8SNickeau        }
114037748cd8SNickeau        return array(
114137748cd8SNickeau            PluginUtility::STATE => DOKU_LEXER_UNMATCHED,
114237748cd8SNickeau            PluginUtility::PAYLOAD => $match,
114337748cd8SNickeau            PluginUtility::CONTEXT => $context
114437748cd8SNickeau        );
114537748cd8SNickeau    }
114637748cd8SNickeau
114737748cd8SNickeau    public
114837748cd8SNickeau    static function setConf($key, $value, $namespace = 'plugin')
114937748cd8SNickeau    {
115037748cd8SNickeau        global $conf;
1151*c3437056SNickeau        if ($namespace !== null) {
115237748cd8SNickeau            $conf[$namespace][PluginUtility::PLUGIN_BASE_NAME][$key] = $value;
115337748cd8SNickeau        } else {
115437748cd8SNickeau            $conf[$key] = $value;
115537748cd8SNickeau        }
115637748cd8SNickeau
115737748cd8SNickeau    }
115837748cd8SNickeau
115937748cd8SNickeau    /**
116037748cd8SNickeau     * Utility methodPreprocess a start tag to be able to extract the name
116137748cd8SNickeau     * and the attributes easily
116237748cd8SNickeau     *
116337748cd8SNickeau     * It will delete:
116437748cd8SNickeau     *   * the characters <> and the /> if present
116537748cd8SNickeau     *   * and trim
116637748cd8SNickeau     *
116737748cd8SNickeau     * It will remain the tagname and its attributes
116837748cd8SNickeau     * @param $match
116937748cd8SNickeau     * @return false|string|null
117037748cd8SNickeau     */
117137748cd8SNickeau    private
117237748cd8SNickeau    static function getPreprocessEnterTag($match)
117337748cd8SNickeau    {
117437748cd8SNickeau        // Until the first >
117537748cd8SNickeau        $pos = strpos($match, ">");
117637748cd8SNickeau        if ($pos == false) {
117737748cd8SNickeau            LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_WARNING);
117837748cd8SNickeau            return null;
117937748cd8SNickeau        }
118037748cd8SNickeau        $match = substr($match, 0, $pos);
118137748cd8SNickeau
118237748cd8SNickeau
118337748cd8SNickeau        // Trim to start clean
118437748cd8SNickeau        $match = trim($match);
118537748cd8SNickeau
118637748cd8SNickeau        // Suppress the <
118737748cd8SNickeau        if ($match[0] == "<") {
118837748cd8SNickeau            $match = substr($match, 1);
118937748cd8SNickeau        }
119037748cd8SNickeau
119137748cd8SNickeau        // Suppress the / for a leaf tag
119237748cd8SNickeau        if ($match[strlen($match) - 1] == "/") {
119337748cd8SNickeau            $match = substr($match, 0, strlen($match) - 1);
119437748cd8SNickeau        }
119537748cd8SNickeau        return $match;
119637748cd8SNickeau    }
119737748cd8SNickeau
119837748cd8SNickeau    /**
119937748cd8SNickeau     * Retrieve the tag name used in the text document
120037748cd8SNickeau     * @param $match
120137748cd8SNickeau     * @return false|string|null
120237748cd8SNickeau     */
120337748cd8SNickeau    public
120437748cd8SNickeau    static function getSyntaxTagNameFromMatch($match)
120537748cd8SNickeau    {
120637748cd8SNickeau        $preprocessMatch = PluginUtility::getPreprocessEnterTag($match);
120737748cd8SNickeau
120837748cd8SNickeau        // Tag name (ie until the first blank)
120937748cd8SNickeau        $spacePosition = strpos($match, " ");
121037748cd8SNickeau        if (!$spacePosition) {
121137748cd8SNickeau            // No space, meaning this is only the tag name
121237748cd8SNickeau            return $preprocessMatch;
121337748cd8SNickeau        } else {
121437748cd8SNickeau            return trim(substr(0, $spacePosition));
121537748cd8SNickeau        }
121637748cd8SNickeau
121737748cd8SNickeau    }
121837748cd8SNickeau
121937748cd8SNickeau    /**
122037748cd8SNickeau     * @param \Doku_Renderer_xhtml $renderer
122137748cd8SNickeau     * @param $position
122237748cd8SNickeau     * @param $name
122337748cd8SNickeau     */
122437748cd8SNickeau    public
122537748cd8SNickeau    static function startSection($renderer, $position, $name)
122637748cd8SNickeau    {
122737748cd8SNickeau
122837748cd8SNickeau
122937748cd8SNickeau        if (empty($position)) {
123037748cd8SNickeau            LogUtility::msg("The position for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support");
123137748cd8SNickeau        }
123237748cd8SNickeau        if (empty($name)) {
123337748cd8SNickeau            LogUtility::msg("The name for a start section should not be empty", LogUtility::LVL_MSG_ERROR, "support");
123437748cd8SNickeau        }
123537748cd8SNickeau
123637748cd8SNickeau        /**
123737748cd8SNickeau         * New Dokuwiki Version
123837748cd8SNickeau         * for DokuWiki Greebo and more recent versions
123937748cd8SNickeau         */
124037748cd8SNickeau        if (defined('SEC_EDIT_PATTERN')) {
124137748cd8SNickeau            $renderer->startSectionEdit($position, array('target' => self::EDIT_SECTION_TARGET, 'name' => $name));
124237748cd8SNickeau        } else {
124337748cd8SNickeau            /**
124437748cd8SNickeau             * Old version
124537748cd8SNickeau             */
124637748cd8SNickeau            /** @noinspection PhpParamsInspection */
124737748cd8SNickeau            $renderer->startSectionEdit($position, self::EDIT_SECTION_TARGET, $name);
124837748cd8SNickeau        }
124937748cd8SNickeau    }
125037748cd8SNickeau
125137748cd8SNickeau    /**
125237748cd8SNickeau     * Add an enter call to the stack
125337748cd8SNickeau     * @param \Doku_Handler $handler
125437748cd8SNickeau     * @param $tagName
125537748cd8SNickeau     * @param array $callStackArray
125637748cd8SNickeau     */
125737748cd8SNickeau    public
125837748cd8SNickeau    static function addEnterCall(
125937748cd8SNickeau        \Doku_Handler &$handler,
126037748cd8SNickeau        $tagName,
126137748cd8SNickeau        $callStackArray = array()
126237748cd8SNickeau    )
126337748cd8SNickeau    {
126437748cd8SNickeau        $pluginName = PluginUtility::getComponentName($tagName);
126537748cd8SNickeau        $handler->addPluginCall(
126637748cd8SNickeau            $pluginName,
126737748cd8SNickeau            $callStackArray,
126837748cd8SNickeau            DOKU_LEXER_ENTER,
126937748cd8SNickeau            null,
127037748cd8SNickeau            null
127137748cd8SNickeau        );
127237748cd8SNickeau    }
127337748cd8SNickeau
127437748cd8SNickeau    /**
127537748cd8SNickeau     * Add an end call dynamically
127637748cd8SNickeau     * @param \Doku_Handler $handler
127737748cd8SNickeau     * @param $tagName
127837748cd8SNickeau     * @param array $callStackArray
127937748cd8SNickeau     */
128037748cd8SNickeau    public
128137748cd8SNickeau    static function addEndCall(\Doku_Handler $handler, $tagName, $callStackArray = array())
128237748cd8SNickeau    {
128337748cd8SNickeau        $pluginName = PluginUtility::getComponentName($tagName);
128437748cd8SNickeau        $handler->addPluginCall(
128537748cd8SNickeau            $pluginName,
128637748cd8SNickeau            $callStackArray,
128737748cd8SNickeau            DOKU_LEXER_END,
128837748cd8SNickeau            null,
128937748cd8SNickeau            null
129037748cd8SNickeau        );
129137748cd8SNickeau    }
129237748cd8SNickeau
129337748cd8SNickeau    /**
129437748cd8SNickeau     * General Debug
129537748cd8SNickeau     */
129637748cd8SNickeau    public
129737748cd8SNickeau    static function isDebug()
129837748cd8SNickeau    {
129937748cd8SNickeau        global $conf;
130037748cd8SNickeau        return $conf["allowdebug"] === 1;
130137748cd8SNickeau
130237748cd8SNickeau    }
130337748cd8SNickeau
130437748cd8SNickeau    /**
130537748cd8SNickeau     * @return bool true if loaded, false otherwise
130637748cd8SNickeau     * Strap is loaded only if this is the same version
130737748cd8SNickeau     * to avoid function, class, or members that does not exist
130837748cd8SNickeau     */
130937748cd8SNickeau    public
131037748cd8SNickeau    static function loadStrapUtilityTemplateIfPresentAndSameVersion()
131137748cd8SNickeau    {
131237748cd8SNickeau        $templateUtilityFile = __DIR__ . '/../../../tpl/strap/class/TplUtility.php';
131337748cd8SNickeau        if (file_exists($templateUtilityFile)) {
131437748cd8SNickeau            /**
131537748cd8SNickeau             * Check the version
131637748cd8SNickeau             */
131737748cd8SNickeau            $templateInfo = confToHash(__DIR__ . '/../../../tpl/strap/template.info.txt');
131837748cd8SNickeau            $templateVersion = $templateInfo['version'];
131937748cd8SNickeau            $comboVersion = self::$INFO_PLUGIN['version'];
132037748cd8SNickeau            if ($templateVersion != $comboVersion) {
132137748cd8SNickeau                if ($comboVersion > $templateVersion) {
132237748cd8SNickeau                    LogUtility::msg("You should upgrade <a href=\"https://www.dokuwiki.org/template:strap\">strap</a> to the latest version to get a fully functional experience. The version of Combo is ($comboVersion) while the version of Strap is ($templateVersion).");
132337748cd8SNickeau                } else {
132437748cd8SNickeau                    LogUtility::msg("You should upgrade <a href=\"https://www.dokuwiki.org/plugin:combo\">combo</a>  to the latest version to get a fully functional experience. The version of Combo is ($comboVersion) while the version of Strap is ($templateVersion).");
132537748cd8SNickeau                }
132637748cd8SNickeau                return false;
132737748cd8SNickeau            } else {
132837748cd8SNickeau                /** @noinspection PhpIncludeInspection */
132937748cd8SNickeau                require_once($templateUtilityFile);
133037748cd8SNickeau                return true;
133137748cd8SNickeau            }
133237748cd8SNickeau        } else {
133337748cd8SNickeau            $level = LogUtility::LVL_MSG_DEBUG;
133437748cd8SNickeau            if (defined('DOKU_UNITTEST')) {
133537748cd8SNickeau                // fail
133637748cd8SNickeau                $level = LogUtility::LVL_MSG_ERROR;
133737748cd8SNickeau            }
133837748cd8SNickeau            if (Site::getTemplate() != "strap") {
133937748cd8SNickeau                LogUtility::msg("The strap template is not installed", $level);
134037748cd8SNickeau            } else {
134137748cd8SNickeau                LogUtility::msg("The file ($templateUtilityFile) was not found", $level);
134237748cd8SNickeau            }
134337748cd8SNickeau            return false;
134437748cd8SNickeau        }
134537748cd8SNickeau    }
134637748cd8SNickeau
134737748cd8SNickeau
134837748cd8SNickeau    /**
134937748cd8SNickeau     *
135037748cd8SNickeau     * See also dev.md file
135137748cd8SNickeau     */
135237748cd8SNickeau    public static function isDevOrTest()
135337748cd8SNickeau    {
135437748cd8SNickeau        if (self::isDev()) {
135537748cd8SNickeau            return true;
135637748cd8SNickeau        }
135737748cd8SNickeau        return self::isTest();
135837748cd8SNickeau    }
135937748cd8SNickeau
136037748cd8SNickeau    public static function isDev()
136137748cd8SNickeau    {
136237748cd8SNickeau        global $_SERVER;
136337748cd8SNickeau        if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1") {
136437748cd8SNickeau            return true;
136537748cd8SNickeau        }
136637748cd8SNickeau        return false;
136737748cd8SNickeau    }
136837748cd8SNickeau
136937748cd8SNickeau    public static function getInstructions($markiCode)
137037748cd8SNickeau    {
137137748cd8SNickeau        return p_get_instructions($markiCode);
137237748cd8SNickeau    }
137337748cd8SNickeau
137437748cd8SNickeau    public static function getInstructionsWithoutRoot($markiCode)
137537748cd8SNickeau    {
137637748cd8SNickeau        return RenderUtility::getInstructionsAndStripPEventually($markiCode);
137737748cd8SNickeau    }
137837748cd8SNickeau
137937748cd8SNickeau    /**
138037748cd8SNickeau     * Transform a text into a valid HTML id
138137748cd8SNickeau     * @param $string
138237748cd8SNickeau     * @return string
138337748cd8SNickeau     */
138437748cd8SNickeau    public static function toHtmlId($string)
138537748cd8SNickeau    {
138637748cd8SNickeau        /**
138737748cd8SNickeau         * sectionId calls cleanID
138837748cd8SNickeau         * cleanID delete all things before a ':'
138937748cd8SNickeau         * we do then the replace before to not
139037748cd8SNickeau         * lost a minus '-' separator
139137748cd8SNickeau         */
139237748cd8SNickeau        $string = str_replace(array(':', '.'), '', $string);
139337748cd8SNickeau        return sectionID($string, $check);
139437748cd8SNickeau    }
139537748cd8SNickeau
139637748cd8SNickeau    public static function isTest()
139737748cd8SNickeau    {
139837748cd8SNickeau        return defined('DOKU_UNITTEST');
139937748cd8SNickeau    }
140037748cd8SNickeau
140137748cd8SNickeau
1402*c3437056SNickeau    public static function getCacheManager(): CacheManager
140337748cd8SNickeau    {
1404*c3437056SNickeau        return CacheManager::getOrCreate();
140537748cd8SNickeau    }
140637748cd8SNickeau
140737748cd8SNickeau    public static function getModeFromPluginName($name)
140837748cd8SNickeau    {
140937748cd8SNickeau        return "plugin_$name";
141037748cd8SNickeau    }
141137748cd8SNickeau
141237748cd8SNickeau    public static function isCi(): bool
141337748cd8SNickeau    {
141437748cd8SNickeau        // https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
141537748cd8SNickeau        return getenv("CI") === "true";
141637748cd8SNickeau    }
141737748cd8SNickeau
141837748cd8SNickeau
141937748cd8SNickeau}
142037748cd8SNickeau
142137748cd8SNickeauPluginUtility::init();
1422