xref: /plugin/combo/ComboStrap/PluginUtility.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
137748cd8SNickeau<?php
237748cd8SNickeau
337748cd8SNickeau
437748cd8SNickeaunamespace ComboStrap;
537748cd8SNickeau
637748cd8SNickeau
7*04fd306cSNickeauuse ComboStrap\Api\ApiRouter;
837748cd8SNickeauuse dokuwiki\Extension\Plugin;
937748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin;
1037748cd8SNickeau
1137748cd8SNickeau
1237748cd8SNickeau/**
1337748cd8SNickeau * Class url static
1437748cd8SNickeau * List of static utilities
1537748cd8SNickeau */
1637748cd8SNickeauclass PluginUtility
1737748cd8SNickeau{
1837748cd8SNickeau
1937748cd8SNickeau    const DOKU_DATA_DIR = '/dokudata/pages';
2037748cd8SNickeau    const DOKU_CACHE_DIR = '/dokudata/cache';
2137748cd8SNickeau
2237748cd8SNickeau    /**
2337748cd8SNickeau     * Key in the data array between the handle and render function
2437748cd8SNickeau     */
2537748cd8SNickeau    const STATE = "state";
2637748cd8SNickeau    const PAYLOAD = "payload"; // The html or text
2737748cd8SNickeau    const ATTRIBUTES = "attributes";
2837748cd8SNickeau// The context is generally the parent tag but it may be also the grandfather.
2937748cd8SNickeau// It permits to determine the HTML that is outputted
3037748cd8SNickeau    const CONTEXT = 'context';
3137748cd8SNickeau    const TAG = "tag";
3237748cd8SNickeau
3337748cd8SNickeau    /**
3437748cd8SNickeau     * The name of the hidden/private namespace
3537748cd8SNickeau     * where the icon and other artifactory are stored
3637748cd8SNickeau     */
3737748cd8SNickeau    const COMBOSTRAP_NAMESPACE_NAME = "combostrap";
3837748cd8SNickeau
3937748cd8SNickeau    const PARENT = "parent";
4037748cd8SNickeau    const POSITION = "position";
4137748cd8SNickeau
4237748cd8SNickeau
43*04fd306cSNickeau    const EXIT_MESSAGE = "exit_message";
444cadd4f8SNickeau    const EXIT_CODE = "exit_code";
45*04fd306cSNickeau
461fa8c418SNickeau    const DISPLAY = "display";
47*04fd306cSNickeau    const MARKUP_TAG = "markup-tag";
48*04fd306cSNickeau
4937748cd8SNickeau
5037748cd8SNickeau    /**
5137748cd8SNickeau     * The URL base of the documentation
5237748cd8SNickeau     */
53c3437056SNickeau    static $URL_APEX;
5437748cd8SNickeau
5537748cd8SNickeau
5637748cd8SNickeau    /**
5737748cd8SNickeau     * @var string - the plugin base name (ie the directory)
5837748cd8SNickeau     * ie $INFO_PLUGIN['base'];
5937748cd8SNickeau     * This is a constant because it permits code analytics
6037748cd8SNickeau     * such as verification of a path
6137748cd8SNickeau     */
6237748cd8SNickeau    const PLUGIN_BASE_NAME = "combo";
6337748cd8SNickeau
6437748cd8SNickeau    /**
6537748cd8SNickeau     * The name of the template plugin
6637748cd8SNickeau     */
6737748cd8SNickeau    const TEMPLATE_STRAP_NAME = "strap";
6837748cd8SNickeau
6937748cd8SNickeau    /**
7037748cd8SNickeau     * @var array
7137748cd8SNickeau     */
7237748cd8SNickeau    static $INFO_PLUGIN;
7337748cd8SNickeau
7437748cd8SNickeau    static $PLUGIN_LANG;
7537748cd8SNickeau
7637748cd8SNickeau    /**
7737748cd8SNickeau     * The plugin name
7837748cd8SNickeau     * (not the same than the base as it's not related to the directory
7937748cd8SNickeau     * @var string
8037748cd8SNickeau     */
8137748cd8SNickeau    public static $PLUGIN_NAME;
8237748cd8SNickeau    /**
83*04fd306cSNickeau     * @var LocalPath
8437748cd8SNickeau     */
85*04fd306cSNickeau    private static $PLUGIN_INFO_FILE;
8637748cd8SNickeau
8737748cd8SNickeau
8837748cd8SNickeau    /**
8937748cd8SNickeau     * Initiate the static variable
9037748cd8SNickeau     * See the call after this class
9137748cd8SNickeau     */
9237748cd8SNickeau    static function init()
9337748cd8SNickeau    {
9437748cd8SNickeau
95*04fd306cSNickeau        $pluginInfoFile = DirectoryLayout::getPluginInfoPath();
96*04fd306cSNickeau        self::$INFO_PLUGIN = confToHash($pluginInfoFile->toAbsoluteId());
9737748cd8SNickeau        self::$PLUGIN_NAME = 'ComboStrap';
9837748cd8SNickeau        global $lang;
9937748cd8SNickeau        self::$PLUGIN_LANG = $lang[self::PLUGIN_BASE_NAME];
100c3437056SNickeau        self::$URL_APEX = "https://" . parse_url(self::$INFO_PLUGIN['url'], PHP_URL_HOST);
101*04fd306cSNickeau        //self::$VERSION = self::$INFO_PLUGIN['version'];
10237748cd8SNickeau
10337748cd8SNickeau    }
10437748cd8SNickeau
10537748cd8SNickeau    /**
10637748cd8SNickeau     * @param $inputExpression
10737748cd8SNickeau     * @return false|int 1|0
10837748cd8SNickeau     * returns:
10937748cd8SNickeau     *    - 1 if the input expression is a pattern,
11037748cd8SNickeau     *    - 0 if not,
11137748cd8SNickeau     *    - FALSE if an error occurred.
11237748cd8SNickeau     */
11337748cd8SNickeau    static function isRegularExpression($inputExpression)
11437748cd8SNickeau    {
11537748cd8SNickeau
11637748cd8SNickeau        $regularExpressionPattern = "/(\\/.*\\/[gmixXsuUAJ]?)/";
11737748cd8SNickeau        return preg_match($regularExpressionPattern, $inputExpression);
11837748cd8SNickeau
11937748cd8SNickeau    }
12037748cd8SNickeau
12137748cd8SNickeau    /**
12237748cd8SNickeau     * Return a mode from a tag (ie from a {@link Plugin::getPluginComponent()}
12337748cd8SNickeau     * @param $tag
12437748cd8SNickeau     * @return string
12537748cd8SNickeau     *
12637748cd8SNickeau     * A mode is just a name for a class
12737748cd8SNickeau     * Example: $Parser->addMode('listblock',new Doku_Parser_Mode_ListBlock());
12837748cd8SNickeau     */
12937748cd8SNickeau    public static function getModeFromTag($tag)
13037748cd8SNickeau    {
13137748cd8SNickeau        return "plugin_" . self::getComponentName($tag);
13237748cd8SNickeau    }
13337748cd8SNickeau
13437748cd8SNickeau
13537748cd8SNickeau    /**
13637748cd8SNickeau     * This pattern allows space after the tag name
13737748cd8SNickeau     * for an end tag
13837748cd8SNickeau     * As XHTML (https://www.w3.org/TR/REC-xml/#dt-etag)
13937748cd8SNickeau     * @param $tag
14037748cd8SNickeau     * @return string
14137748cd8SNickeau     */
14237748cd8SNickeau    public static function getEndTagPattern($tag)
14337748cd8SNickeau    {
14437748cd8SNickeau        return "</$tag\s*>";
14537748cd8SNickeau    }
14637748cd8SNickeau
14737748cd8SNickeau    /**
14837748cd8SNickeau     * @param $tag
14937748cd8SNickeau     * @return string
15037748cd8SNickeau     *
15137748cd8SNickeau     * Create a open tag pattern without lookahead.
152c3437056SNickeau     * Used for
153c3437056SNickeau     * @link https://dev.w3.org/html5/html-author/#void-elements-0
15437748cd8SNickeau     */
15537748cd8SNickeau    public static function getVoidElementTagPattern($tag)
15637748cd8SNickeau    {
15737748cd8SNickeau        return ' < ' . $tag . ' .*?>';
15837748cd8SNickeau    }
15937748cd8SNickeau
16037748cd8SNickeau
16137748cd8SNickeau    /**
16237748cd8SNickeau     * Take an array  where the key is the attribute name
16337748cd8SNickeau     * and return a HTML tag string
16437748cd8SNickeau     *
16537748cd8SNickeau     * The attribute name and value are escaped
16637748cd8SNickeau     *
16737748cd8SNickeau     * @param $attributes - combo attributes
16837748cd8SNickeau     * @return string
16937748cd8SNickeau     * @deprecated to allowed background and other metadata, use {@link TagAttributes::toHtmlEnterTag()}
17037748cd8SNickeau     */
17137748cd8SNickeau    public static function array2HTMLAttributesAsString($attributes)
17237748cd8SNickeau    {
17337748cd8SNickeau
17437748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
17537748cd8SNickeau        return $tagAttributes->toHTMLAttributeString();
17637748cd8SNickeau
17737748cd8SNickeau    }
17837748cd8SNickeau
17937748cd8SNickeau    /**
18037748cd8SNickeau     *
18137748cd8SNickeau     * Parse the attributes part of a match
18237748cd8SNickeau     *
18337748cd8SNickeau     * Example:
18437748cd8SNickeau     *   line-numbers="value"
18537748cd8SNickeau     *   line-numbers='value'
18637748cd8SNickeau     *
18737748cd8SNickeau     * This value may be in:
18837748cd8SNickeau     *   * configuration value
18937748cd8SNickeau     *   * as well as in the match of a {@link SyntaxPlugin}
19037748cd8SNickeau     *
19137748cd8SNickeau     * @param $string
19237748cd8SNickeau     * @return array
19337748cd8SNickeau     *
19437748cd8SNickeau     * To parse a match, use {@link PluginUtility::getTagAttributes()}
19537748cd8SNickeau     *
19637748cd8SNickeau     *
19737748cd8SNickeau     */
19837748cd8SNickeau    public static function parseAttributes($string)
19937748cd8SNickeau    {
20037748cd8SNickeau
20137748cd8SNickeau        $parameters = array();
20237748cd8SNickeau
20337748cd8SNickeau// Rules
20437748cd8SNickeau//  * name may be alone (ie true boolean attribute)
20537748cd8SNickeau//  * a name may get a `-`
20637748cd8SNickeau//  * there may be space every everywhere when the value is enclosed with a quote
20737748cd8SNickeau//  * there may be no space in the value and between the equal sign when the value is not enclosed
20837748cd8SNickeau//
20937748cd8SNickeau// /i not case sensitive
21037748cd8SNickeau        $attributePattern = '\s*([-\w]+)\s*(?:=(\s*[\'"]([^`"]*)[\'"]\s*|[^\s]*))?';
21137748cd8SNickeau        $result = preg_match_all('/' . $attributePattern . '/i', $string, $matches);
21237748cd8SNickeau        if ($result != 0) {
21337748cd8SNickeau            foreach ($matches[1] as $key => $parameterKey) {
21437748cd8SNickeau
21537748cd8SNickeau// group 3 (ie the value between quotes)
21637748cd8SNickeau                $value = $matches[3][$key];
21737748cd8SNickeau                if ($value == "") {
21837748cd8SNickeau// check the value without quotes
21937748cd8SNickeau                    $value = $matches[2][$key];
22037748cd8SNickeau                }
22137748cd8SNickeau// if there is no value, this is a boolean
22237748cd8SNickeau                if ($value == "") {
22337748cd8SNickeau                    $value = true;
22437748cd8SNickeau                } else {
22537748cd8SNickeau                    $value = hsc($value);
22637748cd8SNickeau                }
22737748cd8SNickeau                $parameters[hsc(strtolower($parameterKey))] = $value;
22837748cd8SNickeau            }
22937748cd8SNickeau        }
23037748cd8SNickeau        return $parameters;
23137748cd8SNickeau
23237748cd8SNickeau    }
23337748cd8SNickeau
234*04fd306cSNickeau    public static function getTagAttributes(string $match, array $knownTypes = [], bool $allowFirstBooleanAttributesAsType = false): array
23537748cd8SNickeau    {
236*04fd306cSNickeau        return self::getQualifiedTagAttributes($match, false, "", $knownTypes, $allowFirstBooleanAttributesAsType);
23737748cd8SNickeau    }
23837748cd8SNickeau
23937748cd8SNickeau    /**
24037748cd8SNickeau     * Return the attribute of a tag
24137748cd8SNickeau     * Because they are users input, they are all escaped
24237748cd8SNickeau     * @param $match
24337748cd8SNickeau     * @param $hasThirdValue - if true, the third parameter is treated as value, not a property and returned in the `third` key
24437748cd8SNickeau     * use for the code/file/console where they accept a name as third value
24537748cd8SNickeau     * @param $keyThirdArgument - if a third argument is found, return it with this key
2464cadd4f8SNickeau     * @param array|null $knownTypes
247*04fd306cSNickeau     * @param bool $allowFirstBooleanAttributesAsType
24837748cd8SNickeau     * @return array
24937748cd8SNickeau     */
250*04fd306cSNickeau    public static function getQualifiedTagAttributes($match, $hasThirdValue, $keyThirdArgument, array $knownTypes = [], bool $allowFirstBooleanAttributesAsType = false): array
25137748cd8SNickeau    {
25237748cd8SNickeau
25337748cd8SNickeau        $match = PluginUtility::getPreprocessEnterTag($match);
25437748cd8SNickeau
25537748cd8SNickeau        // Suppress the tag name (ie until the first blank)
25637748cd8SNickeau        $spacePosition = strpos($match, " ");
25737748cd8SNickeau        if (!$spacePosition) {
25837748cd8SNickeau        // No space, meaning this is only the tag name
25937748cd8SNickeau            return array();
26037748cd8SNickeau        }
26137748cd8SNickeau        $match = trim(substr($match, $spacePosition));
26237748cd8SNickeau        if ($match == "") {
26337748cd8SNickeau            return array();
26437748cd8SNickeau        }
26537748cd8SNickeau
266*04fd306cSNickeau        /**
267*04fd306cSNickeau         * Do we have a type as first argument ?
268*04fd306cSNickeau         */
26937748cd8SNickeau        $attributes = array();
27037748cd8SNickeau        $spacePosition = strpos($match, " ");
27137748cd8SNickeau        if ($spacePosition) {
27237748cd8SNickeau            $nextArgument = substr($match, 0, $spacePosition);
27337748cd8SNickeau        } else {
27437748cd8SNickeau            $nextArgument = $match;
27537748cd8SNickeau        }
2764cadd4f8SNickeau
277*04fd306cSNickeau        $isBooleanAttribute = !strpos($nextArgument, "=");
2784cadd4f8SNickeau        $isType = false;
279*04fd306cSNickeau        if ($isBooleanAttribute) {
280*04fd306cSNickeau            $possibleTypeLowercase = strtolower($nextArgument);
281*04fd306cSNickeau            if ($allowFirstBooleanAttributesAsType) {
282*04fd306cSNickeau                $isType = true;
283*04fd306cSNickeau                $nextArgument = $possibleTypeLowercase;
284*04fd306cSNickeau            } else {
285*04fd306cSNickeau                if (!empty($knownTypes) && in_array($possibleTypeLowercase, $knownTypes)) {
286*04fd306cSNickeau                    $isType = true;
287*04fd306cSNickeau                    $nextArgument = $possibleTypeLowercase;
288*04fd306cSNickeau                }
2894cadd4f8SNickeau            }
2904cadd4f8SNickeau        }
2914cadd4f8SNickeau        if ($isType) {
2924cadd4f8SNickeau
293*04fd306cSNickeau            $attributes[TagAttributes::TYPE_KEY] = $nextArgument;
294*04fd306cSNickeau            /**
295*04fd306cSNickeau             * Suppress the type
296*04fd306cSNickeau             */
29737748cd8SNickeau            $match = substr($match, strlen($nextArgument));
29837748cd8SNickeau            $match = trim($match);
29937748cd8SNickeau
300*04fd306cSNickeau            /**
301*04fd306cSNickeau             * Do we have a value as first argument ?
302*04fd306cSNickeau             */
30337748cd8SNickeau            if (!empty($hasThirdValue)) {
30437748cd8SNickeau                $spacePosition = strpos($match, " ");
30537748cd8SNickeau                if ($spacePosition) {
30637748cd8SNickeau                    $nextArgument = substr($match, 0, $spacePosition);
30737748cd8SNickeau                } else {
30837748cd8SNickeau                    $nextArgument = $match;
30937748cd8SNickeau                }
31037748cd8SNickeau                if (!strpos($nextArgument, "=") && !empty($nextArgument)) {
31137748cd8SNickeau                    $attributes[$keyThirdArgument] = $nextArgument;
312*04fd306cSNickeau                    /**
313*04fd306cSNickeau                     * Suppress the third argument
314*04fd306cSNickeau                     */
31537748cd8SNickeau                    $match = substr($match, strlen($nextArgument));
31637748cd8SNickeau                    $match = trim($match);
31737748cd8SNickeau                }
31837748cd8SNickeau            }
31937748cd8SNickeau        }
32037748cd8SNickeau
321*04fd306cSNickeau        /**
322*04fd306cSNickeau         * Parse the remaining attributes
323*04fd306cSNickeau         */
32437748cd8SNickeau        $parsedAttributes = self::parseAttributes($match);
32537748cd8SNickeau
326*04fd306cSNickeau        /**
327*04fd306cSNickeau         * Merge
328*04fd306cSNickeau         */
32937748cd8SNickeau        $attributes = array_merge($attributes, $parsedAttributes);;
33037748cd8SNickeau
33137748cd8SNickeau        return $attributes;
33237748cd8SNickeau
33337748cd8SNickeau    }
33437748cd8SNickeau
33537748cd8SNickeau    /**
33637748cd8SNickeau     * @param $tag
33737748cd8SNickeau     * @return string
33837748cd8SNickeau     * Create a pattern used where the tag is not a container.
33937748cd8SNickeau     * ie
34037748cd8SNickeau     * <br/>
341*04fd306cSNickeau     *
34237748cd8SNickeau     * <icon/>
34337748cd8SNickeau     * This is generally used with a subtition plugin
34437748cd8SNickeau     * and a {@link Lexer::addSpecialPattern} state
34537748cd8SNickeau     * where the tag is just replaced
34637748cd8SNickeau     */
34719494974Sgerardnico    public static function getEmptyTagPattern($tag): string
34837748cd8SNickeau    {
34919494974Sgerardnico
3504cadd4f8SNickeau        /**
3514cadd4f8SNickeau         * A tag should start with the tag
3524cadd4f8SNickeau         * `(?=[/ ]{1})` - a space or the / (lookahead) => to allow allow tag name with minus character
3534cadd4f8SNickeau         * `(?![^/]>)` - it's not a normal tag (ie a > with the previous character that is not /)
3544cadd4f8SNickeau         * `[^>]*` then until the > is found (dokuwiki capture greedy, don't use the point character)
3554cadd4f8SNickeau         * then until the close `/>` character
3564cadd4f8SNickeau         */
3574cadd4f8SNickeau        return '<' . $tag . '(?=[/ ]{1})(?![^/]>)[^>]*\/>';
35837748cd8SNickeau    }
35937748cd8SNickeau
360*04fd306cSNickeau    public static function getEmptyTagPatternGeneral(): string
361*04fd306cSNickeau    {
362*04fd306cSNickeau
363*04fd306cSNickeau        return self::getEmptyTagPattern("[\w-]+");
364*04fd306cSNickeau    }
365*04fd306cSNickeau
36637748cd8SNickeau    /**
36737748cd8SNickeau     * Just call this function from a class like that
36837748cd8SNickeau     *     getTageName(get_called_class())
36937748cd8SNickeau     * to get the tag name (ie the component plugin)
37037748cd8SNickeau     * of a syntax plugin
37137748cd8SNickeau     *
37237748cd8SNickeau     * @param $get_called_class
37337748cd8SNickeau     * @return string
37437748cd8SNickeau     */
37537748cd8SNickeau    public static function getTagName($get_called_class)
37637748cd8SNickeau    {
37737748cd8SNickeau        list(/* $t */, /* $p */, /* $n */, $c) = explode('_', $get_called_class, 4);
37837748cd8SNickeau        return (isset($c) ? $c : '');
37937748cd8SNickeau    }
38037748cd8SNickeau
38137748cd8SNickeau    /**
38237748cd8SNickeau     * Just call this function from a class like that
38337748cd8SNickeau     *     getAdminPageName(get_called_class())
38437748cd8SNickeau     * to get the page name of a admin plugin
38537748cd8SNickeau     *
38637748cd8SNickeau     * @param $get_called_class
38737748cd8SNickeau     * @return string - the admin page name
38837748cd8SNickeau     */
38937748cd8SNickeau    public static function getAdminPageName($get_called_class)
39037748cd8SNickeau    {
39137748cd8SNickeau        $names = explode('_', $get_called_class);
39237748cd8SNickeau        $names = array_slice($names, -2);
39337748cd8SNickeau        return implode('_', $names);
39437748cd8SNickeau    }
39537748cd8SNickeau
39637748cd8SNickeau    public static function getNameSpace()
39737748cd8SNickeau    {
39837748cd8SNickeau// No : at the begin of the namespace please
39937748cd8SNickeau        return self::PLUGIN_BASE_NAME . ':';
40037748cd8SNickeau    }
40137748cd8SNickeau
40237748cd8SNickeau    /**
40337748cd8SNickeau     * @param $get_called_class - the plugin class
40437748cd8SNickeau     * @return array
40537748cd8SNickeau     */
40637748cd8SNickeau    public static function getTags($get_called_class)
40737748cd8SNickeau    {
40837748cd8SNickeau        $elements = array();
40937748cd8SNickeau        $elementName = PluginUtility::getTagName($get_called_class);
41037748cd8SNickeau        $elements[] = $elementName;
41137748cd8SNickeau        $elements[] = strtoupper($elementName);
41237748cd8SNickeau        return $elements;
41337748cd8SNickeau    }
41437748cd8SNickeau
41537748cd8SNickeau    /**
41637748cd8SNickeau     * Render a text
41737748cd8SNickeau     * @param $pageContent
41837748cd8SNickeau     * @return string|null
41937748cd8SNickeau     */
420*04fd306cSNickeau    public static function render($pageContent): ?string
42137748cd8SNickeau    {
422*04fd306cSNickeau        return MarkupRenderUtility::renderText2XhtmlAndStripPEventually($pageContent, false);
42337748cd8SNickeau    }
42437748cd8SNickeau
42537748cd8SNickeau
42637748cd8SNickeau    /**
42737748cd8SNickeau     * This method will takes attributes
42837748cd8SNickeau     * and process the plugin styling attribute such as width and height
42937748cd8SNickeau     * to put them in a style HTML attribute
43037748cd8SNickeau     * @param TagAttributes $attributes
43137748cd8SNickeau     */
43237748cd8SNickeau    public static function processStyle(&$attributes)
43337748cd8SNickeau    {
43437748cd8SNickeau        // Style
43537748cd8SNickeau        $styleAttributeName = "style";
43637748cd8SNickeau        if ($attributes->hasComponentAttribute($styleAttributeName)) {
43737748cd8SNickeau            $properties = explode(";", $attributes->getValueAndRemove($styleAttributeName));
43837748cd8SNickeau            foreach ($properties as $property) {
43937748cd8SNickeau                list($key, $value) = explode(":", $property);
44037748cd8SNickeau                if ($key != "") {
44182a60d03SNickeau                    $attributes->addStyleDeclarationIfNotSet($key, $value);
44237748cd8SNickeau                }
44337748cd8SNickeau            }
44437748cd8SNickeau        }
44537748cd8SNickeau
44637748cd8SNickeau
44737748cd8SNickeau        /**
44837748cd8SNickeau         * Border Color
44937748cd8SNickeau         * For background color, see {@link TagAttributes::processBackground()}
45037748cd8SNickeau         * For text color, see {@link TextColor}
45137748cd8SNickeau         */
45237748cd8SNickeau
4534cadd4f8SNickeau        if ($attributes->hasComponentAttribute(ColorRgb::BORDER_COLOR)) {
4544cadd4f8SNickeau            $colorValue = $attributes->getValueAndRemove(ColorRgb::BORDER_COLOR);
4554cadd4f8SNickeau            $attributes->addStyleDeclarationIfNotSet(ColorRgb::BORDER_COLOR, ColorRgb::createFromString($colorValue)->toCssValue());
45637748cd8SNickeau            self::checkDefaultBorderColorAttributes($attributes);
45737748cd8SNickeau        }
45837748cd8SNickeau
45937748cd8SNickeau
46037748cd8SNickeau    }
46137748cd8SNickeau
46237748cd8SNickeau    /**
46337748cd8SNickeau     * Return the name of the requested script
46437748cd8SNickeau     */
46537748cd8SNickeau    public
46637748cd8SNickeau    static function getRequestScript()
46737748cd8SNickeau    {
46837748cd8SNickeau        $scriptPath = null;
46937748cd8SNickeau        $testPropertyValue = self::getPropertyValue("SCRIPT_NAME");
47037748cd8SNickeau        if (defined('DOKU_UNITTEST') && $testPropertyValue != null) {
47137748cd8SNickeau            return $testPropertyValue;
47237748cd8SNickeau        }
47337748cd8SNickeau        if (array_key_exists("DOCUMENT_URI", $_SERVER)) {
47437748cd8SNickeau            $scriptPath = $_SERVER["DOCUMENT_URI"];
47537748cd8SNickeau        }
47637748cd8SNickeau        if ($scriptPath == null && array_key_exists("SCRIPT_NAME", $_SERVER)) {
47737748cd8SNickeau            $scriptPath = $_SERVER["SCRIPT_NAME"];
47837748cd8SNickeau        }
47937748cd8SNickeau        if ($scriptPath == null) {
48037748cd8SNickeau            msg("Unable to find the main script", LogUtility::LVL_MSG_ERROR);
48137748cd8SNickeau        }
48237748cd8SNickeau        $path_parts = pathinfo($scriptPath);
48337748cd8SNickeau        return $path_parts['basename'];
48437748cd8SNickeau    }
48537748cd8SNickeau
48637748cd8SNickeau    /**
48737748cd8SNickeau     *
48837748cd8SNickeau     * @param $name
48937748cd8SNickeau     * @param $default
49037748cd8SNickeau     * @return string - the value of a query string property or if in test mode, the value of a test variable
49137748cd8SNickeau     * set with {@link self::setTestProperty}
49237748cd8SNickeau     * This is used to test script that are not supported by the dokuwiki test framework
49337748cd8SNickeau     * such as css.php
494*04fd306cSNickeau     * @deprecated use {@link ApiRouter::getRequestParameter()}
49537748cd8SNickeau     */
49637748cd8SNickeau    public
49737748cd8SNickeau    static function getPropertyValue($name, $default = null)
49837748cd8SNickeau    {
49937748cd8SNickeau        global $INPUT;
50037748cd8SNickeau        $value = $INPUT->str($name);
50137748cd8SNickeau        if ($value == null && defined('DOKU_UNITTEST')) {
50237748cd8SNickeau            global $COMBO;
50337748cd8SNickeau            $value = $COMBO[$name];
50437748cd8SNickeau        }
50537748cd8SNickeau        if ($value == null) {
50637748cd8SNickeau            return $default;
50737748cd8SNickeau        } else {
50837748cd8SNickeau            return $value;
50937748cd8SNickeau        }
51037748cd8SNickeau
51137748cd8SNickeau    }
51237748cd8SNickeau
51337748cd8SNickeau    /**
51437748cd8SNickeau     * Create an URL to the documentation website
51537748cd8SNickeau     * @param $canonical - canonical id or slug
516c3437056SNickeau     * @param $label -  the text of the link
517*04fd306cSNickeau     * @param bool $withIcon - used to break the recursion with the message in the {@link IconDownloader}
51837748cd8SNickeau     * @return string - an url
51937748cd8SNickeau     */
52037748cd8SNickeau    public
521*04fd306cSNickeau    static function getDocumentationHyperLink($canonical, $label, bool $withIcon = true, $tooltip = ""): string
52237748cd8SNickeau    {
52337748cd8SNickeau
52437748cd8SNickeau        $xhtmlIcon = "";
52537748cd8SNickeau        if ($withIcon) {
52637748cd8SNickeau
527*04fd306cSNickeau            $logoPath = WikiPath::createComboResource("images:logo.svg");
5284cadd4f8SNickeau            try {
529*04fd306cSNickeau                $fetchImage = FetcherSvg::createSvgFromPath($logoPath);
530*04fd306cSNickeau                $fetchImage->setRequestedType(FetcherSvg::ICON_TYPE)
531*04fd306cSNickeau                    ->setRequestedWidth(20);
532*04fd306cSNickeau                $xhtmlIcon = SvgImageLink::createFromFetcher($fetchImage)
533*04fd306cSNickeau                    ->renderMediaTag();
534*04fd306cSNickeau            } catch (ExceptionCompile $e) {
535*04fd306cSNickeau                /**
536*04fd306cSNickeau                 * We don't throw because this function
537*04fd306cSNickeau                 * is also used by:
538*04fd306cSNickeau                 *   * the log functionality to show link to the documentation creating a loop
539*04fd306cSNickeau                 *   * inside the configuration description crashing the page
540*04fd306cSNickeau                 */
541*04fd306cSNickeau                if (PluginUtility::isDevOrTest()) {
542*04fd306cSNickeau// shows errors in the html only on dev/test
543*04fd306cSNickeau                    $xhtmlIcon = "Error: {$e->getMessage()}";
54437748cd8SNickeau                }
5454cadd4f8SNickeau            }
54637748cd8SNickeau
54737748cd8SNickeau        }
548c3437056SNickeau        $urlApex = self::$URL_APEX;
549c3437056SNickeau        $path = str_replace(":", "/", $canonical);
550c3437056SNickeau        if (empty($tooltip)) {
551c3437056SNickeau            $title = $label;
552c3437056SNickeau        } else {
553c3437056SNickeau            $title = $tooltip;
554c3437056SNickeau        }
555c3437056SNickeau        $htmlToolTip = "";
556c3437056SNickeau        if (!empty($tooltip)) {
557c3437056SNickeau            $dataAttributeNamespace = Bootstrap::getDataNamespace();
558c3437056SNickeau            $htmlToolTip = "data{$dataAttributeNamespace}-toggle=\"tooltip\"";
559c3437056SNickeau        }
560c3437056SNickeau        return "$xhtmlIcon<a href=\"$urlApex/$path\" title=\"$title\" $htmlToolTip style=\"text-decoration:none;\">$label</a>";
56137748cd8SNickeau    }
56237748cd8SNickeau
56337748cd8SNickeau    /**
56437748cd8SNickeau     * An utility function to not search every time which array should be first
56537748cd8SNickeau     * @param array $inlineAttributes - the component inline attributes
56637748cd8SNickeau     * @param array $defaultAttributes - the default configuration attributes
56737748cd8SNickeau     * @return array - a merged array
56837748cd8SNickeau     */
56937748cd8SNickeau    public
57037748cd8SNickeau    static function mergeAttributes(array $inlineAttributes, array $defaultAttributes = array())
57137748cd8SNickeau    {
57237748cd8SNickeau        return array_merge($defaultAttributes, $inlineAttributes);
57337748cd8SNickeau    }
57437748cd8SNickeau
57537748cd8SNickeau    /**
57637748cd8SNickeau     * A pattern for a container tag
57737748cd8SNickeau     * that needs to catch the content
57837748cd8SNickeau     *
57937748cd8SNickeau     * Use as a special pattern (substition)
58037748cd8SNickeau     *
58137748cd8SNickeau     * The {@link \syntax_plugin_combo_math} use it
58237748cd8SNickeau     * @param $tag
58337748cd8SNickeau     * @return string - a pattern
58437748cd8SNickeau     */
58537748cd8SNickeau    public
58637748cd8SNickeau    static function getLeafContainerTagPattern($tag)
58737748cd8SNickeau    {
58837748cd8SNickeau        return '<' . $tag . '.*?>.*?<\/' . $tag . '>';
58937748cd8SNickeau    }
59037748cd8SNickeau
59137748cd8SNickeau    /**
59237748cd8SNickeau     * Return the content of a tag
593*04fd306cSNickeau     *
59437748cd8SNickeau     * <math>Content</math>
59537748cd8SNickeau     * @param $match
59637748cd8SNickeau     * @return string the content
59737748cd8SNickeau     */
59837748cd8SNickeau    public
59937748cd8SNickeau    static function getTagContent($match)
60037748cd8SNickeau    {
60137748cd8SNickeau// From the first >
60237748cd8SNickeau        $start = strpos($match, ">");
60337748cd8SNickeau        if ($start == false) {
60437748cd8SNickeau            LogUtility::msg("The match does not contain any opening tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
60537748cd8SNickeau            return "";
60637748cd8SNickeau        }
60737748cd8SNickeau        $match = substr($match, $start + 1);
60837748cd8SNickeau// If this is the last character, we get a false
60937748cd8SNickeau        if ($match == false) {
61037748cd8SNickeau            LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
61137748cd8SNickeau            return "";
61237748cd8SNickeau        }
61337748cd8SNickeau
61437748cd8SNickeau        $end = strrpos($match, "</");
61537748cd8SNickeau        if ($end == false) {
61637748cd8SNickeau            LogUtility::msg("The match does not contain any closing tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
61737748cd8SNickeau            return "";
61837748cd8SNickeau        }
61937748cd8SNickeau
62037748cd8SNickeau        return substr($match, 0, $end);
62137748cd8SNickeau    }
62237748cd8SNickeau
62337748cd8SNickeau    /**
62437748cd8SNickeau     *
62537748cd8SNickeau     * Check if a HTML tag was already added for a request
62637748cd8SNickeau     * The request id is just the timestamp
62737748cd8SNickeau     * An indicator array should be provided
62837748cd8SNickeau     * @return string
62937748cd8SNickeau     */
63037748cd8SNickeau    public
63137748cd8SNickeau    static function getRequestId()
63237748cd8SNickeau    {
63337748cd8SNickeau
63437748cd8SNickeau        if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
63537748cd8SNickeau// since php 5.4
63637748cd8SNickeau            $requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
63737748cd8SNickeau        } else {
63837748cd8SNickeau// DokuWiki test framework use this
63937748cd8SNickeau            $requestTime = $_SERVER['REQUEST_TIME'];
64037748cd8SNickeau        }
64137748cd8SNickeau        $keyPrefix = 'combo_';
64237748cd8SNickeau
64337748cd8SNickeau        global $ID;
64437748cd8SNickeau        return $keyPrefix . hash('crc32b', $_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT'] . $requestTime . $ID);
64537748cd8SNickeau
64637748cd8SNickeau    }
64737748cd8SNickeau
64837748cd8SNickeau    /**
6494cadd4f8SNickeau     *
650*04fd306cSNickeau     * Return the requested wiki id (known also as page id)
6514cadd4f8SNickeau     *
652*04fd306cSNickeau     * If the code is rendering a sidebar, it will not return the id of the sidebar
653*04fd306cSNickeau     * but the requested wiki id
6544cadd4f8SNickeau     *
65537748cd8SNickeau     * @return string
656*04fd306cSNickeau     * @throws ExceptionNotFound
657*04fd306cSNickeau     * @deprecated use {@link ExecutionContext::getRequestedPath()}
65837748cd8SNickeau     */
659*04fd306cSNickeau    public static function getRequestedWikiId(): string
66037748cd8SNickeau    {
661*04fd306cSNickeau
662*04fd306cSNickeau        return ExecutionContext::getActualOrCreateFromEnv()->getRequestedPath()->getWikiId();
6634cadd4f8SNickeau
66437748cd8SNickeau    }
66537748cd8SNickeau
666*04fd306cSNickeau    public static function xmlEncode($text)
667c3437056SNickeau    {
668c3437056SNickeau        /**
669c3437056SNickeau         * {@link htmlentities }
670c3437056SNickeau         */
671c3437056SNickeau        return htmlentities($text, ENT_XML1);
672c3437056SNickeau    }
673c3437056SNickeau
67437748cd8SNickeau
67537748cd8SNickeau    /**
67637748cd8SNickeau     * Add a class
67737748cd8SNickeau     * @param $classValue
67837748cd8SNickeau     * @param array $attributes
67937748cd8SNickeau     */
68037748cd8SNickeau    public
68137748cd8SNickeau    static function addClass2Attributes($classValue, array &$attributes)
68237748cd8SNickeau    {
68337748cd8SNickeau        self::addAttributeValue("class", $classValue, $attributes);
68437748cd8SNickeau    }
68537748cd8SNickeau
68637748cd8SNickeau    /**
68737748cd8SNickeau     * Add a style property to the attributes
68837748cd8SNickeau     * @param $property
68937748cd8SNickeau     * @param $value
69037748cd8SNickeau     * @param array $attributes
69182a60d03SNickeau     * @deprecated use {@link TagAttributes::addStyleDeclarationIfNotSet()} instead
69237748cd8SNickeau     */
69337748cd8SNickeau    public
69437748cd8SNickeau    static function addStyleProperty($property, $value, array &$attributes)
69537748cd8SNickeau    {
69637748cd8SNickeau        if (isset($attributes["style"])) {
69737748cd8SNickeau            $attributes["style"] .= ";$property:$value";
69837748cd8SNickeau        } else {
69937748cd8SNickeau            $attributes["style"] = "$property:$value";
70037748cd8SNickeau        }
70137748cd8SNickeau
70237748cd8SNickeau    }
70337748cd8SNickeau
70437748cd8SNickeau    /**
70537748cd8SNickeau     * Add default border attributes
70637748cd8SNickeau     * to see a border
70737748cd8SNickeau     * Doc
70837748cd8SNickeau     * https://combostrap.com/styling/color#border_color
70937748cd8SNickeau     * @param TagAttributes $tagAttributes
71037748cd8SNickeau     */
71137748cd8SNickeau    private
71237748cd8SNickeau    static function checkDefaultBorderColorAttributes(&$tagAttributes)
71337748cd8SNickeau    {
71437748cd8SNickeau        /**
71537748cd8SNickeau         * border color was set without the width
71637748cd8SNickeau         * setting the width
71737748cd8SNickeau         */
71837748cd8SNickeau        if (!(
71937748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border")
72037748cd8SNickeau            ||
72137748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border-width")
72237748cd8SNickeau        )
72337748cd8SNickeau        ) {
72482a60d03SNickeau            $tagAttributes->addStyleDeclarationIfNotSet("border-width", "1px");
72537748cd8SNickeau        }
72637748cd8SNickeau        /**
72737748cd8SNickeau         * border color was set without the style
72837748cd8SNickeau         * setting the style
72937748cd8SNickeau         */
73037748cd8SNickeau        if (!
73137748cd8SNickeau        (
73237748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border")
73337748cd8SNickeau            ||
73437748cd8SNickeau            $tagAttributes->hasStyleDeclaration("border-style")
73537748cd8SNickeau        )
73637748cd8SNickeau        ) {
73782a60d03SNickeau            $tagAttributes->addStyleDeclarationIfNotSet("border-style", "solid");
73837748cd8SNickeau
73937748cd8SNickeau        }
74037748cd8SNickeau        if (!$tagAttributes->hasStyleDeclaration("border-radius")) {
74182a60d03SNickeau            $tagAttributes->addStyleDeclarationIfNotSet("border-radius", ".25rem");
74237748cd8SNickeau        }
74337748cd8SNickeau
74437748cd8SNickeau    }
74537748cd8SNickeau
74637748cd8SNickeau    /**
74737748cd8SNickeau     * @param $match
74837748cd8SNickeau     * @return null|string - return the tag name or null if not found
74937748cd8SNickeau     */
75037748cd8SNickeau    public
751*04fd306cSNickeau    static function getMarkupTag($match): ?string
75237748cd8SNickeau    {
75337748cd8SNickeau
75437748cd8SNickeau        // Until the first >
75537748cd8SNickeau        $pos = strpos($match, ">");
756*04fd306cSNickeau        if (!$pos) {
75737748cd8SNickeau            LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_ERROR);
75837748cd8SNickeau            return null;
75937748cd8SNickeau        }
76037748cd8SNickeau        $match = substr($match, 0, $pos);
76137748cd8SNickeau
762*04fd306cSNickeau        // if this is a empty tag with / at the end we delete it
763*04fd306cSNickeau        if ($match[strlen($match) - 1] == "/") {
764*04fd306cSNickeau            $match = substr($match, 0, -1);
765*04fd306cSNickeau        }
766*04fd306cSNickeau
76737748cd8SNickeau        // Suppress the <
76837748cd8SNickeau        if ($match[0] == "<") {
76937748cd8SNickeau            $match = substr($match, 1);
770*04fd306cSNickeau            // closing tag
771*04fd306cSNickeau            if ($match[0] == "/") {
772*04fd306cSNickeau                $match = substr($match, 1);
773*04fd306cSNickeau            }
77437748cd8SNickeau        } else {
77537748cd8SNickeau            LogUtility::msg("This is not a text tag because it does not start with the character `>`");
77637748cd8SNickeau        }
77737748cd8SNickeau
77837748cd8SNickeau        // Suppress the tag name (ie until the first blank)
77937748cd8SNickeau        $spacePosition = strpos($match, " ");
78037748cd8SNickeau        if (!$spacePosition) {
78137748cd8SNickeau            // No space, meaning this is only the tag name
78237748cd8SNickeau            return $match;
78337748cd8SNickeau        } else {
78437748cd8SNickeau            return substr($match, 0, $spacePosition);
78537748cd8SNickeau        }
78637748cd8SNickeau
78737748cd8SNickeau    }
78837748cd8SNickeau
78937748cd8SNickeau
79037748cd8SNickeau    public
791*04fd306cSNickeau    static function getComponentName($tag): string
79237748cd8SNickeau    {
79337748cd8SNickeau        return strtolower(PluginUtility::PLUGIN_BASE_NAME) . "_" . $tag;
79437748cd8SNickeau    }
79537748cd8SNickeau
79637748cd8SNickeau    public
79737748cd8SNickeau    static function addAttributeValue($attribute, $value, array &$attributes)
79837748cd8SNickeau    {
79937748cd8SNickeau        if (array_key_exists($attribute, $attributes) && $attributes[$attribute] !== "") {
80037748cd8SNickeau            $attributes[$attribute] .= " {$value}";
80137748cd8SNickeau        } else {
80237748cd8SNickeau            $attributes[$attribute] = "{$value}";
80337748cd8SNickeau        }
80437748cd8SNickeau    }
80537748cd8SNickeau
80637748cd8SNickeau    /**
80737748cd8SNickeau     * Plugin Utility is available to all plugin,
80837748cd8SNickeau     * this is a convenient way to the the snippet manager
809*04fd306cSNickeau     * @return SnippetSystem
81037748cd8SNickeau     */
81137748cd8SNickeau    public
812*04fd306cSNickeau    static function getSnippetManager(): SnippetSystem
81337748cd8SNickeau    {
814*04fd306cSNickeau        return SnippetSystem::getFromContext();
81537748cd8SNickeau    }
81637748cd8SNickeau
817c3437056SNickeau
81837748cd8SNickeau    /**
81937748cd8SNickeau     * Function used in a render
82037748cd8SNickeau     * @param $data - the data from {@link PluginUtility::handleAndReturnUnmatchedData()}
82137748cd8SNickeau     * @return string
822*04fd306cSNickeau     *
823*04fd306cSNickeau     *
82437748cd8SNickeau     */
82537748cd8SNickeau    public
8264cadd4f8SNickeau    static function renderUnmatched($data): string
82737748cd8SNickeau    {
82837748cd8SNickeau        /**
82937748cd8SNickeau         * Attributes
83037748cd8SNickeau         */
831*04fd306cSNickeau        $attributes = $data[PluginUtility::ATTRIBUTES] ?? [];
83237748cd8SNickeau        $tagAttributes = TagAttributes::createFromCallStackArray($attributes);
833*04fd306cSNickeau
834*04fd306cSNickeau        /**
835*04fd306cSNickeau         * Display
836*04fd306cSNickeau         */
837*04fd306cSNickeau        $display = $tagAttributes->getValueAndRemoveIfPresent(Display::DISPLAY);
838*04fd306cSNickeau        if ($display === "none") {
839*04fd306cSNickeau            return "";
840*04fd306cSNickeau        }
841*04fd306cSNickeau
84237748cd8SNickeau        $payload = $data[self::PAYLOAD];
8431fa8c418SNickeau        $previousTagDisplayType = $data[self::CONTEXT];
8441fa8c418SNickeau        if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
845*04fd306cSNickeau            // Delete the eol at the beginning and end
846*04fd306cSNickeau            // otherwise we get a big block
84737748cd8SNickeau            $payload = ltrim($payload);
84837748cd8SNickeau        }
849*04fd306cSNickeau        return Html::encode($payload);
850*04fd306cSNickeau
85137748cd8SNickeau    }
85237748cd8SNickeau
853c3437056SNickeau    public
854c3437056SNickeau    static function renderUnmatchedXml($data)
855c3437056SNickeau    {
856c3437056SNickeau        $payload = $data[self::PAYLOAD];
857c3437056SNickeau        $previousTagDisplayType = $data[self::CONTEXT];
858c3437056SNickeau        if ($previousTagDisplayType !== Call::INLINE_DISPLAY) {
859c3437056SNickeau            $payload = ltrim($payload);
860c3437056SNickeau        }
861c3437056SNickeau        return PluginUtility::xmlEncode($payload);
862c3437056SNickeau
863c3437056SNickeau    }
864c3437056SNickeau
86537748cd8SNickeau    /**
86637748cd8SNickeau     * Function used in a handle function of a syntax plugin for
86737748cd8SNickeau     * unmatched context
86837748cd8SNickeau     * @param $tagName
86937748cd8SNickeau     * @param $match
87037748cd8SNickeau     * @param \Doku_Handler $handler
87137748cd8SNickeau     * @return array
87237748cd8SNickeau     */
87337748cd8SNickeau    public
8741fa8c418SNickeau    static function handleAndReturnUnmatchedData($tagName, $match, \Doku_Handler $handler): array
87537748cd8SNickeau    {
8761fa8c418SNickeau        $callStack = CallStack::createFromHandler($handler);
8771fa8c418SNickeau        $sibling = $callStack->previous();
87837748cd8SNickeau        $context = null;
87937748cd8SNickeau        if (!empty($sibling)) {
8801fa8c418SNickeau            $context = $sibling->getDisplay();
88137748cd8SNickeau        }
88237748cd8SNickeau        return array(
88337748cd8SNickeau            PluginUtility::STATE => DOKU_LEXER_UNMATCHED,
88437748cd8SNickeau            PluginUtility::PAYLOAD => $match,
88537748cd8SNickeau            PluginUtility::CONTEXT => $context
88637748cd8SNickeau        );
88737748cd8SNickeau    }
88837748cd8SNickeau
88937748cd8SNickeau    /**
89037748cd8SNickeau     * Utility methodPreprocess a start tag to be able to extract the name
89137748cd8SNickeau     * and the attributes easily
89237748cd8SNickeau     *
89337748cd8SNickeau     * It will delete:
89437748cd8SNickeau     *   * the characters <> and the /> if present
89537748cd8SNickeau     *   * and trim
89637748cd8SNickeau     *
89737748cd8SNickeau     * It will remain the tagname and its attributes
89837748cd8SNickeau     * @param $match
89937748cd8SNickeau     * @return false|string|null
90037748cd8SNickeau     */
90137748cd8SNickeau    private
90237748cd8SNickeau    static function getPreprocessEnterTag($match)
90337748cd8SNickeau    {
90437748cd8SNickeau// Until the first >
90537748cd8SNickeau        $pos = strpos($match, ">");
906*04fd306cSNickeau        if (!$pos) {
90737748cd8SNickeau            LogUtility::msg("The match does not contain any tag. Match: {$match}", LogUtility::LVL_MSG_WARNING);
90837748cd8SNickeau            return null;
90937748cd8SNickeau        }
91037748cd8SNickeau        $match = substr($match, 0, $pos);
91137748cd8SNickeau
91237748cd8SNickeau
91337748cd8SNickeau// Trim to start clean
91437748cd8SNickeau        $match = trim($match);
91537748cd8SNickeau
91637748cd8SNickeau// Suppress the <
91737748cd8SNickeau        if ($match[0] == "<") {
91837748cd8SNickeau            $match = substr($match, 1);
91937748cd8SNickeau        }
92037748cd8SNickeau
92137748cd8SNickeau// Suppress the / for a leaf tag
92237748cd8SNickeau        if ($match[strlen($match) - 1] == "/") {
92337748cd8SNickeau            $match = substr($match, 0, strlen($match) - 1);
92437748cd8SNickeau        }
92537748cd8SNickeau        return $match;
92637748cd8SNickeau    }
92737748cd8SNickeau
92837748cd8SNickeau    /**
92937748cd8SNickeau     * Retrieve the tag name used in the text document
93037748cd8SNickeau     * @param $match
93137748cd8SNickeau     * @return false|string|null
93237748cd8SNickeau     */
93337748cd8SNickeau    public
93437748cd8SNickeau    static function getSyntaxTagNameFromMatch($match)
93537748cd8SNickeau    {
93637748cd8SNickeau        $preprocessMatch = PluginUtility::getPreprocessEnterTag($match);
93737748cd8SNickeau
93837748cd8SNickeau// Tag name (ie until the first blank)
93937748cd8SNickeau        $spacePosition = strpos($match, " ");
94037748cd8SNickeau        if (!$spacePosition) {
94137748cd8SNickeau// No space, meaning this is only the tag name
94237748cd8SNickeau            return $preprocessMatch;
94337748cd8SNickeau        } else {
94437748cd8SNickeau            return trim(substr(0, $spacePosition));
94537748cd8SNickeau        }
94637748cd8SNickeau
94737748cd8SNickeau    }
94837748cd8SNickeau
94937748cd8SNickeau    /**
95037748cd8SNickeau     * Add an enter call to the stack
95137748cd8SNickeau     * @param \Doku_Handler $handler
95237748cd8SNickeau     * @param $tagName
95337748cd8SNickeau     * @param array $callStackArray
95437748cd8SNickeau     */
95537748cd8SNickeau    public
95637748cd8SNickeau    static function addEnterCall(
95737748cd8SNickeau        \Doku_Handler &$handler,
95837748cd8SNickeau                      $tagName,
95937748cd8SNickeau                      $callStackArray = array()
96037748cd8SNickeau    )
96137748cd8SNickeau    {
96237748cd8SNickeau        $pluginName = PluginUtility::getComponentName($tagName);
96337748cd8SNickeau        $handler->addPluginCall(
96437748cd8SNickeau            $pluginName,
96537748cd8SNickeau            $callStackArray,
96637748cd8SNickeau            DOKU_LEXER_ENTER,
96737748cd8SNickeau            null,
96837748cd8SNickeau            null
96937748cd8SNickeau        );
97037748cd8SNickeau    }
97137748cd8SNickeau
972*04fd306cSNickeau    /**
973*04fd306cSNickeau     * Add an end call dynamically
974*04fd306cSNickeau     * @param \Doku_Handler $handler
975*04fd306cSNickeau     * @param $tagName
976*04fd306cSNickeau     * @param array $callStackArray
977*04fd306cSNickeau     */
978*04fd306cSNickeau    public
979*04fd306cSNickeau    static function addEndCall(\Doku_Handler $handler, $tagName, $callStackArray = array())
980*04fd306cSNickeau    {
981*04fd306cSNickeau        $pluginName = PluginUtility::getComponentName($tagName);
982*04fd306cSNickeau        $handler->addPluginCall(
983*04fd306cSNickeau            $pluginName,
984*04fd306cSNickeau            $callStackArray,
985*04fd306cSNickeau            DOKU_LEXER_EXIT,
986*04fd306cSNickeau            null,
987*04fd306cSNickeau            null
988*04fd306cSNickeau        );
989*04fd306cSNickeau    }
99037748cd8SNickeau
99137748cd8SNickeau    /**
99237748cd8SNickeau     * General Debug
99337748cd8SNickeau     */
99437748cd8SNickeau    public
99537748cd8SNickeau    static function isDebug()
99637748cd8SNickeau    {
99737748cd8SNickeau        global $conf;
99837748cd8SNickeau        return $conf["allowdebug"] === 1;
99937748cd8SNickeau
100037748cd8SNickeau    }
100137748cd8SNickeau
100237748cd8SNickeau
100337748cd8SNickeau    /**
100437748cd8SNickeau     *
100537748cd8SNickeau     * See also dev.md file
100637748cd8SNickeau     */
100737748cd8SNickeau    public static function isDevOrTest()
100837748cd8SNickeau    {
100937748cd8SNickeau        if (self::isDev()) {
101037748cd8SNickeau            return true;
101137748cd8SNickeau        }
101237748cd8SNickeau        return self::isTest();
101337748cd8SNickeau    }
101437748cd8SNickeau
10154cadd4f8SNickeau    /**
10164cadd4f8SNickeau     * Is this a dev environment (ie laptop where the dev is working)
10174cadd4f8SNickeau     * @return bool
10184cadd4f8SNickeau     */
10194cadd4f8SNickeau    public static function isDev(): bool
102037748cd8SNickeau    {
102137748cd8SNickeau        global $_SERVER;
102237748cd8SNickeau        if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1") {
102337748cd8SNickeau            return true;
102437748cd8SNickeau        }
10254cadd4f8SNickeau        if ($_SERVER["COMPUTERNAME"] === "NICO") {
10264cadd4f8SNickeau            return true;
10274cadd4f8SNickeau        }
102837748cd8SNickeau        return false;
102937748cd8SNickeau    }
103037748cd8SNickeau
103137748cd8SNickeau    public static function getInstructions($markiCode)
103237748cd8SNickeau    {
103337748cd8SNickeau        return p_get_instructions($markiCode);
103437748cd8SNickeau    }
103537748cd8SNickeau
103637748cd8SNickeau    public static function getInstructionsWithoutRoot($markiCode)
103737748cd8SNickeau    {
1038*04fd306cSNickeau        return MarkupRenderUtility::getInstructionsAndStripPEventually($markiCode);
103937748cd8SNickeau    }
104037748cd8SNickeau
1041*04fd306cSNickeau    public static function isTest(): bool
104237748cd8SNickeau    {
104337748cd8SNickeau        return defined('DOKU_UNITTEST');
104437748cd8SNickeau    }
104537748cd8SNickeau
104637748cd8SNickeau
1047c3437056SNickeau    public static function getCacheManager(): CacheManager
104837748cd8SNickeau    {
1049*04fd306cSNickeau        return CacheManager::getFromContextExecution();
105037748cd8SNickeau    }
105137748cd8SNickeau
105237748cd8SNickeau    public static function getModeFromPluginName($name)
105337748cd8SNickeau    {
105437748cd8SNickeau        return "plugin_$name";
105537748cd8SNickeau    }
105637748cd8SNickeau
105737748cd8SNickeau    public static function isCi(): bool
105837748cd8SNickeau    {
105937748cd8SNickeau        // https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
1060*04fd306cSNickeau        // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
106137748cd8SNickeau        return getenv("CI") === "true";
106237748cd8SNickeau    }
106337748cd8SNickeau
10644cadd4f8SNickeau
10654cadd4f8SNickeau    /**
1066*04fd306cSNickeau     * @throws ExceptionCompile
10674cadd4f8SNickeau     */
10684cadd4f8SNickeau    public static function renderInstructionsToXhtml($callStackHeaderInstructions): ?string
10694cadd4f8SNickeau    {
1070*04fd306cSNickeau        return MarkupRenderUtility::renderInstructionsToXhtml($callStackHeaderInstructions);
10714cadd4f8SNickeau    }
10724cadd4f8SNickeau
10734cadd4f8SNickeau    /**
1074*04fd306cSNickeau     * @deprecated for {@link ExecutionContext::getExecutingWikiId()}
10754cadd4f8SNickeau     */
1076*04fd306cSNickeau    public static function getCurrentSlotId(): string
10774cadd4f8SNickeau    {
1078*04fd306cSNickeau        return ExecutionContext::getActualOrCreateFromEnv()->getExecutingWikiId();
10794cadd4f8SNickeau    }
10804cadd4f8SNickeau
108137748cd8SNickeau
108237748cd8SNickeau}
108337748cd8SNickeau
108437748cd8SNickeauPluginUtility::init();
1085