1<?php 2/** 3 * Action Component 4 * Add a button in the edit toolbar 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Nicolas GERARD 8 */ 9 10use ComboStrap\BrandColors; 11use ComboStrap\Identity; 12use ComboStrap\LogUtility; 13use ComboStrap\PluginUtility; 14use dokuwiki\Form\Form; 15use dokuwiki\Form\InputElement; 16use dokuwiki\Menu\Item\Login; 17 18if (!defined('DOKU_INC')) die(); 19require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 20 21/** 22 * Class action_plugin_combo_login 23 * 24 * $conf['rememberme'] 25 */ 26class action_plugin_combo_login extends DokuWiki_Action_Plugin 27{ 28 29 30 const CANONICAL = Identity::CANONICAL; 31 const TAG = "login"; 32 const FORM_LOGIN_CLASS = "form-" . self::TAG; 33 34 const CONF_ENABLE_LOGIN_FORM = "enableLoginForm"; 35 36 37 /** 38 * Update the old form 39 * @param Doku_Form $form 40 * @return void 41 */ 42 private static function updateDokuFormLogin(Doku_Form &$form) 43 { 44 /** 45 * The Login page is an admin page created via buffer 46 * We print before the forms 47 * to avoid a FOUC 48 */ 49 print Identity::getHtmlStyleTag(self::TAG); 50 51 52 $form->params["class"] = Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS; 53 54 55 /** 56 * Heading 57 */ 58 $newFormContent[] = Identity::getHeaderHTML($form, self::FORM_LOGIN_CLASS); 59 60 /** 61 * Field 62 */ 63 foreach ($form->_content as $field) { 64 if (!is_array($field)) { 65 continue; 66 } 67 $fieldName = $field["name"]; 68 if ($fieldName == null) { 69 // this is not an input field 70 if ($field["type"] == "submit") { 71 /** 72 * This is important to keep the submit element intact 73 * for forms integration such as captcha 74 * They search the submit button to insert before it 75 */ 76 $classes = "btn btn-primary btn-block"; 77 if (isset($field["class"])) { 78 $field["class"] = $field["class"] . " " . $classes; 79 } else { 80 $field["class"] = $classes; 81 } 82 $newFormContent[] = $field; 83 } 84 continue; 85 } 86 switch ($fieldName) { 87 case "u": 88 $loginText = $field["_text"]; 89 $loginValue = $field["value"]; 90 $loginHTMLField = <<<EOF 91<div class="form-floating"> 92 <input type="text" id="inputUserName" class="form-control" placeholder="$loginText" required="required" autofocus="" name="u" value="$loginValue"> 93 <label for="inputUserName">$loginText</label> 94</div> 95EOF; 96 $newFormContent[] = $loginHTMLField; 97 break; 98 case "p": 99 $passwordText = $field["_text"]; 100 $passwordFieldHTML = <<<EOF 101<div class="form-floating"> 102 <input type="password" id="inputPassword" class="form-control" placeholder="$passwordText" required="required" name="p"> 103 <label for="inputPassword">$passwordText</label> 104</div> 105EOF; 106 $newFormContent[] = $passwordFieldHTML; 107 break; 108 case "r": 109 $rememberText = $field["_text"]; 110 $rememberValue = $field["value"]; 111 $rememberMeHtml = <<<EOF 112<div class="checkbox rememberMe"> 113 <label><input type="checkbox" id="remember__me" name="r" value="$rememberValue"> $rememberText</label> 114</div> 115EOF; 116 $newFormContent[] = $rememberMeHtml; 117 break; 118 default: 119 $tag = self::TAG; 120 LogUtility::msg("The $tag field name ($fieldName) is unknown", LogUtility::LVL_MSG_ERROR, self::CANONICAL); 121 122 123 } 124 } 125 126 127 $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph(); 128 if (!empty($registerHtml)) { 129 $newFormContent[] = $registerHtml; 130 } 131 $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage(); 132 if (!empty($resendPwdHtml)) { 133 $newFormContent[] = $resendPwdHtml; 134 } 135 136 /** 137 * Set the new in place of the old one 138 */ 139 $form->_content = $newFormContent; 140 } 141 142 143 function register(Doku_Event_Handler $controller) 144 { 145 /** 146 * To modify the form and add class 147 * 148 * The event HTML_LOGINFORM_OUTPUT is deprecated 149 * for FORM_LOGIN_OUTPUT 150 * 151 * The difference is on the type of object that we got in the event 152 */ 153 if (PluginUtility::getConfValue(self::CONF_ENABLE_LOGIN_FORM, 1)) { 154 155 /** 156 * Old event: Deprecated object passed by the event but still in use 157 * https://www.dokuwiki.org/devel:event:html_loginform_output 158 */ 159 $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handle_login_html', array()); 160 161 /** 162 * New Event: using the new object but only in use in 163 * the {@link https://codesearch.dokuwiki.org/xref/dokuwiki/lib/plugins/authad/action.php authad plugin} 164 * (ie login against active directory) 165 * 166 * https://www.dokuwiki.org/devel:event:form_login_output 167 */ 168 $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handle_login_html', array()); 169 } 170 171 172 } 173 174 function handle_login_html(&$event, $param): void 175 { 176 177 $form = &$event->data; 178 $class = get_class($form); 179 switch ($class) { 180 case Doku_Form::class: 181 /** 182 * Old one 183 * @var Doku_Form $form 184 */ 185 self::updateDokuFormLogin($form); 186 return; 187 case dokuwiki\Form\Form::class; 188 /** 189 * New One 190 * @var Form $form 191 */ 192 self::updateNewFormLogin($form); 193 return; 194 } 195 196 197 } 198 199 200 /** 201 * Login 202 * @return string 203 */ 204 public static function getLoginParagraphWithLinkToFormPage(): string 205 { 206 207 $loginPwLink = (new Login())->asHtmlLink('', false); 208 global $lang; 209 $loginText = $lang['btn_login']; 210 return <<<EOF 211<p class="login">$loginText ? : $loginPwLink</p> 212EOF; 213 214 } 215 216 /** 217 * https://www.dokuwiki.org/devel:form - documentation 218 * @param Form $form 219 * @return void 220 */ 221 private static function updateNewFormLogin(Form &$form) 222 { 223 /** 224 * The Login page is an admin page created via buffer 225 * We print before the forms 226 * to avoid a FOUC 227 */ 228 print Identity::getHtmlStyleTag(self::TAG); 229 230 231 $form->addClass(Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS); 232 233 /** 234 * Heading 235 */ 236 $headerHTML = Identity::getHeaderHTML($form, self::FORM_LOGIN_CLASS); 237 if ($headerHTML != "") { 238 $form->addHTML($headerHTML, 1); 239 } 240 241 $brPositionElement = [4, 5]; // 4 and 6 but when you delete 4, it's on 5 242 foreach ($brPositionElement as $brPosition) { 243 $fieldBr = $form->getElementAt($brPosition); 244 if ($fieldBr->val() === "<br>\n") { 245 $form->removeElement($brPosition); 246 } else { 247 LogUtility::msg("Internal: the login br $brPosition element was not found and not deleted"); 248 } 249 } 250 251 /** 252 * Fieldset delete 253 */ 254 $elementsTypeToDelete = ["fieldsetopen", "fieldsetclose"]; 255 foreach ($elementsTypeToDelete as $type) { 256 $field = $form->findPositionByType($type); 257 if ($field != false) { 258 $form->removeElement($field); 259 } 260 } 261 262 /** 263 * Field 264 */ 265 $submitButtonPosition = $form->findPositionByAttribute("type", "submit"); 266 if ($submitButtonPosition == false) { 267 LogUtility::msg("Internal error: No submit button found"); 268 return; 269 } 270 /** 271 * This is important to keep the submit element intact 272 * for forms integration such as captcha 273 * They search the submit button to insert before it 274 */ 275 $form->getElementAt($submitButtonPosition) 276 ->addClass("btn") 277 ->addClass("btn-primary") 278 ->addClass("btn-block") 279 ->addClass("mb-2"); 280 281 $userPosition = $form->findPositionByAttribute("name", "u"); 282 if ($userPosition == false) { 283 LogUtility::msg("Internal error: No user field found"); 284 return; 285 } 286 /** 287 * @var InputElement $userField 288 */ 289 $userField = $form->getElementAt($userPosition); 290 $newUserField = new InputElement($userField->getType(), "u"); 291 $loginText = $userField->getLabel()->val(); 292 foreach ($userField->attrs() as $keyAttr => $valueAttr) { 293 $newUserField->attr($keyAttr, $valueAttr); 294 } 295 $newUserField->addClass("form-control"); 296 $newUserField->attr("placeholder", $loginText); 297 $newUserField->attr("required", "required"); 298 $newUserField->attr("autofocus", ""); 299 $userFieldId = $userField->attr("id"); 300 301 $form->replaceElement($newUserField, $userPosition); 302 303 $form->addHTML("<div class=\"form-floating\">", $userPosition); 304 $form->addHTML("<label for=\"$userFieldId\">$loginText</label>", $userPosition + 2); 305 $form->addHTML("</div>", $userPosition + 3); 306 307 308 $pwdPosition = $form->findPositionByAttribute("name", "p"); 309 if ($pwdPosition == false) { 310 LogUtility::msg("Internal error: No password field found"); 311 return; 312 } 313 $pwdField = $form->getElementAt($pwdPosition); 314 $newPwdField = new InputElement($pwdField->getType(), "p"); 315 foreach ($pwdField->attrs() as $keyAttr => $valueAttr) { 316 $newPwdField->attr($keyAttr, $valueAttr); 317 } 318 $newPwdField->addClass("form-control"); 319 $passwordText = $pwdField->getLabel()->val(); 320 $newPwdField->attr("placeholder", $passwordText); 321 $newPwdField->attr("required", "required"); 322 $pwdFieldId = $newPwdField->attr("id"); 323 if (empty($pwdFieldId)) { 324 $pwdFieldId = "input__password"; 325 $newPwdField->id($pwdFieldId); 326 } 327 $form->replaceElement($newPwdField, $pwdPosition); 328 329 330 $form->addHTML("<div class=\"form-floating\">", $pwdPosition); 331 $form->addHTML("<label for=\"$pwdFieldId\">$passwordText</label>", $pwdPosition + 2); 332 $form->addHTML("</div>", $pwdPosition + 3); 333 334 335 $rememberPosition = $form->findPositionByAttribute("name", "r"); 336 if ($rememberPosition == false) { 337 LogUtility::msg("Internal error: No remember field found"); 338 return; 339 } 340 $rememberField = $form->getElementAt($rememberPosition); 341 $newRememberField = new InputElement($rememberField->getType(), "r"); 342 foreach ($rememberField->attrs() as $keyAttr => $valueAttr) { 343 $newRememberField->attr($keyAttr, $valueAttr); 344 } 345 $newRememberField->addClass("form-check-input"); 346 $form->replaceElement($newRememberField, $rememberPosition); 347 348 $remberText = $rememberField->getLabel()->val(); 349 $remFieldId = $newRememberField->attr("id"); 350 351 $form->addHTML("<div class=\"form-check py-2\">", $rememberPosition); 352 $form->addHTML("<label for=\"$remFieldId\" class=\"form-check-label\">$remberText</label>", $rememberPosition + 2); 353 $form->addHTML("</div>", $rememberPosition + 3); 354 355 356// $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph(); 357// if (!empty($registerHtml)) { 358// $newFormContent[] = $registerHtml; 359// } 360// 361// $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage(); 362// if (!empty($resendPwdHtml)) { 363// $newFormContent[] = $resendPwdHtml; 364// } 365 366 367 } 368 369} 370