xref: /plugin/combo/ComboStrap/Tag/BackgroundTag.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeaunamespace ComboStrap\Tag;
4*04fd306cSNickeau
5*04fd306cSNickeauuse ComboStrap\CallStack;
6*04fd306cSNickeauuse ComboStrap\ColorRgb;
7*04fd306cSNickeauuse ComboStrap\Dimension;
8*04fd306cSNickeauuse ComboStrap\FetcherSvg;
9*04fd306cSNickeauuse ComboStrap\IFetcherAbs;
10*04fd306cSNickeauuse ComboStrap\LinkMarkup;
11*04fd306cSNickeauuse ComboStrap\MarkupRef;
12*04fd306cSNickeauuse ComboStrap\MediaMarkup;
13*04fd306cSNickeauuse ComboStrap\PluginUtility;
14*04fd306cSNickeauuse ComboStrap\Position;
15*04fd306cSNickeauuse ComboStrap\TagAttribute\BackgroundAttribute;
16*04fd306cSNickeauuse ComboStrap\TagAttributes;
17*04fd306cSNickeauuse Doku_Renderer_metadata;
18*04fd306cSNickeauuse syntax_plugin_combo_media;
19*04fd306cSNickeau
20*04fd306cSNickeau
21*04fd306cSNickeau/**
22*04fd306cSNickeau * The {@link BackgroundTag background tag} does not render as HTML tag
23*04fd306cSNickeau * but collects data to create a {@link BackgroundAttribute}
24*04fd306cSNickeau * on the parent node
25*04fd306cSNickeau *
26*04fd306cSNickeau * Implementation of a background
27*04fd306cSNickeau *
28*04fd306cSNickeau *
29*04fd306cSNickeau * Cool calm example of moving square background
30*04fd306cSNickeau * https://codepen.io/Lewitje/pen/BNNJjo
31*04fd306cSNickeau * Particles.js
32*04fd306cSNickeau * https://codepen.io/akey96/pen/oNgeQYX
33*04fd306cSNickeau * Gradient positioning above a photo
34*04fd306cSNickeau * https://codepen.io/uzoawili/pen/GypGOy
35*04fd306cSNickeau * Fire flies
36*04fd306cSNickeau * https://codepen.io/mikegolus/pen/Jegvym
37*04fd306cSNickeau *
38*04fd306cSNickeau * z-index:100 could also be on the front
39*04fd306cSNickeau * https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_without_z-index
40*04fd306cSNickeau * https://getbootstrap.com/docs/5.0/layout/z-index/
41*04fd306cSNickeau */
42*04fd306cSNickeauclass BackgroundTag
43*04fd306cSNickeau{
44*04fd306cSNickeau
45*04fd306cSNickeau    public const MARKUP_LONG = "background";
46*04fd306cSNickeau    public const MARKUP_SHORT = "bg";
47*04fd306cSNickeau    const LOGICAL_TAG = self::MARKUP_LONG;
48*04fd306cSNickeau
49*04fd306cSNickeau    /**
50*04fd306cSNickeau     * Function used in the special and enter tag
51*04fd306cSNickeau     * @param TagAttributes $attributes
52*04fd306cSNickeau     */
53*04fd306cSNickeau    public static function handleEnterAndSpecial(TagAttributes $attributes)
54*04fd306cSNickeau    {
55*04fd306cSNickeau
56*04fd306cSNickeau        $color = $attributes->getValueAndRemoveIfPresent(ColorRgb::COLOR);
57*04fd306cSNickeau        if ($color !== null) {
58*04fd306cSNickeau            $attributes->addComponentAttributeValue(BackgroundAttribute::BACKGROUND_COLOR, $color);
59*04fd306cSNickeau        }
60*04fd306cSNickeau
61*04fd306cSNickeau    }
62*04fd306cSNickeau
63*04fd306cSNickeau    /**
64*04fd306cSNickeau     * @param CallStack $callStack
65*04fd306cSNickeau     * @param TagAttributes $backgroundAttributes
66*04fd306cSNickeau     * @param $state
67*04fd306cSNickeau     * @return array
68*04fd306cSNickeau     */
69*04fd306cSNickeau    public static function setAttributesToParentAndReturnData(CallStack $callStack, TagAttributes $backgroundAttributes, $state): array
70*04fd306cSNickeau    {
71*04fd306cSNickeau
72*04fd306cSNickeau        /**
73*04fd306cSNickeau         * The data array
74*04fd306cSNickeau         */
75*04fd306cSNickeau        $data = array();
76*04fd306cSNickeau
77*04fd306cSNickeau        /**
78*04fd306cSNickeau         * Set the backgrounds attributes
79*04fd306cSNickeau         * to the parent
80*04fd306cSNickeau         * There is two state (special and exit)
81*04fd306cSNickeau         * Go to the opening call if in exit
82*04fd306cSNickeau         */
83*04fd306cSNickeau        if ($state == DOKU_LEXER_EXIT) {
84*04fd306cSNickeau            $callStack->moveToEnd();
85*04fd306cSNickeau           $openingCall =  $callStack->moveToPreviousCorrespondingOpeningCall();
86*04fd306cSNickeau        }
87*04fd306cSNickeau        $parentCall = $callStack->moveToParent();
88*04fd306cSNickeau
89*04fd306cSNickeau        /** @noinspection PhpPointlessBooleanExpressionInConditionInspection */
90*04fd306cSNickeau        if ($parentCall != false) {
91*04fd306cSNickeau            if ($parentCall->getTagName() == BackgroundAttribute::BACKGROUNDS) {
92*04fd306cSNickeau                /**
93*04fd306cSNickeau                 * The backgrounds node
94*04fd306cSNickeau                 * (is already relative)
95*04fd306cSNickeau                 */
96*04fd306cSNickeau                $parentCall = $callStack->moveToParent();
97*04fd306cSNickeau            } else {
98*04fd306cSNickeau                /**
99*04fd306cSNickeau                 * Another parent node
100*04fd306cSNickeau                 * With a image background, the node should be relative
101*04fd306cSNickeau                 */
102*04fd306cSNickeau                if ($backgroundAttributes->hasComponentAttribute(BackgroundAttribute::BACKGROUND_IMAGE)) {
103*04fd306cSNickeau                    $parentCall->addAttribute(Position::POSITION_ATTRIBUTE, "relative");
104*04fd306cSNickeau                }
105*04fd306cSNickeau            }
106*04fd306cSNickeau            $backgrounds = $parentCall->getAttribute(BackgroundAttribute::BACKGROUNDS);
107*04fd306cSNickeau            if ($backgrounds == null) {
108*04fd306cSNickeau                $backgrounds = [$backgroundAttributes->toCallStackArray()];
109*04fd306cSNickeau            } else {
110*04fd306cSNickeau                $backgrounds[] = $backgroundAttributes->toCallStackArray();
111*04fd306cSNickeau            }
112*04fd306cSNickeau            $parentCall->addAttribute(BackgroundAttribute::BACKGROUNDS, $backgrounds);
113*04fd306cSNickeau
114*04fd306cSNickeau        } else {
115*04fd306cSNickeau            $data[PluginUtility::EXIT_MESSAGE] = "A background should have a parent";
116*04fd306cSNickeau        }
117*04fd306cSNickeau
118*04fd306cSNickeau        /**
119*04fd306cSNickeau         * Return the image data for the metadata
120*04fd306cSNickeau         * (Metadat is taken only from enter/exit)
121*04fd306cSNickeau         */
122*04fd306cSNickeau        if ($state === DOKU_LEXER_EXIT && isset($openingCall)) {
123*04fd306cSNickeau            // exit state
124*04fd306cSNickeau            $backgroundImage = $backgroundAttributes->getComponentAttributeValue(BackgroundAttribute::BACKGROUND_IMAGE);
125*04fd306cSNickeau            $openingCall->setAttribute(BackgroundAttribute::BACKGROUND_IMAGE, $backgroundImage);
126*04fd306cSNickeau        } else {
127*04fd306cSNickeau            // special state
128*04fd306cSNickeau            $data[PluginUtility::ATTRIBUTES] = $backgroundAttributes->toCallStackArray();
129*04fd306cSNickeau        }
130*04fd306cSNickeau        return $data;
131*04fd306cSNickeau
132*04fd306cSNickeau    }
133*04fd306cSNickeau
134*04fd306cSNickeau    /**
135*04fd306cSNickeau     * Print only any error
136*04fd306cSNickeau     */
137*04fd306cSNickeau    public static function renderExitSpecialHtml($data): string
138*04fd306cSNickeau    {
139*04fd306cSNickeau
140*04fd306cSNickeau        if (isset($data[PluginUtility::EXIT_MESSAGE])) {
141*04fd306cSNickeau            $class = LinkMarkup::TEXT_ERROR_CLASS;
142*04fd306cSNickeau            $error = $data[PluginUtility::EXIT_MESSAGE];
143*04fd306cSNickeau            return "<p class=\"$class\">$error</p>" . DOKU_LF;
144*04fd306cSNickeau        }
145*04fd306cSNickeau
146*04fd306cSNickeau        return "";
147*04fd306cSNickeau    }
148*04fd306cSNickeau
149*04fd306cSNickeau    public static function handleExit($handler): array
150*04fd306cSNickeau    {
151*04fd306cSNickeau        $callStack = CallStack::createFromHandler($handler);
152*04fd306cSNickeau        $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
153*04fd306cSNickeau        $backgroundAttributes = TagAttributes::createFromCallStackArray($openingTag->getAttributes())
154*04fd306cSNickeau            ->setLogicalTag(BackgroundTag::LOGICAL_TAG);
155*04fd306cSNickeau
156*04fd306cSNickeau        /**
157*04fd306cSNickeau         * if the media syntax of Combo is not used, try to retrieve the media of dokuwiki
158*04fd306cSNickeau         */
159*04fd306cSNickeau        $imageTag = [syntax_plugin_combo_media::TAG, MediaMarkup::INTERNAL_MEDIA_CALL_NAME];
160*04fd306cSNickeau
161*04fd306cSNickeau        /**
162*04fd306cSNickeau         * Collect the image if any
163*04fd306cSNickeau         */
164*04fd306cSNickeau        while ($actual = $callStack->next()) {
165*04fd306cSNickeau
166*04fd306cSNickeau            $tagName = $actual->getTagName();
167*04fd306cSNickeau            if (in_array($tagName, $imageTag)) {
168*04fd306cSNickeau                $imageAttribute = $actual->getAttributes();
169*04fd306cSNickeau                if ($tagName == syntax_plugin_combo_media::TAG) {
170*04fd306cSNickeau                    $backgroundImageAttribute = BackgroundAttribute::fromMediaToBackgroundImageStackArray($imageAttribute);
171*04fd306cSNickeau
172*04fd306cSNickeau                    /**
173*04fd306cSNickeau                     * Hack for tile svg
174*04fd306cSNickeau                     */
175*04fd306cSNickeau                    $fill = $openingTag->getAttribute(BackgroundAttribute::BACKGROUND_FILL);
176*04fd306cSNickeau                    if ($fill === FetcherSvg::TILE_TYPE) {
177*04fd306cSNickeau                        $ref = $backgroundImageAttribute[MarkupRef::REF_ATTRIBUTE];
178*04fd306cSNickeau                        if (!str_contains($ref, TagAttributes::TYPE_KEY) && str_contains($ref, "svg")) {
179*04fd306cSNickeau                            if (str_contains($ref, "?")) {
180*04fd306cSNickeau                                $ref = "$ref&type=$fill";
181*04fd306cSNickeau                            } else {
182*04fd306cSNickeau                                $ref = "$ref?type=$fill";
183*04fd306cSNickeau                            }
184*04fd306cSNickeau                        }
185*04fd306cSNickeau                        $backgroundImageAttribute[MarkupRef::REF_ATTRIBUTE] = $ref;
186*04fd306cSNickeau                    }
187*04fd306cSNickeau                } else {
188*04fd306cSNickeau                    /**
189*04fd306cSNickeau                     * As seen in {@link Doku_Handler::media()}
190*04fd306cSNickeau                     */
191*04fd306cSNickeau                    $backgroundImageAttribute = [
192*04fd306cSNickeau                        MediaMarkup::MEDIA_DOKUWIKI_TYPE => MediaMarkup::INTERNAL_MEDIA_CALL_NAME,
193*04fd306cSNickeau                        MediaMarkup::DOKUWIKI_SRC => $imageAttribute[0],
194*04fd306cSNickeau                        Dimension::WIDTH_KEY => $imageAttribute[3],
195*04fd306cSNickeau                        Dimension::HEIGHT_KEY => $imageAttribute[4],
196*04fd306cSNickeau                        IFetcherAbs::CACHE_KEY => $imageAttribute[5]
197*04fd306cSNickeau                    ];
198*04fd306cSNickeau                }
199*04fd306cSNickeau                $backgroundAttributes->addComponentAttributeValue(BackgroundAttribute::BACKGROUND_IMAGE, $backgroundImageAttribute);
200*04fd306cSNickeau                $callStack->deleteActualCallAndPrevious();
201*04fd306cSNickeau            }
202*04fd306cSNickeau        }
203*04fd306cSNickeau        return BackgroundTag::setAttributesToParentAndReturnData($callStack, $backgroundAttributes, DOKU_LEXER_EXIT);
204*04fd306cSNickeau    }
205*04fd306cSNickeau
206*04fd306cSNickeau    public static function renderEnterTag(): string
207*04fd306cSNickeau    {
208*04fd306cSNickeau        /**
209*04fd306cSNickeau         * background is printed via the {@link BackgroundAttribute::processBackgroundAttributes()}
210*04fd306cSNickeau         */
211*04fd306cSNickeau        return "";
212*04fd306cSNickeau    }
213*04fd306cSNickeau
214*04fd306cSNickeau    public static function renderMeta(array $data, Doku_Renderer_metadata $renderer)
215*04fd306cSNickeau    {
216*04fd306cSNickeau
217*04fd306cSNickeau        $attributes = $data[PluginUtility::ATTRIBUTES];
218*04fd306cSNickeau        if (isset($attributes[BackgroundAttribute::BACKGROUND_IMAGE])) {
219*04fd306cSNickeau            $image = $attributes[BackgroundAttribute::BACKGROUND_IMAGE];
220*04fd306cSNickeau            syntax_plugin_combo_media::registerImageMeta($image, $renderer);
221*04fd306cSNickeau        }
222*04fd306cSNickeau
223*04fd306cSNickeau    }
224*04fd306cSNickeau}
225