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