1<?php
2
3namespace ComboStrap;
4
5use Doku_Handler;
6use Doku_Renderer_metadata;
7use Exception;
8use syntax_plugin_combo_link;
9use syntax_plugin_combo_media;
10use syntax_plugin_combo_note;
11use syntax_plugin_combo_tooltip;
12
13class IconTag
14{
15
16    const CANONICAL = "icon";
17    public const TAG = "icon";
18
19    public static function handleSpecial(TagAttributes $tagAttributes, Doku_Handler $handler): array
20    {
21        // Get the parameters
22        $callStack = CallStack::createFromHandler($handler);
23        $parent = $callStack->moveToParent();
24        $context = "";
25        if ($parent !== false) {
26            $context = $parent->getTagName();
27            if ($context === syntax_plugin_combo_link::TAG) {
28                $context = $parent->getTagName();
29            }
30        }
31        /**
32         * Color setting should know the color of its parent
33         * For now, we don't set any color if the parent is a button, note, link
34         * As a header is not a parent, we may say that if the icon is contained, the default
35         * branding color is not set ?
36         */
37        $requestedColor = $tagAttributes->getValue(ColorRgb::COLOR);
38        if (
39            $requestedColor === null &&
40            Site::isBrandingColorInheritanceEnabled() &&
41            !in_array($context, [
42                ButtonTag::MARKUP_LONG,
43                syntax_plugin_combo_note::TAG,
44                syntax_plugin_combo_link::TAG
45            ])
46        ) {
47
48            $requestedWidth = $tagAttributes->getValue(Dimension::WIDTH_KEY, FetcherSvg::DEFAULT_ICON_LENGTH);
49
50            // By default, a character icon
51            $color = Site::getSecondaryColor();
52            try {
53                $requestedWidthInPx = ConditionalLength::createFromString($requestedWidth)->toPixelNumber();
54                if ($requestedWidthInPx > 36) {
55                    // Illustrative icon
56                    $color = Site::getPrimaryColor();
57                }
58            } catch (ExceptionBadArgument $e) {
59                LogUtility::error("The requested icon width ($requestedWidth) is not a conform width. Error: " . $e->getMessage(), self::CANONICAL, $e);
60            }
61
62            if ($color !== null) {
63                $tagAttributes->setComponentAttributeValue(ColorRgb::COLOR, $color);
64            }
65        }
66        return array(PluginUtility::CONTEXT => $context);
67    }
68
69    public static function exceptionHandling(Exception $e, $tagAttribute): string
70    {
71        $errorClass = syntax_plugin_combo_media::SVG_RENDERING_ERROR_CLASS;
72        $message = "Icon ({$tagAttribute->getValue("name")}). Error while rendering: {$e->getMessage()}";
73        $html = "<span class=\"text-danger $errorClass\">" . hsc(trim($message)) . "</span>";
74        LogUtility::warning($message, self::CANONICAL, $e);
75        return $html;
76    }
77
78    /**
79     * @param TagAttributes $tagAttributes
80     * @return string
81     */
82    public static function renderEmptyTag(TagAttributes $tagAttributes): string
83    {
84
85        try {
86            return Icon::createFromTagAttributes($tagAttributes)
87                ->toHtml();
88        } catch (\Exception $e) {
89            // catch all
90            return IconTag::exceptionHandling($e, $tagAttributes);
91        }
92
93    }
94
95    /**
96     * @param Doku_Renderer_metadata $renderer
97     * @param $tagAttribute
98     * @return void
99     */
100    public static function metadata(Doku_Renderer_metadata $renderer, $tagAttribute)
101    {
102
103        try {
104            $mediaPath = Icon::createFromTagAttributes($tagAttribute)->getFetchSvg()->getSourcePath();
105        } catch (ExceptionCompile $e) {
106            // error is already fired in the renderer
107            return;
108        }
109        if (FileSystems::exists($mediaPath)) {
110            syntax_plugin_combo_media::registerFirstImage($renderer, $mediaPath);
111        }
112    }
113
114    public static function handleEnter(TagAttributes $tagAttributes, Doku_Handler $handler): array
115    {
116        return self::handleSpecial($tagAttributes, $handler);
117    }
118
119    public static function handleExit(Doku_Handler $handler): array
120    {
121        $callStack = CallStack::createFromHandler($handler);
122        $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall();
123        return array(
124            PluginUtility::ATTRIBUTES => $openingCall->getAttributes(),
125            PluginUtility::CONTEXT => $openingCall->getContext()
126        );
127    }
128
129    public static function renderEnterTag(TagAttributes $tagAttributes): string
130    {
131        $tooltip = $tagAttributes->getValueAndRemoveIfPresent(Tooltip::TOOLTIP_ATTRIBUTE);
132        $html = "";
133        if ($tooltip !== null) {
134            /**
135             * If there is a tooltip, we need
136             * to start with a span to wrap the svg with it
137             */
138
139
140            $tooltipTag = TagAttributes::createFromCallStackArray([Tooltip::TOOLTIP_ATTRIBUTE => $tooltip])
141                ->addClassName(syntax_plugin_combo_tooltip::TOOLTIP_CLASS_INLINE_BLOCK);
142            $html .= $tooltipTag->toHtmlEnterTag("span");
143        }
144        /**
145         * Print the icon
146         */
147        $html .= IconTag::renderEmptyTag($tagAttributes);
148        /**
149         * Close the span if we are in a tooltip context
150         */
151        if ($tooltip !== null) {
152            $html .= "</span>";
153        }
154        return $html;
155    }
156}
157