1<?php
2
3namespace ComboStrap;
4
5use Doku_Form;
6use dokuwiki\Form\Form;
7use dokuwiki\Form\InputElement;
8
9class IdentityFormsHelper
10{
11
12    const CANONICAL = "identity-forms-helper";
13
14    public static function toBoostrapInputElements(Form $form, string $formName)
15    {
16        for ($i = 0; $i < $form->elementCount(); $i++) {
17            $inputElement = $form->getElementAt($i);
18            if ($inputElement instanceof InputElement) {
19                $i = self::toBootStrapInputElementAndGetNewLoopingPosition($form, $i, $formName);
20            }
21        }
22    }
23
24    /**
25     * Tansfrom the Dokuwiki {@link InputElement} into a Boostrap layout
26     * @param Form $form - the form
27     * @param int $elementPosition - the position of the element (that's how works {@link Form}
28     * @param string $formName - the form name to create unique id (as the profile page has 2 forms)
29     * @return int - the new position that should be used in a loop (the remove, add action reset the whole array indexes)
30     */
31    public static function toBootStrapInputElementAndGetNewLoopingPosition(Form $form, int $elementPosition, string $formName): int
32    {
33        $inputElement = $form->getElementAt($elementPosition);
34        if (!($inputElement instanceof InputElement)) {
35            LogUtility::internalError("The element should be an input element");
36            return $elementPosition;
37        }
38        $inputType = $inputElement->getType();
39        $inputName = $inputElement->attr("name");
40        $labelObject = $inputElement->getLabel();
41        $label = "";
42        if ($labelObject !== null) {
43            $label = $labelObject->val();
44        }
45        $inputId = $inputElement->attr("id");
46        if (empty($inputId)) {
47            $inputId = "user__$formName-input-$elementPosition";
48            $inputElement->id($inputId);
49        }
50        $placeholder = $inputElement->attr("placeholder");
51        if (empty($placeholder) && !empty($label)) {
52            $inputElement->attr("placeholder", $label);
53        }
54        $newInputField = new InputElement($inputType, $inputName);
55        foreach ($inputElement->attrs() as $keyAttr => $valueAttr) {
56            $newInputField->attr($keyAttr, $valueAttr);
57        }
58        $newInputField->addClass("form-control");
59        $form->replaceElement($newInputField, $elementPosition);
60        $form->addHTML('<div class="form-control-row">', $elementPosition);
61        $form->addHTML("<label for=\"$inputId\" class=\"form-label\">$label</label>", $elementPosition + 1);
62        $form->addHTML('</div>', $elementPosition + 3);
63        return $elementPosition + 3;
64
65    }
66
67    /**
68     * @param Doku_Form|Form $form
69     * @param string $classPrefix
70     * @param bool $includeLogo
71     * @return string
72     */
73    public static function getHeaderHTML($form, string $classPrefix, bool $includeLogo = true): string
74    {
75        $class = get_class($form);
76        switch ($class) {
77            case Doku_Form::class:
78                /**
79                 * Old one
80                 * @var Doku_Form $form
81                 */
82                $legend = $form->_content[0]["_legend"];
83                if (!isset($legend)) {
84                    return "";
85                }
86
87                $title = $legend;
88                break;
89            case Form::class;
90                /**
91                 * New One
92                 * @var Form $form
93                 */
94                $pos = $form->findPositionByType("fieldsetopen");
95                if ($pos === false) {
96                    return "";
97                }
98
99                $title = $form->getElementAt($pos)->val();
100                break;
101            default:
102                LogUtility::msg("Internal Error: Unknown form class " . $class);
103                return "";
104        }
105
106        /**
107         * Logo
108         */
109        $logoHtmlImgTag = "";
110        if (
111            $includeLogo === true
112        ) {
113            try {
114                $logoPath = self::getLogoPath();
115            } catch (ExceptionNotFound $e) {
116                $logoPath = WikiPath::createComboResource(":images:home.svg");
117            }
118            $logoHtmlImgTag = self::getLogoHtml($logoPath);
119        }
120        /**
121         * Don't use `header` in place of
122         * div because this is a HTML5 tag
123         *
124         * On php 5.6, the php test library method {@link \phpQueryObject::htmlOuter()}
125         * add the below meta tag
126         * <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
127         *
128         */
129        return <<<EOF
130<div class="$classPrefix-header">
131    $logoHtmlImgTag
132    <h1>$title</h1>
133</div>
134EOF;
135    }
136
137    public static function addPrimaryColorCssRuleIfSet(?string $content): ?string
138    {
139        if ($content === null) {
140            return null;
141        }
142        $primaryColor = Site::getPrimaryColor();
143        if ($primaryColor !== null) {
144            $identityClass = Identity::FORM_IDENTITY_CLASS;
145            $cssFormControl = BrandingColors::getCssFormControlFocusColor($primaryColor);
146            $content .= <<<EOF
147.$identityClass button[type="submit"]{
148   background-color: {$primaryColor->toCssValue()};
149   border-color: {$primaryColor->toCssValue()};
150}
151$cssFormControl
152EOF;
153        }
154        return $content;
155    }
156
157    public static function getHtmlStyleTag(string $componentId): string
158    {
159        $loginCss = Snippet::createCssSnippetFromComponentId($componentId);
160        try {
161            $content = $loginCss->getInternalInlineAndFileContent();
162        } catch (ExceptionNotFound $e) {
163            LogUtility::internalError("The style content should be not null", Identity::CANONICAL);
164            $content = "";
165        }
166        $content = IdentityFormsHelper::addPrimaryColorCssRuleIfSet($content);
167        $class = $loginCss->getClass();
168        return <<<EOF
169<style class="$class">
170$content
171</style>
172EOF;
173
174    }
175
176    public static function addIdentityClass(&$class, string $formClass)
177    {
178
179        $formClass = Identity::FORM_IDENTITY_CLASS . " " . $formClass;
180        if (isset($class)) {
181            $class .= " " . $formClass;
182        } else {
183            $class = $formClass;
184        }
185
186    }
187
188    public static function deleteFieldSetAndBrFromForm(Form $form)
189    {
190        foreach (Identity::FIELD_SET_TO_DELETE as $type) {
191            $field = $form->findPositionByType($type);
192            if ($field !== false) {
193                $form->removeElement($field);
194            }
195        }
196
197        for ($i = 0; $i < $form->elementCount(); $i++) {
198            $fieldBr = $form->getElementAt($i);
199            if (trim($fieldBr->val()) === "<br>") {
200                $form->removeElement($i);
201                // removing the element, rearrange the array and shift the array index of minus 1
202                // to delete two br one after the other, we need to readjust the counter
203                $i--;
204            }
205        }
206    }
207
208    public static function toBootStrapSubmitButton(Form $form)
209    {
210        $submitButtonPosition = $form->findPositionByAttribute("type", "submit");
211        if ($submitButtonPosition === false) {
212            LogUtility::msg("Internal error: No submit button found");
213            return;
214        }
215        $form->getElementAt($submitButtonPosition)
216            ->addClass("btn")
217            ->addClass("btn-primary");
218    }
219
220    public static function toBootstrapResetButton(Form $form)
221    {
222        $resetButtonPosition = $form->findPositionByAttribute("type", "reset");
223        if ($resetButtonPosition === false) {
224            LogUtility::msg("Internal error: No submit button found");
225            return;
226        }
227        $form->getElementAt($resetButtonPosition)
228            ->addClass("btn")
229            ->addClass("btn-secondary");
230    }
231
232    /**
233     */
234    public static function getLogoHtml(WikiPath $logoImagePath): string
235    {
236
237        $tagAttributes = TagAttributes::createEmpty("identity")
238            ->addClassName("logo");
239
240        try {
241            $imageFetcher = IFetcherLocalImage::createImageFetchFromPath($logoImagePath)
242                ->setRequestedHeight(72)
243                ->setRequestedWidth(72);
244
245            if ($imageFetcher instanceof FetcherSvg) {
246                $imageFetcher->setRequestedType(FetcherSvg::ICON_TYPE);
247                $primaryColor = Site::getPrimaryColor();
248                if ($primaryColor !== null) {
249                    $imageFetcher->setRequestedColor($primaryColor);
250                }
251            }
252            $brand = Brand::create(Brand::CURRENT_BRAND);
253
254            $mediaMarkup = MediaMarkup::createFromFetcher($imageFetcher)
255                ->setLazyLoad(false)
256                ->setLinking(MediaMarkup::LINKING_NOLINK_VALUE)
257                ->buildFromTagAttributes($tagAttributes)
258                ->toHtml();
259            return <<<EOF
260<a href="{$brand->getBrandUrl()}" title="{$brand->getTitle()}">$mediaMarkup</a>
261EOF;
262        } catch (\Exception $e) {
263            LogUtility::error("Error while creating the logo html", self::CANONICAL, $e);
264            return "";
265        }
266
267    }
268
269    /**
270     * @throws ExceptionNotFound
271     */
272    public static function getLogoPath(): WikiPath
273    {
274        $logoImagesPath = Site::getLogoImagesAsPath();
275        foreach ($logoImagesPath as $logoImagePath) {
276
277            if (!Identity::isReader($logoImagePath->getWikiId())) {
278                continue;
279            }
280            return $logoImagePath;
281
282        }
283        throw new ExceptionNotFound("No logo image could be found");
284    }
285}
286