1<?php
2
3use ComboStrap\Bootstrap;
4use ComboStrap\Identity;
5use ComboStrap\IdentityFormsHelper;
6use ComboStrap\LogUtility;
7use ComboStrap\PluginUtility;
8use ComboStrap\Site;
9use ComboStrap\SiteConfig;
10use dokuwiki\Form\Form;
11use dokuwiki\Form\InputElement;
12
13if (!defined('DOKU_INC')) die();
14require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
15
16/**
17 *
18 */
19class action_plugin_combo_profile extends DokuWiki_Action_Plugin
20{
21
22    const CANONICAL = Identity::CANONICAL;
23    const TAG_UPDATE = "profile-update"; // form 1
24    const TAG_DELETE = "profile-delete"; // form 2
25    const FORM_PROFILE_UPDATE_CLASS = "form-" . self::TAG_UPDATE;
26    const FORM_PROFILE_DELETE_CLASS = "form-" . self::TAG_DELETE;
27    const CONF_ENABLE_PROFILE_UPDATE_FORM = "enableProfileUpdateForm";
28    const CONF_ENABLE_PROFILE_DELETE_FORM = "enableProfileDeleteForm";
29
30
31    function register(Doku_Event_Handler $controller)
32    {
33        /**
34         * To modify the profile update form and add class
35         *
36         * Deprecated object passed by the event but still in use
37         * https://www.dokuwiki.org/devel:event:html_updateprofileform_output
38         *
39         * Event using the new object but not found anywhere
40         * https://www.dokuwiki.org/devel:event:form_updateprofile_output
41         */
42        if (SiteConfig::getConfValue(self::CONF_ENABLE_PROFILE_UPDATE_FORM, 1)) {
43            $controller->register_hook('HTML_UPDATEPROFILEFORM_OUTPUT', 'BEFORE', $this, 'handle_profile_update', array());
44            $controller->register_hook('FORM_UPDATEPROFILE_OUTPUT', 'BEFORE', $this, 'handle_profile_update', array());
45        }
46
47        /**
48         * To modify the register form and add class
49         *
50         * Deprecated object passed by the event but still in use
51         * https://www.dokuwiki.org/devel:event:html_profiledeleteform_output
52         *
53         * Event using the new object but not found anywhere
54         * https://www.dokuwiki.org/devel:event:form_profiledelete_output
55         */
56        if (SiteConfig::getConfValue(self::CONF_ENABLE_PROFILE_DELETE_FORM, 1)) {
57            $controller->register_hook('HTML_PROFILEDELETEFORM_OUTPUT', 'BEFORE', $this, 'handle_profile_delete', array());
58            $controller->register_hook('FORM_PROFILEDELETE_OUTPUT', 'BEFORE', $this, 'handle_profile_delete', array());
59        }
60
61
62    }
63
64    function handle_profile_update(&$event, $param)
65    {
66
67        $form = &$event->data;
68        $class = get_class($form);
69        switch ($class) {
70            case "Doku_Form":
71                /**
72                 * Old one
73                 * @var Doku_Form $form
74                 */
75                self::updateDokuFormProfileUpdate($form);
76                return;
77            case "dokuwiki\Form\Form";
78                /**
79                 * New One
80                 * @var Form $form
81                 */
82                self::updateNewFormProfileUpdate($form);
83                return;
84        }
85
86
87    }
88
89    public function handle_profile_delete($event, $param)
90    {
91
92        $form = &$event->data;
93        $class = get_class($form);
94        switch ($class) {
95            case Doku_Form::class:
96                /**
97                 * Old one
98                 * @var Doku_Form $form
99                 */
100                self::updateDokuFormProfileDelete($form);
101                return;
102            case dokuwiki\Form\Form::class;
103                /**
104                 * New One
105                 * @var Form $form
106                 */
107                self::updateNewFormProfileDelete($form);
108                return;
109        }
110
111
112    }
113
114    private static function updateNewFormProfileDelete(Form &$form)
115    {
116        /**
117         * The Login page is an admin page created via buffer
118         * We print before the forms
119         * to avoid a FOUC
120         */
121        print IdentityFormsHelper::getHtmlStyleTag(self::TAG_DELETE);
122
123
124        $deleteFormClassSuffix = self::FORM_PROFILE_DELETE_CLASS;
125        $form->addClass(Identity::FORM_IDENTITY_CLASS . " " . $deleteFormClassSuffix);
126
127        /**
128         * Heading
129         */
130        $headerHTML = IdentityFormsHelper::getHeaderHTML($form, $deleteFormClassSuffix, false);
131        if ($headerHTML != "") {
132            $form->addHTML($headerHTML, 1);
133        }
134
135        IdentityFormsHelper::deleteFieldSetAndBrFromForm($form);
136
137
138        /**
139         * Submit button
140         */
141        $submitButtonPosition = $form->findPositionByAttribute("type", "submit");
142        if ($submitButtonPosition === false) {
143            LogUtility::msg("Internal error: No submit button found");
144            return;
145        }
146        $form->getElementAt($submitButtonPosition)
147            ->addClass("btn")
148            ->addClass("btn-primary");
149
150        /**
151         * Password Input
152         */
153
154        $passwordElementPosition = $form->findPositionByAttribute("type", "password");
155        if ($passwordElementPosition === false) {
156            LogUtility::msg("Internal error: No password found");
157            return;
158        }
159
160        IdentityFormsHelper::toBootStrapInputElementAndGetNewLoopingPosition($form, $passwordElementPosition, $deleteFormClassSuffix);
161
162
163    }
164
165    private static function updateDokuFormProfileDelete(Doku_Form &$form)
166    {
167
168        /**
169         * The profile page is created via buffer
170         * We print before the forms to avoid a FOUC
171         */
172        print IdentityFormsHelper::getHtmlStyleTag(self::TAG_DELETE);
173
174
175        $class = &$form->params["class"];
176        IdentityFormsHelper::addIdentityClass($class, self::FORM_PROFILE_DELETE_CLASS);
177        $newFormContent = [];
178
179        /**
180         * Header (Logo / Title)
181         */
182        $newFormContent[] = IdentityFormsHelper::getHeaderHTML($form, self::FORM_PROFILE_DELETE_CLASS, false);
183
184        /**
185         * Field
186         */
187        foreach ($form->_content as $field) {
188            if (!is_array($field)) {
189                continue;
190            }
191            $fieldName = $field["name"];
192            if ($fieldName == null) {
193                // this is not an input field
194                if ($field["type"] == "submit") {
195                    /**
196                     * This is important to keep the submit element intact
197                     * for forms integration such as captcha
198                     * They search the submit button to insert before it
199                     */
200                    $classes = "btn btn-primary btn-block";
201                    if (isset($field["class"])) {
202                        $field["class"] = $field["class"] . " " . $classes;
203                    } else {
204                        $field["class"] = $classes;
205                    }
206                    $newFormContent[] = $field;
207                }
208                continue;
209            }
210            switch ($fieldName) {
211                case "oldpass":
212                    $passwordText = $field["_text"];
213                    $passwordFieldHTML = <<<EOF
214<div>
215    <input type="password" class="form-control" placeholder="$passwordText" required="required" name="$fieldName">
216</div>
217EOF;
218                    $newFormContent[] = $passwordFieldHTML;
219                    break;
220                case "confirm_delete":
221                    $confirmText = $field["_text"];
222                    $ConfirmValue = $field["value"];
223                    $rememberMeHtml = <<<EOF
224<div class="checkbox rememberMe">
225    <label><input type="checkbox" name="$fieldName" value="$ConfirmValue" required="required"> $confirmText</label>
226</div>
227EOF;
228                    $newFormContent[] = $rememberMeHtml;
229                    break;
230                default:
231                    $tag = self::TAG_DELETE;
232                    LogUtility::msg("The $tag field name ($fieldName) is unknown", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
233
234
235            }
236        }
237        $form->_content = $newFormContent;
238
239    }
240
241    private static function updateNewFormProfileUpdate(Form &$form)
242    {
243        /**
244         * The Login page is an admin page created via buffer
245         * We print before the forms
246         * to avoid a FOUC
247         */
248        print IdentityFormsHelper::getHtmlStyleTag(self::TAG_UPDATE);
249
250
251        $form->addClass(Identity::FORM_IDENTITY_CLASS . " " . self::FORM_PROFILE_UPDATE_CLASS);
252
253
254        /**
255         * Heading
256         */
257        $headerHTML = IdentityFormsHelper::getHeaderHTML($form, self::FORM_PROFILE_UPDATE_CLASS);
258        if ($headerHTML != "") {
259            $form->addHTML($headerHTML, 1);
260        }
261
262        IdentityFormsHelper::deleteFieldSetAndBrFromForm($form);
263
264        /**
265         * Submit and reset button
266         */
267        IdentityFormsHelper::toBootStrapSubmitButton($form);
268        IdentityFormsHelper::toBootstrapResetButton($form);
269
270        /**
271         * Input elements
272         */
273        IdentityFormsHelper::toBoostrapInputElements($form, self::FORM_PROFILE_UPDATE_CLASS);
274
275    }
276
277
278    private static function updateDokuFormProfileUpdate(Doku_Form &$form)
279    {
280
281        /**
282         * The profile page is created via buffer
283         * We print before the forms to avoid a FOUC
284         */
285        print IdentityFormsHelper::getHtmlStyleTag(self::TAG_UPDATE);
286
287
288        $class = &$form->params["class"];
289        IdentityFormsHelper::addIdentityClass($class, self::FORM_PROFILE_UPDATE_CLASS);
290        $newFormContent = [];
291
292        /**
293         * Header (Logo / Title)
294         */
295        $newFormContent[] = IdentityFormsHelper::getHeaderHTML($form, self::FORM_PROFILE_UPDATE_CLASS);
296
297
298        /**
299         * Form Attributes
300         * https://getbootstrap.com/docs/5.0/forms/layout/#horizontal-form
301         */
302        $rowClass = "row";
303        if (Bootstrap::getBootStrapMajorVersion() == Bootstrap::BootStrapFourMajorVersion) {
304            $rowClass .= " form-group";
305        }
306        $firstColWeight = 5;
307        $secondColWeight = 12 - $firstColWeight;
308
309
310        /**
311         * Replace the field
312         *
313         * The password text localized by lang is shared
314         * between the password and the password check field
315         */
316        $passwordText = "Password";
317        foreach ($form->_content as $field) {
318            if (!is_array($field)) {
319                continue;
320            }
321            $fieldName = $field["name"];
322            if ($fieldName == null) {
323                // this is not an input field
324                switch ($field["type"]) {
325                    case "submit":
326                        /**
327                         * This is important to keep the submit element intact
328                         * for forms integration such as captcha
329                         * The search the submit button to insert before it
330                         */
331                        $classes = "btn btn-primary";
332                        if (isset($field["class"])) {
333                            $field["class"] = $field["class"] . " " . $classes;
334                        } else {
335                            $field["class"] = $classes;
336                        }
337                        $field["tabindex"] = "6";
338                        $newFormContent[] = $field;
339                        break;
340                    case "reset":
341                        $classes = "btn btn-secondary";
342                        if (isset($field["class"])) {
343                            $field["class"] = $field["class"] . " " . $classes;
344                        } else {
345                            $field["class"] = $classes;
346                        }
347                        $field["tabindex"] = "7";
348                        $newFormContent[] = $field;
349                        break;
350                }
351                continue;
352            }
353            switch ($fieldName) {
354                case "login":
355                    $loginText = $field["_text"];
356                    $loginValue = $field["value"];
357                    $loginHTML = <<<EOF
358<div class="$rowClass">
359    <label for="inputUserName" class="col-sm-$firstColWeight col-form-label">$loginText</label>
360    <div class="col-sm-$secondColWeight">
361      <input type="text" class="form-control" id="inputUserName" placeholder="Username" name="$fieldName" value="$loginValue" disabled>
362    </div>
363</div>
364EOF;
365                    $newFormContent[] = $loginHTML;
366                    break;
367                case "fullname":
368                    $fullNameText = $field["_text"];
369                    $fullNameValue = $field["value"];
370                    $fullNameHtml = <<<EOF
371<div class="$rowClass">
372    <label for="inputRealName" class="col-sm-$firstColWeight col-form-label">$fullNameText</label>
373    <div class="col-sm-$secondColWeight">
374      <input type="text" class="form-control" id="inputRealName" placeholder="$fullNameText" tabindex="1" name="$fieldName" value="$fullNameValue" required="required">
375    </div>
376</div>
377EOF;
378                    $newFormContent[] = $fullNameHtml;
379                    break;
380                case "email":
381                    $emailText = $field["_text"];
382                    $emailValue = $field["value"];
383                    $emailHTML = <<<EOF
384<div class="$rowClass">
385    <label for="inputEmail" class="col-sm-$firstColWeight col-form-label">$emailText</label>
386    <div class="col-sm-$secondColWeight">
387      <input type="email" class="form-control" id="inputEmail" placeholder="name@example.com" tabindex="2" name="$fieldName" value="$emailValue" required="required">
388    </div>
389</div>
390EOF;
391                    $newFormContent[] = $emailHTML;
392                    break;
393                case "newpass":
394                    $passwordText = $field["_text"];
395                    $passwordHtml = <<<EOF
396<div class="$rowClass">
397    <label for="inputPassword" class="col-sm-$firstColWeight col-form-label">$passwordText</label>
398    <div class="col-sm-$secondColWeight">
399      <input type="password" class="form-control" id="inputPassword" placeholder="$passwordText" tabindex="3" name="$fieldName">
400    </div>
401</div>
402EOF;
403                    $newFormContent[] = $passwordHtml;
404                    break;
405                case "passchk":
406                    $passwordCheckText = $field["_text"];
407                    $passwordCheckHtml = <<<EOF
408<div class="$rowClass">
409    <label for="inputPasswordCheck" class="col-sm-$firstColWeight col-form-label">$passwordCheckText</label>
410    <div class="col-sm-$secondColWeight">
411      <input type="password" class="form-control" id="inputPasswordCheck" placeholder="$passwordText" tabindex="4" name="$fieldName">
412    </div>
413</div>
414EOF;
415                    $newFormContent[] = $passwordCheckHtml;
416                    break;
417                case "oldpass":
418                    $passwordCheckText = $field["_text"];
419                    $passwordCheckHtml = <<<EOF
420<div class="$rowClass">
421    <label for="inputPasswordCheck" class="col-sm-$firstColWeight col-form-label">$passwordCheckText</label>
422    <div class="col-sm-$secondColWeight">
423      <input type="password" class="form-control" id="inputPasswordCheck" placeholder="$passwordCheckText" tabindex="5" name="$fieldName" required="required">
424    </div>
425</div>
426EOF;
427                    $newFormContent[] = $passwordCheckHtml;
428                    break;
429
430
431                default:
432                    $tag = self::TAG_UPDATE;
433                    LogUtility::msg("The $tag field name ($fieldName) is unknown", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
434
435            }
436        }
437
438
439        /**
440         * Update
441         */
442        $form->_content = $newFormContent;
443
444    }
445
446}
447
448