@keycloakify/angular 0.0.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/lib/i18n.d.ts +4 -0
  4. package/lib/i18n.js +6 -0
  5. package/lib/i18n.js.map +1 -0
  6. package/lib/models/index.d.ts +1 -0
  7. package/lib/models/index.js +2 -0
  8. package/lib/models/index.js.map +1 -0
  9. package/lib/models/script.model.d.ts +6 -0
  10. package/lib/models/script.model.js +2 -0
  11. package/lib/models/script.model.js.map +1 -0
  12. package/lib/providers/keycloakify-angular.providers.d.ts +150 -0
  13. package/lib/providers/keycloakify-angular.providers.js +58 -0
  14. package/lib/providers/keycloakify-angular.providers.js.map +1 -0
  15. package/lib/public-api.d.ts +10 -0
  16. package/lib/public-api.js +4 -0
  17. package/lib/public-api.js.map +1 -0
  18. package/lib/services/i18n.service.d.ts +3 -0
  19. package/lib/services/i18n.service.js +14 -0
  20. package/lib/services/i18n.service.js.map +1 -0
  21. package/lib/services/index.d.ts +2 -0
  22. package/lib/services/index.js +3 -0
  23. package/lib/services/index.js.map +1 -0
  24. package/lib/services/resource-injector.service.d.ts +7 -0
  25. package/lib/services/resource-injector.service.js +57 -0
  26. package/lib/services/resource-injector.service.js.map +1 -0
  27. package/login/DefaultPage.d.ts +260 -0
  28. package/login/DefaultPage.js +121 -0
  29. package/login/DefaultPage.js.map +1 -0
  30. package/login/KcContext.d.ts +1 -0
  31. package/login/KcContext.js +2 -0
  32. package/login/KcContext.js.map +1 -0
  33. package/login/classes/component-reference.class.d.ts +5 -0
  34. package/login/classes/component-reference.class.js +3 -0
  35. package/login/classes/component-reference.class.js.map +1 -0
  36. package/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.d.ts +13 -0
  37. package/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.html +24 -0
  38. package/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.js +123 -0
  39. package/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.js.map +1 -0
  40. package/login/components/field-errors/field-errors.component.d.ts +11 -0
  41. package/login/components/field-errors/field-errors.component.html +15 -0
  42. package/login/components/field-errors/field-errors.component.js +45 -0
  43. package/login/components/field-errors/field-errors.component.js.map +1 -0
  44. package/login/components/group-label/group-label.component.d.ts +10 -0
  45. package/login/components/group-label/group-label.component.html +30 -0
  46. package/login/components/group-label/group-label.component.js +55 -0
  47. package/login/components/group-label/group-label.component.js.map +1 -0
  48. package/login/components/index.d.ts +11 -0
  49. package/login/components/index.js +12 -0
  50. package/login/components/index.js.map +1 -0
  51. package/login/components/input-field-by-type/input-field-by-type.component.d.ts +13 -0
  52. package/login/components/input-field-by-type/input-field-by-type.component.html +63 -0
  53. package/login/components/input-field-by-type/input-field-by-type.component.js +63 -0
  54. package/login/components/input-field-by-type/input-field-by-type.component.js.map +1 -0
  55. package/login/components/input-tag/input-tag.component.d.ts +17 -0
  56. package/login/components/input-tag/input-tag.component.html +49 -0
  57. package/login/components/input-tag/input-tag.component.js +107 -0
  58. package/login/components/input-tag/input-tag.component.js.map +1 -0
  59. package/login/components/input-tag-selects/input-tag-selects.component.d.ts +23 -0
  60. package/login/components/input-tag-selects/input-tag-selects.component.html +29 -0
  61. package/login/components/input-tag-selects/input-tag-selects.component.js +132 -0
  62. package/login/components/input-tag-selects/input-tag-selects.component.js.map +1 -0
  63. package/login/components/logout-other-sessions/logout-other-sessions.component.d.ts +6 -0
  64. package/login/components/logout-other-sessions/logout-other-sessions.component.html +19 -0
  65. package/login/components/logout-other-sessions/logout-other-sessions.component.js +43 -0
  66. package/login/components/logout-other-sessions/logout-other-sessions.component.js.map +1 -0
  67. package/login/components/password-wrapper/password-wrapper.component.d.ts +12 -0
  68. package/login/components/password-wrapper/password-wrapper.component.html +15 -0
  69. package/login/components/password-wrapper/password-wrapper.component.js +57 -0
  70. package/login/components/password-wrapper/password-wrapper.component.js.map +1 -0
  71. package/login/components/select-tag/select-tag.component.d.ts +16 -0
  72. package/login/components/select-tag/select-tag.component.html +31 -0
  73. package/login/components/select-tag/select-tag.component.js +97 -0
  74. package/login/components/select-tag/select-tag.component.js.map +1 -0
  75. package/login/components/textarea-tag/textarea-tag.component.d.ts +14 -0
  76. package/login/components/textarea-tag/textarea-tag.component.html +18 -0
  77. package/login/components/textarea-tag/textarea-tag.component.js +63 -0
  78. package/login/components/textarea-tag/textarea-tag.component.js.map +1 -0
  79. package/login/components/user-profile-form-fields/user-profile-form-fields.component.d.ts +25 -0
  80. package/login/components/user-profile-form-fields/user-profile-form-fields.component.html +85 -0
  81. package/login/components/user-profile-form-fields/user-profile-form-fields.component.js +74 -0
  82. package/login/components/user-profile-form-fields/user-profile-form-fields.component.js.map +1 -0
  83. package/login/containers/template.component.d.ts +28 -0
  84. package/login/containers/template.component.html +203 -0
  85. package/login/containers/template.component.js +78 -0
  86. package/login/containers/template.component.js.map +1 -0
  87. package/login/directives/attributes.directive.d.ts +5 -0
  88. package/login/directives/attributes.directive.js +34 -0
  89. package/login/directives/attributes.directive.js.map +1 -0
  90. package/login/directives/index.d.ts +2 -0
  91. package/login/directives/index.js +3 -0
  92. package/login/directives/index.js.map +1 -0
  93. package/login/directives/kc-class.directive.d.ts +23 -0
  94. package/login/directives/kc-class.directive.js +146 -0
  95. package/login/directives/kc-class.directive.js.map +1 -0
  96. package/login/i18n.d.ts +4 -0
  97. package/login/i18n.js +2 -0
  98. package/login/i18n.js.map +1 -0
  99. package/login/pages/code/code.component.d.ts +8 -0
  100. package/login/pages/code/code.component.html +26 -0
  101. package/login/pages/code/code.component.js +38 -0
  102. package/login/pages/code/code.component.js.map +1 -0
  103. package/login/pages/delete-account-confirm/delete-account-confirm.component.d.ts +8 -0
  104. package/login/pages/delete-account-confirm/delete-account-confirm.component.html +46 -0
  105. package/login/pages/delete-account-confirm/delete-account-confirm.component.js +38 -0
  106. package/login/pages/delete-account-confirm/delete-account-confirm.component.js.map +1 -0
  107. package/login/pages/delete-credential/delete-credential.component.d.ts +13 -0
  108. package/login/pages/delete-credential/delete-credential.component.html +35 -0
  109. package/login/pages/delete-credential/delete-credential.component.js +43 -0
  110. package/login/pages/delete-credential/delete-credential.component.js.map +1 -0
  111. package/login/pages/error/error.component.d.ts +8 -0
  112. package/login/pages/error/error.component.html +25 -0
  113. package/login/pages/error/error.component.js +38 -0
  114. package/login/pages/error/error.component.js.map +1 -0
  115. package/login/pages/frontchannel-logout/frontchannel-logout.component.d.ts +14 -0
  116. package/login/pages/frontchannel-logout/frontchannel-logout.component.html +35 -0
  117. package/login/pages/frontchannel-logout/frontchannel-logout.component.js +47 -0
  118. package/login/pages/frontchannel-logout/frontchannel-logout.component.js.map +1 -0
  119. package/login/pages/idp-review-user-profile/idp-review-user-profile.component.d.ts +15 -0
  120. package/login/pages/idp-review-user-profile/idp-review-user-profile.component.html +41 -0
  121. package/login/pages/idp-review-user-profile/idp-review-user-profile.component.js +54 -0
  122. package/login/pages/idp-review-user-profile/idp-review-user-profile.component.js.map +1 -0
  123. package/login/pages/info/info.component.d.ts +20 -0
  124. package/login/pages/info/info.component.html +54 -0
  125. package/login/pages/info/info.component.js +61 -0
  126. package/login/pages/info/info.component.js.map +1 -0
  127. package/login/pages/login/login.component.d.ts +14 -0
  128. package/login/pages/login/login.component.html +212 -0
  129. package/login/pages/login/login.component.js +58 -0
  130. package/login/pages/login/login.component.js.map +1 -0
  131. package/login/pages/login-config-totp/login-config-totp.component.d.ts +13 -0
  132. package/login/pages/login-config-totp/login-config-totp.component.html +190 -0
  133. package/login/pages/login-config-totp/login-config-totp.component.js +53 -0
  134. package/login/pages/login-config-totp/login-config-totp.component.js.map +1 -0
  135. package/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.d.ts +13 -0
  136. package/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.html +41 -0
  137. package/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.js +43 -0
  138. package/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.js.map +1 -0
  139. package/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.d.ts +13 -0
  140. package/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.html +40 -0
  141. package/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.js +43 -0
  142. package/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.js.map +1 -0
  143. package/login/pages/login-idp-link-email/login-idp-link-email.component.d.ts +13 -0
  144. package/login/pages/login-idp-link-email/login-idp-link-email.component.html +37 -0
  145. package/login/pages/login-idp-link-email/login-idp-link-email.component.js +43 -0
  146. package/login/pages/login-idp-link-email/login-idp-link-email.component.js.map +1 -0
  147. package/login/pages/login-oauth-grant/login-oauth-grant.component.d.ts +13 -0
  148. package/login/pages/login-oauth-grant/login-oauth-grant.component.html +92 -0
  149. package/login/pages/login-oauth-grant/login-oauth-grant.component.js +44 -0
  150. package/login/pages/login-oauth-grant/login-oauth-grant.component.js.map +1 -0
  151. package/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.d.ts +13 -0
  152. package/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.html +63 -0
  153. package/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.js +43 -0
  154. package/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.js.map +1 -0
  155. package/login/pages/login-otp/login-otp.component.d.ts +13 -0
  156. package/login/pages/login-otp/login-otp.component.html +103 -0
  157. package/login/pages/login-otp/login-otp.component.js +44 -0
  158. package/login/pages/login-otp/login-otp.component.js.map +1 -0
  159. package/login/pages/login-page-expired/login-page-expired.component.d.ts +13 -0
  160. package/login/pages/login-page-expired/login-page-expired.component.html +35 -0
  161. package/login/pages/login-page-expired/login-page-expired.component.js +42 -0
  162. package/login/pages/login-page-expired/login-page-expired.component.js.map +1 -0
  163. package/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.d.ts +16 -0
  164. package/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.html +203 -0
  165. package/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.js +91 -0
  166. package/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.js.map +1 -0
  167. package/login/pages/login-password/login-password.component.d.ts +14 -0
  168. package/login/pages/login-password/login-password.component.html +90 -0
  169. package/login/pages/login-password/login-password.component.js +52 -0
  170. package/login/pages/login-password/login-password.component.js.map +1 -0
  171. package/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.d.ts +15 -0
  172. package/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.html +155 -0
  173. package/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.js +51 -0
  174. package/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.js.map +1 -0
  175. package/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.d.ts +13 -0
  176. package/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.html +76 -0
  177. package/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.js +44 -0
  178. package/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.js.map +1 -0
  179. package/login/pages/login-reset-otp/login-reset-otp.component.d.ts +13 -0
  180. package/login/pages/login-reset-otp/login-reset-otp.component.html +65 -0
  181. package/login/pages/login-reset-otp/login-reset-otp.component.js +43 -0
  182. package/login/pages/login-reset-otp/login-reset-otp.component.js.map +1 -0
  183. package/login/pages/login-reset-password/login-reset-password.component.d.ts +13 -0
  184. package/login/pages/login-reset-password/login-reset-password.component.html +95 -0
  185. package/login/pages/login-reset-password/login-reset-password.component.js +44 -0
  186. package/login/pages/login-reset-password/login-reset-password.component.js.map +1 -0
  187. package/login/pages/login-update-password/login-update-password.component.d.ts +13 -0
  188. package/login/pages/login-update-password/login-update-password.component.html +116 -0
  189. package/login/pages/login-update-password/login-update-password.component.js +53 -0
  190. package/login/pages/login-update-password/login-update-password.component.js.map +1 -0
  191. package/login/pages/login-update-profile/login-update-profile.component.d.ts +14 -0
  192. package/login/pages/login-update-profile/login-update-profile.component.html +59 -0
  193. package/login/pages/login-update-profile/login-update-profile.component.js +50 -0
  194. package/login/pages/login-update-profile/login-update-profile.component.js.map +1 -0
  195. package/login/pages/login-username/login-username.component.d.ts +14 -0
  196. package/login/pages/login-username/login-username.component.html +161 -0
  197. package/login/pages/login-username/login-username.component.js +56 -0
  198. package/login/pages/login-username/login-username.component.js.map +1 -0
  199. package/login/pages/login-verify-email/login-verify-email.component.d.ts +13 -0
  200. package/login/pages/login-verify-email/login-verify-email.component.html +27 -0
  201. package/login/pages/login-verify-email/login-verify-email.component.js +43 -0
  202. package/login/pages/login-verify-email/login-verify-email.component.js.map +1 -0
  203. package/login/pages/login-x509-info/login-x509-info.component.d.ts +13 -0
  204. package/login/pages/login-x509-info/login-x509-info.component.html +102 -0
  205. package/login/pages/login-x509-info/login-x509-info.component.js +43 -0
  206. package/login/pages/login-x509-info/login-x509-info.component.js.map +1 -0
  207. package/login/pages/logout-confirm/logout-confirm.component.d.ts +13 -0
  208. package/login/pages/logout-confirm/logout-confirm.component.html +59 -0
  209. package/login/pages/logout-confirm/logout-confirm.component.js +43 -0
  210. package/login/pages/logout-confirm/logout-confirm.component.js.map +1 -0
  211. package/login/pages/register/register.component.d.ts +16 -0
  212. package/login/pages/register/register.component.html +126 -0
  213. package/login/pages/register/register.component.js +62 -0
  214. package/login/pages/register/register.component.js.map +1 -0
  215. package/login/pages/saml-post-form/saml-post-form.component.d.ts +16 -0
  216. package/login/pages/saml-post-form/saml-post-form.component.html +51 -0
  217. package/login/pages/saml-post-form/saml-post-form.component.js +55 -0
  218. package/login/pages/saml-post-form/saml-post-form.component.js.map +1 -0
  219. package/login/pages/select-authenticator/select-authenticator.component.d.ts +13 -0
  220. package/login/pages/select-authenticator/select-authenticator.component.html +49 -0
  221. package/login/pages/select-authenticator/select-authenticator.component.js +51 -0
  222. package/login/pages/select-authenticator/select-authenticator.component.js.map +1 -0
  223. package/login/pages/terms/terms.component.d.ts +13 -0
  224. package/login/pages/terms/terms.component.html +36 -0
  225. package/login/pages/terms/terms.component.js +43 -0
  226. package/login/pages/terms/terms.component.js.map +1 -0
  227. package/login/pages/update-email/update-email.component.d.ts +14 -0
  228. package/login/pages/update-email/update-email.component.html +58 -0
  229. package/login/pages/update-email/update-email.component.js +52 -0
  230. package/login/pages/update-email/update-email.component.js.map +1 -0
  231. package/login/pages/webauthn-authenticate/webauthn-authenticate.component.d.ts +20 -0
  232. package/login/pages/webauthn-authenticate/webauthn-authenticate.component.html +162 -0
  233. package/login/pages/webauthn-authenticate/webauthn-authenticate.component.js +93 -0
  234. package/login/pages/webauthn-authenticate/webauthn-authenticate.component.js.map +1 -0
  235. package/login/pages/webauthn-error/webauthn-error.component.d.ts +14 -0
  236. package/login/pages/webauthn-error/webauthn-error.component.html +60 -0
  237. package/login/pages/webauthn-error/webauthn-error.component.js +57 -0
  238. package/login/pages/webauthn-error/webauthn-error.component.js.map +1 -0
  239. package/login/pages/webauthn-register/webauthn-register.component.d.ts +19 -0
  240. package/login/pages/webauthn-register/webauthn-register.component.html +82 -0
  241. package/login/pages/webauthn-register/webauthn-register.component.js +86 -0
  242. package/login/pages/webauthn-register/webauthn-register.component.js.map +1 -0
  243. package/login/pipes/advanced-msg-str.pipe.d.ts +5 -0
  244. package/login/pipes/advanced-msg-str.pipe.js +31 -0
  245. package/login/pipes/advanced-msg-str.pipe.js.map +1 -0
  246. package/login/pipes/index.d.ts +6 -0
  247. package/login/pipes/index.js +7 -0
  248. package/login/pipes/index.js.map +1 -0
  249. package/login/pipes/input-type.pipe.d.ts +4 -0
  250. package/login/pipes/input-type.pipe.js +23 -0
  251. package/login/pipes/input-type.pipe.js.map +1 -0
  252. package/login/pipes/kc-sanitize.pipe.d.ts +7 -0
  253. package/login/pipes/kc-sanitize.pipe.js +36 -0
  254. package/login/pipes/kc-sanitize.pipe.js.map +1 -0
  255. package/login/pipes/msg-str.pipe.d.ts +6 -0
  256. package/login/pipes/msg-str.pipe.js +31 -0
  257. package/login/pipes/msg-str.pipe.js.map +1 -0
  258. package/login/pipes/to-array.pipe.d.ts +4 -0
  259. package/login/pipes/to-array.pipe.js +24 -0
  260. package/login/pipes/to-array.pipe.js.map +1 -0
  261. package/login/pipes/to-number.pipe.d.ts +4 -0
  262. package/login/pipes/to-number.pipe.js +23 -0
  263. package/login/pipes/to-number.pipe.js.map +1 -0
  264. package/login/services/index.d.ts +2 -0
  265. package/login/services/index.js +3 -0
  266. package/login/services/index.js.map +1 -0
  267. package/login/services/login-resource-injector.service.d.ts +8 -0
  268. package/login/services/login-resource-injector.service.js +71 -0
  269. package/login/services/login-resource-injector.service.js.map +1 -0
  270. package/login/services/user-profile-form.service.d.ts +82 -0
  271. package/login/services/user-profile-form.service.js +1031 -0
  272. package/login/services/user-profile-form.service.js.map +1 -0
  273. package/package.json +450 -0
  274. package/src/lib/i18n.ts +9 -0
  275. package/src/lib/models/index.ts +1 -0
  276. package/src/lib/models/script.model.ts +6 -0
  277. package/src/lib/providers/keycloakify-angular.providers.ts +92 -0
  278. package/src/lib/public-api.ts +12 -0
  279. package/src/lib/services/i18n.service.ts +5 -0
  280. package/src/lib/services/index.ts +2 -0
  281. package/src/lib/services/resource-injector.service.ts +50 -0
  282. package/src/login/DefaultPage.ts +208 -0
  283. package/src/login/KcContext.ts +1 -0
  284. package/src/login/classes/component-reference.class.ts +5 -0
  285. package/src/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.html +24 -0
  286. package/src/login/components/add-remove-buttons-multi-valued-attribute/add-remove-buttons-multi-valued-attribute.component.ts +144 -0
  287. package/src/login/components/field-errors/field-errors.component.html +15 -0
  288. package/src/login/components/field-errors/field-errors.component.ts +41 -0
  289. package/src/login/components/group-label/group-label.component.html +30 -0
  290. package/src/login/components/group-label/group-label.component.ts +50 -0
  291. package/src/login/components/index.ts +11 -0
  292. package/src/login/components/input-field-by-type/input-field-by-type.component.html +63 -0
  293. package/src/login/components/input-field-by-type/input-field-by-type.component.ts +67 -0
  294. package/src/login/components/input-tag/input-tag.component.html +49 -0
  295. package/src/login/components/input-tag/input-tag.component.ts +108 -0
  296. package/src/login/components/input-tag-selects/input-tag-selects.component.html +29 -0
  297. package/src/login/components/input-tag-selects/input-tag-selects.component.ts +150 -0
  298. package/src/login/components/logout-other-sessions/logout-other-sessions.component.html +19 -0
  299. package/src/login/components/logout-other-sessions/logout-other-sessions.component.ts +31 -0
  300. package/src/login/components/password-wrapper/password-wrapper.component.html +15 -0
  301. package/src/login/components/password-wrapper/password-wrapper.component.ts +61 -0
  302. package/src/login/components/select-tag/select-tag.component.html +31 -0
  303. package/src/login/components/select-tag/select-tag.component.ts +109 -0
  304. package/src/login/components/textarea-tag/textarea-tag.component.html +18 -0
  305. package/src/login/components/textarea-tag/textarea-tag.component.ts +63 -0
  306. package/src/login/components/user-profile-form-fields/user-profile-form-fields.component.html +85 -0
  307. package/src/login/components/user-profile-form-fields/user-profile-form-fields.component.ts +84 -0
  308. package/src/login/containers/template.component.html +203 -0
  309. package/src/login/containers/template.component.ts +94 -0
  310. package/src/login/directives/attributes.directive.ts +23 -0
  311. package/src/login/directives/index.ts +2 -0
  312. package/src/login/directives/kc-class.directive.ts +167 -0
  313. package/src/login/i18n.ts +4 -0
  314. package/src/login/pages/code/code.component.html +26 -0
  315. package/src/login/pages/code/code.component.ts +31 -0
  316. package/src/login/pages/delete-account-confirm/delete-account-confirm.component.html +46 -0
  317. package/src/login/pages/delete-account-confirm/delete-account-confirm.component.ts +32 -0
  318. package/src/login/pages/delete-credential/delete-credential.component.html +35 -0
  319. package/src/login/pages/delete-credential/delete-credential.component.ts +43 -0
  320. package/src/login/pages/error/error.component.html +25 -0
  321. package/src/login/pages/error/error.component.ts +31 -0
  322. package/src/login/pages/frontchannel-logout/frontchannel-logout.component.html +35 -0
  323. package/src/login/pages/frontchannel-logout/frontchannel-logout.component.ts +49 -0
  324. package/src/login/pages/idp-review-user-profile/idp-review-user-profile.component.html +41 -0
  325. package/src/login/pages/idp-review-user-profile/idp-review-user-profile.component.ts +55 -0
  326. package/src/login/pages/info/info.component.html +54 -0
  327. package/src/login/pages/info/info.component.ts +65 -0
  328. package/src/login/pages/login/login.component.html +212 -0
  329. package/src/login/pages/login/login.component.ts +61 -0
  330. package/src/login/pages/login-config-totp/login-config-totp.component.html +190 -0
  331. package/src/login/pages/login-config-totp/login-config-totp.component.ts +57 -0
  332. package/src/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.html +41 -0
  333. package/src/login/pages/login-idp-link-confirm/login-idp-link-confirm.component.ts +43 -0
  334. package/src/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.html +40 -0
  335. package/src/login/pages/login-idp-link-confirm-override/login-idp-link-confirm-override.component.ts +45 -0
  336. package/src/login/pages/login-idp-link-email/login-idp-link-email.component.html +37 -0
  337. package/src/login/pages/login-idp-link-email/login-idp-link-email.component.ts +43 -0
  338. package/src/login/pages/login-oauth-grant/login-oauth-grant.component.html +92 -0
  339. package/src/login/pages/login-oauth-grant/login-oauth-grant.component.ts +44 -0
  340. package/src/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.html +63 -0
  341. package/src/login/pages/login-oauth2-device-verify-user-code/login-oauth2-device-verify-user-code.component.ts +45 -0
  342. package/src/login/pages/login-otp/login-otp.component.html +103 -0
  343. package/src/login/pages/login-otp/login-otp.component.ts +43 -0
  344. package/src/login/pages/login-page-expired/login-page-expired.component.html +35 -0
  345. package/src/login/pages/login-page-expired/login-page-expired.component.ts +42 -0
  346. package/src/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.html +203 -0
  347. package/src/login/pages/login-passkeys-conditional-authenticate/login-passkeys-conditional-authenticate.component.ts +101 -0
  348. package/src/login/pages/login-password/login-password.component.html +90 -0
  349. package/src/login/pages/login-password/login-password.component.ts +53 -0
  350. package/src/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.html +155 -0
  351. package/src/login/pages/login-recovery-authn-code-config/login-recovery-authn-code-config.component.ts +55 -0
  352. package/src/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.html +76 -0
  353. package/src/login/pages/login-recovery-authn-code-input/login-recovery-authn-code-input.component.ts +47 -0
  354. package/src/login/pages/login-reset-otp/login-reset-otp.component.html +65 -0
  355. package/src/login/pages/login-reset-otp/login-reset-otp.component.ts +42 -0
  356. package/src/login/pages/login-reset-password/login-reset-password.component.html +95 -0
  357. package/src/login/pages/login-reset-password/login-reset-password.component.ts +44 -0
  358. package/src/login/pages/login-update-password/login-update-password.component.html +116 -0
  359. package/src/login/pages/login-update-password/login-update-password.component.ts +56 -0
  360. package/src/login/pages/login-update-profile/login-update-profile.component.html +59 -0
  361. package/src/login/pages/login-update-profile/login-update-profile.component.ts +52 -0
  362. package/src/login/pages/login-username/login-username.component.html +161 -0
  363. package/src/login/pages/login-username/login-username.component.ts +56 -0
  364. package/src/login/pages/login-verify-email/login-verify-email.component.html +27 -0
  365. package/src/login/pages/login-verify-email/login-verify-email.component.ts +43 -0
  366. package/src/login/pages/login-x509-info/login-x509-info.component.html +102 -0
  367. package/src/login/pages/login-x509-info/login-x509-info.component.ts +42 -0
  368. package/src/login/pages/logout-confirm/logout-confirm.component.html +59 -0
  369. package/src/login/pages/logout-confirm/logout-confirm.component.ts +42 -0
  370. package/src/login/pages/register/register.component.html +126 -0
  371. package/src/login/pages/register/register.component.ts +62 -0
  372. package/src/login/pages/saml-post-form/saml-post-form.component.html +51 -0
  373. package/src/login/pages/saml-post-form/saml-post-form.component.ts +58 -0
  374. package/src/login/pages/select-authenticator/select-authenticator.component.html +49 -0
  375. package/src/login/pages/select-authenticator/select-authenticator.component.ts +51 -0
  376. package/src/login/pages/terms/terms.component.html +36 -0
  377. package/src/login/pages/terms/terms.component.ts +42 -0
  378. package/src/login/pages/update-email/update-email.component.html +58 -0
  379. package/src/login/pages/update-email/update-email.component.ts +52 -0
  380. package/src/login/pages/webauthn-authenticate/webauthn-authenticate.component.html +162 -0
  381. package/src/login/pages/webauthn-authenticate/webauthn-authenticate.component.ts +106 -0
  382. package/src/login/pages/webauthn-error/webauthn-error.component.html +60 -0
  383. package/src/login/pages/webauthn-error/webauthn-error.component.ts +57 -0
  384. package/src/login/pages/webauthn-register/webauthn-register.component.html +82 -0
  385. package/src/login/pages/webauthn-register/webauthn-register.component.ts +106 -0
  386. package/src/login/pipes/advanced-msg-str.pipe.ts +13 -0
  387. package/src/login/pipes/index.ts +6 -0
  388. package/src/login/pipes/input-type.pipe.ts +15 -0
  389. package/src/login/pipes/kc-sanitize.pipe.ts +36 -0
  390. package/src/login/pipes/msg-str.pipe.ts +14 -0
  391. package/src/login/pipes/to-array.pipe.ts +15 -0
  392. package/src/login/pipes/to-number.pipe.ts +13 -0
  393. package/src/login/services/index.ts +2 -0
  394. package/src/login/services/login-resource-injector.service.ts +72 -0
  395. package/src/login/services/user-profile-form.service.ts +1504 -0
  396. package/src/tsconfig.json +18 -0
@@ -0,0 +1,1504 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
3
+
4
+ import {
5
+ computed,
6
+ inject,
7
+ Injectable,
8
+ signal,
9
+ Signal,
10
+ WritableSignal
11
+ } from "@angular/core";
12
+ import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
13
+ import {
14
+ DO_MAKE_USER_CONFIRM_PASSWORD,
15
+ I18N,
16
+ KC_CONTEXT
17
+ } from "@keycloakify/angular/lib/public-api";
18
+ import {
19
+ Attribute,
20
+ KcContext,
21
+ PasswordPolicies,
22
+ Validators
23
+ } from "keycloakify/login/KcContext";
24
+ import type {
25
+ KcContextLike as KcContextLike_i18n,
26
+ MessageKey_defaultSet
27
+ } from "keycloakify/login/i18n/noJsx";
28
+ import type { I18n } from "../i18n";
29
+ import { emailRegexp } from "keycloakify/tools/emailRegExp";
30
+ import { formatNumber } from "keycloakify/tools/formatNumber";
31
+ import { structuredCloneButFunctions } from "keycloakify/tools/structuredCloneButFunctions";
32
+ import { assert, id } from "tsafe";
33
+ import { LoginResourceInjectorService } from "./login-resource-injector.service";
34
+
35
+ type KcContextLike_useGetErrors = KcContextLike_i18n & {
36
+ messagesPerField: Pick<KcContext["messagesPerField"], "existsError" | "get">;
37
+ passwordPolicies?: PasswordPolicies;
38
+ };
39
+ export namespace FormFieldError {
40
+ export type Source =
41
+ | Source.Validator
42
+ | Source.PasswordPolicy
43
+ | Source.Server
44
+ | Source.Other;
45
+
46
+ export namespace Source {
47
+ export type Validator = {
48
+ type: "validator";
49
+ name: keyof Validators;
50
+ };
51
+ export type PasswordPolicy = {
52
+ type: "passwordPolicy";
53
+ name: keyof PasswordPolicies;
54
+ };
55
+ export type Server = {
56
+ type: "server";
57
+ };
58
+
59
+ export type Other = {
60
+ type: "other";
61
+ rule: "passwordConfirmMatchesPassword" | "requiredField";
62
+ };
63
+ }
64
+ }
65
+
66
+ export type KcContextLike = KcContextLike_i18n &
67
+ KcContextLike_useGetErrors & {
68
+ profile: {
69
+ attributesByName: Record<string, Attribute>;
70
+ html5DataAnnotations?: Record<string, string>;
71
+ };
72
+ passwordRequired?: boolean;
73
+ realm: { registrationEmailAsUsername: boolean };
74
+ url: {
75
+ resourcesPath: string;
76
+ };
77
+ };
78
+ export type FormFieldError = {
79
+ errorMessage: SafeHtml; // this was jsx, be carefull
80
+ errorMessageStr: string;
81
+ source: FormFieldError.Source;
82
+ fieldIndex: number | undefined;
83
+ };
84
+ namespace internal {
85
+ export type FormFieldState = {
86
+ attribute: Attribute;
87
+ errors: FormFieldError[];
88
+ hasLostFocusAtLeastOnce: boolean | boolean[];
89
+ valueOrValues: string | string[];
90
+ };
91
+
92
+ export type State = {
93
+ formFieldStates: FormFieldState[];
94
+ };
95
+ }
96
+ type FormFieldState = {
97
+ attribute: Attribute;
98
+ displayableErrors: FormFieldError[];
99
+ valueOrValues: string | string[];
100
+ };
101
+ type FormState = {
102
+ isFormSubmittable: boolean;
103
+ formFieldStates: FormFieldState[];
104
+ };
105
+ export type FormAction =
106
+ | {
107
+ action: "update";
108
+ name: string;
109
+ valueOrValues: string | string[];
110
+ /** Default false */
111
+ displayErrorsImmediately?: boolean;
112
+ }
113
+ | {
114
+ action: "focus lost";
115
+ name: string;
116
+ fieldIndex: number | undefined;
117
+ };
118
+
119
+ @Injectable({ providedIn: "root" })
120
+ export class UserProfileFormService {
121
+ private kcContext: KcContextLike =
122
+ inject<Extract<KcContext, { pageId: "register.ftl" }>>(KC_CONTEXT);
123
+ private i18n = inject<I18n>(I18N);
124
+ private doMakeUserConfirmPassword = inject(DO_MAKE_USER_CONFIRM_PASSWORD);
125
+ private loginResourceInjectorService = inject(LoginResourceInjectorService);
126
+ private sanitizer: DomSanitizer = inject(DomSanitizer);
127
+ private initialState: internal.State = (() => {
128
+ const attributes: Attribute[] = (() => {
129
+ mock_user_profile_attributes_for_older_keycloak_versions: {
130
+ if (
131
+ "profile" in this.kcContext &&
132
+ "attributesByName" in this.kcContext.profile &&
133
+ Object.keys(this.kcContext.profile.attributesByName).length !== 0
134
+ ) {
135
+ break mock_user_profile_attributes_for_older_keycloak_versions;
136
+ }
137
+
138
+ if (
139
+ "register" in this.kcContext &&
140
+ this.kcContext.register instanceof Object &&
141
+ "formData" in this.kcContext.register
142
+ ) {
143
+ //NOTE: Handle legacy register.ftl page
144
+ return (["firstName", "lastName", "email", "username"] as const)
145
+ .filter(name =>
146
+ name !== "username"
147
+ ? true
148
+ : !this.kcContext.realm.registrationEmailAsUsername
149
+ )
150
+ .map(name =>
151
+ id<Attribute>({
152
+ name: name,
153
+ displayName: id<`\${${MessageKey_defaultSet}}`>(
154
+ `\${${name}}`
155
+ ),
156
+ required: true,
157
+ value:
158
+ (this.kcContext as any).register.formData[name] ?? "",
159
+ html5DataAnnotations: {},
160
+ readOnly: false,
161
+ validators: {},
162
+ annotations: {},
163
+ autocomplete: (() => {
164
+ switch (name) {
165
+ case "email":
166
+ return "email";
167
+ case "username":
168
+ return "username";
169
+ default:
170
+ return undefined;
171
+ }
172
+ })()
173
+ })
174
+ );
175
+ }
176
+
177
+ if ("user" in this.kcContext && this.kcContext.user instanceof Object) {
178
+ //NOTE: Handle legacy login-update-profile.ftl
179
+ return (["username", "email", "firstName", "lastName"] as const)
180
+ .filter(name =>
181
+ name !== "username"
182
+ ? true
183
+ : (this.kcContext as any).user.editUsernameAllowed
184
+ )
185
+ .map(name =>
186
+ id<Attribute>({
187
+ name: name,
188
+ displayName: id<`\${${MessageKey_defaultSet}}`>(
189
+ `\${${name}}`
190
+ ),
191
+ required: true,
192
+ value: (this.kcContext as any).user[name] ?? "",
193
+ html5DataAnnotations: {},
194
+ readOnly: false,
195
+ validators: {},
196
+ annotations: {},
197
+ autocomplete: (() => {
198
+ switch (name) {
199
+ case "email":
200
+ return "email";
201
+ case "username":
202
+ return "username";
203
+ default:
204
+ return undefined;
205
+ }
206
+ })()
207
+ })
208
+ );
209
+ }
210
+
211
+ if ("email" in this.kcContext && this.kcContext.email instanceof Object) {
212
+ //NOTE: Handle legacy update-email.ftl
213
+ return [
214
+ id<Attribute>({
215
+ name: "email",
216
+ displayName: id<`\${${MessageKey_defaultSet}}`>(`\${email}`),
217
+ required: true,
218
+ value: (this.kcContext.email as any).value ?? "",
219
+ html5DataAnnotations: {},
220
+ readOnly: false,
221
+ validators: {},
222
+ annotations: {},
223
+ autocomplete: "email"
224
+ })
225
+ ];
226
+ }
227
+
228
+ assert(false, "Unable to mock user profile from the current kcContext");
229
+ }
230
+
231
+ return Object.values(this.kcContext.profile.attributesByName).map(
232
+ structuredCloneButFunctions
233
+ );
234
+ })();
235
+ // Retro-compatibility and consistency patches
236
+ attributes.forEach(attribute => {
237
+ patch_legacy_group: {
238
+ if (typeof attribute.group !== "string") {
239
+ break patch_legacy_group;
240
+ }
241
+
242
+ const {
243
+ group,
244
+ groupDisplayHeader,
245
+ groupDisplayDescription,
246
+ groupAnnotations
247
+ } = attribute as Attribute & {
248
+ group: string;
249
+ groupDisplayHeader?: string;
250
+ groupDisplayDescription?: string;
251
+ groupAnnotations: Record<string, string>;
252
+ };
253
+
254
+ delete attribute.group;
255
+ // @ts-expect-error
256
+ delete attribute.groupDisplayHeader;
257
+ // @ts-expect-error
258
+ delete attribute.groupDisplayDescription;
259
+ // @ts-expect-error
260
+ delete attribute.groupAnnotations;
261
+
262
+ if (group === "") {
263
+ break patch_legacy_group;
264
+ }
265
+
266
+ attribute.group = {
267
+ name: group,
268
+ displayHeader: groupDisplayHeader,
269
+ displayDescription: groupDisplayDescription,
270
+ annotations: groupAnnotations,
271
+ html5DataAnnotations: {}
272
+ };
273
+ }
274
+
275
+ // Attributes with options rendered by default as select inputs
276
+ if (
277
+ attribute.validators.options !== undefined &&
278
+ attribute.annotations.inputType === undefined
279
+ ) {
280
+ attribute.annotations.inputType = "select";
281
+ }
282
+
283
+ // Consistency patch on values/value property
284
+ {
285
+ if (this.getIsMultivaluedSingleField({ attribute })) {
286
+ attribute.multivalued = true;
287
+ }
288
+
289
+ if (attribute.multivalued) {
290
+ attribute.values ??=
291
+ attribute.value !== undefined ? [attribute.value] : [];
292
+ delete attribute.value;
293
+ } else {
294
+ attribute.value ??= attribute.values?.[0];
295
+ delete attribute.values;
296
+ }
297
+ }
298
+ });
299
+ add_password_and_password_confirm: {
300
+ if (!this.kcContext.passwordRequired) {
301
+ break add_password_and_password_confirm;
302
+ }
303
+
304
+ attributes.forEach((attribute, i) => {
305
+ if (
306
+ attribute.name !==
307
+ (this.kcContext.realm.registrationEmailAsUsername
308
+ ? "email"
309
+ : "username")
310
+ ) {
311
+ // NOTE: We want to add password and password-confirm after the field that identifies the user.
312
+ // It's either email or username.
313
+ return;
314
+ }
315
+
316
+ attributes.splice(
317
+ i + 1,
318
+ 0,
319
+ {
320
+ name: "password",
321
+ displayName: id<`\${${MessageKey_defaultSet}}`>("${password}"),
322
+ required: true,
323
+ readOnly: false,
324
+ validators: {},
325
+ annotations: {},
326
+ autocomplete: "new-password",
327
+ html5DataAnnotations: {}
328
+ },
329
+ {
330
+ name: "password-confirm",
331
+ displayName:
332
+ id<`\${${MessageKey_defaultSet}}`>("${passwordConfirm}"),
333
+ required: true,
334
+ readOnly: false,
335
+ validators: {},
336
+ annotations: {},
337
+ html5DataAnnotations: {},
338
+ autocomplete: "new-password"
339
+ }
340
+ );
341
+ });
342
+ }
343
+ const initialFormFieldState: {
344
+ attribute: Attribute;
345
+ valueOrValues: string | string[];
346
+ }[] = [];
347
+
348
+ for (const attribute of attributes) {
349
+ handle_multi_valued_attribute: {
350
+ if (!attribute.multivalued) {
351
+ break handle_multi_valued_attribute;
352
+ }
353
+
354
+ const values = attribute.values?.length ? attribute.values : [""];
355
+
356
+ apply_validator_min_range: {
357
+ if (this.getIsMultivaluedSingleField({ attribute })) {
358
+ break apply_validator_min_range;
359
+ }
360
+
361
+ const validator = attribute.validators.multivalued;
362
+
363
+ if (validator === undefined) {
364
+ break apply_validator_min_range;
365
+ }
366
+
367
+ const { min: minStr } = validator;
368
+
369
+ if (!minStr) {
370
+ break apply_validator_min_range;
371
+ }
372
+
373
+ const min = parseInt(`${minStr}`);
374
+
375
+ for (let index = values.length; index < min; index++) {
376
+ values.push("");
377
+ }
378
+ }
379
+
380
+ initialFormFieldState.push({
381
+ attribute,
382
+ valueOrValues: values
383
+ });
384
+
385
+ continue;
386
+ }
387
+
388
+ initialFormFieldState.push({
389
+ attribute,
390
+ valueOrValues: attribute.value ?? ""
391
+ });
392
+ }
393
+
394
+ const initialState: internal.State = {
395
+ formFieldStates: initialFormFieldState.map(
396
+ ({ attribute, valueOrValues }) => ({
397
+ attribute,
398
+ errors: this.getErrors({
399
+ attributeName: attribute.name,
400
+ formFieldStates: initialFormFieldState
401
+ }),
402
+ hasLostFocusAtLeastOnce:
403
+ valueOrValues instanceof Array &&
404
+ !this.getIsMultivaluedSingleField({ attribute })
405
+ ? valueOrValues.map(() => false)
406
+ : false,
407
+ valueOrValues: valueOrValues
408
+ })
409
+ )
410
+ };
411
+ return initialState;
412
+ })();
413
+
414
+ private state: WritableSignal<internal.State> = signal(this.initialState);
415
+
416
+ formState: Signal<FormState> = computed(() => {
417
+ const state: internal.State = this.state();
418
+ return {
419
+ formFieldStates: state.formFieldStates.map(
420
+ ({
421
+ errors,
422
+ hasLostFocusAtLeastOnce: hasLostFocusAtLeastOnceOrArr,
423
+ attribute,
424
+ ...valueOrValuesWrap
425
+ }) => ({
426
+ displayableErrors: errors.filter(error => {
427
+ const hasLostFocusAtLeastOnce =
428
+ typeof hasLostFocusAtLeastOnceOrArr === "boolean"
429
+ ? hasLostFocusAtLeastOnceOrArr
430
+ : error.fieldIndex !== undefined
431
+ ? hasLostFocusAtLeastOnceOrArr[error.fieldIndex]
432
+ : hasLostFocusAtLeastOnceOrArr[
433
+ hasLostFocusAtLeastOnceOrArr.length - 1
434
+ ];
435
+ let value = false;
436
+ switch (error.source.type) {
437
+ case "server":
438
+ value = true;
439
+ break;
440
+ case "other":
441
+ switch (error.source.rule) {
442
+ case "requiredField":
443
+ value = hasLostFocusAtLeastOnce;
444
+ break;
445
+ case "passwordConfirmMatchesPassword":
446
+ value = hasLostFocusAtLeastOnce;
447
+ break;
448
+ }
449
+ // assert<Equals<typeof error.source.rule, never>>(false);
450
+ break;
451
+ case "passwordPolicy":
452
+ switch (error.source.name) {
453
+ case "length":
454
+ value = hasLostFocusAtLeastOnce;
455
+ break;
456
+ case "digits":
457
+ value = hasLostFocusAtLeastOnce;
458
+ break;
459
+ case "lowerCase":
460
+ value = hasLostFocusAtLeastOnce;
461
+ break;
462
+ case "upperCase":
463
+ value = hasLostFocusAtLeastOnce;
464
+ break;
465
+ case "specialChars":
466
+ value = hasLostFocusAtLeastOnce;
467
+ break;
468
+ case "notUsername":
469
+ value = true;
470
+ break;
471
+ case "notEmail":
472
+ value = true;
473
+ break;
474
+ }
475
+ // assert<Equals<typeof error.source, never>>(false);
476
+ break;
477
+ case "validator":
478
+ switch (error.source.name) {
479
+ case "length":
480
+ value = hasLostFocusAtLeastOnce;
481
+ break;
482
+ case "pattern":
483
+ value = hasLostFocusAtLeastOnce;
484
+ break;
485
+ case "email":
486
+ value = hasLostFocusAtLeastOnce;
487
+ break;
488
+ case "integer":
489
+ value = hasLostFocusAtLeastOnce;
490
+ break;
491
+ case "multivalued":
492
+ value = hasLostFocusAtLeastOnce;
493
+ break;
494
+ case "options":
495
+ value = hasLostFocusAtLeastOnce;
496
+ break;
497
+ }
498
+ // assert<Equals<typeof error.source, never>>(false);
499
+ break;
500
+ }
501
+ return value;
502
+ }),
503
+ attribute,
504
+ ...valueOrValuesWrap
505
+ })
506
+ ),
507
+ isFormSubmittable: state.formFieldStates.every(
508
+ ({ errors }) => errors.length === 0
509
+ )
510
+ };
511
+ });
512
+
513
+ constructor() {
514
+ this.loginResourceInjectorService.insertAdditionalScripts(
515
+ Object.keys(this.kcContext.profile?.html5DataAnnotations ?? {})
516
+ .filter(key => key !== "kcMultivalued" && key !== "kcNumberFormat") // NOTE: Keycloakify handles it.
517
+ .map(key => ({
518
+ type: "module",
519
+ src: `${this.kcContext.url.resourcesPath}/js/${key}.js`,
520
+ id: `${this.kcContext.url.resourcesPath}/js/${key}.js`
521
+ }))
522
+ );
523
+ }
524
+
525
+ public dispatchFormAction(formAction: FormAction) {
526
+ if (!formAction) return;
527
+ const state = this.state();
528
+ const formFieldState = state.formFieldStates.find(
529
+ ({ attribute }) => attribute.name === formAction.name
530
+ );
531
+ assert(formFieldState !== undefined);
532
+ switch (formAction.action) {
533
+ case "update":
534
+ formFieldState.valueOrValues = formAction.valueOrValues;
535
+
536
+ apply_formatters: {
537
+ const { attribute } = formFieldState;
538
+
539
+ const { kcNumberFormat } = attribute.html5DataAnnotations ?? {};
540
+
541
+ if (!kcNumberFormat) {
542
+ break apply_formatters;
543
+ }
544
+
545
+ if (formFieldState.valueOrValues instanceof Array) {
546
+ formFieldState.valueOrValues = formFieldState.valueOrValues.map(
547
+ value => formatNumber(value, kcNumberFormat)
548
+ );
549
+ } else {
550
+ formFieldState.valueOrValues = formatNumber(
551
+ formFieldState.valueOrValues,
552
+ kcNumberFormat
553
+ );
554
+ }
555
+ }
556
+
557
+ formFieldState.errors = this.getErrors({
558
+ attributeName: formAction.name,
559
+ formFieldStates: state.formFieldStates
560
+ });
561
+
562
+ simulate_focus_lost: {
563
+ const { displayErrorsImmediately = false } = formAction;
564
+
565
+ if (!displayErrorsImmediately) {
566
+ break simulate_focus_lost;
567
+ }
568
+
569
+ for (const fieldIndex of formAction.valueOrValues instanceof Array
570
+ ? formAction.valueOrValues.map((...[, index]) => index)
571
+ : [undefined]) {
572
+ this.dispatchFormAction({
573
+ action: "focus lost",
574
+ name: formAction.name,
575
+ fieldIndex
576
+ });
577
+ }
578
+ }
579
+
580
+ update_password_confirm: {
581
+ if (this.doMakeUserConfirmPassword) {
582
+ break update_password_confirm;
583
+ }
584
+
585
+ if (formAction.name !== "password") {
586
+ break update_password_confirm;
587
+ }
588
+
589
+ this.dispatchFormAction({
590
+ action: "update",
591
+ name: "password-confirm",
592
+ valueOrValues: formAction.valueOrValues,
593
+ displayErrorsImmediately: formAction.displayErrorsImmediately
594
+ });
595
+ }
596
+
597
+ trigger_password_confirm_validation_on_password_change: {
598
+ if (!this.doMakeUserConfirmPassword) {
599
+ break trigger_password_confirm_validation_on_password_change;
600
+ }
601
+
602
+ if (formAction.name !== "password") {
603
+ break trigger_password_confirm_validation_on_password_change;
604
+ }
605
+
606
+ this.dispatchFormAction({
607
+ action: "update",
608
+ name: "password-confirm",
609
+ valueOrValues: (() => {
610
+ const formFieldState = state.formFieldStates.find(
611
+ ({ attribute }) => attribute.name === "password-confirm"
612
+ );
613
+
614
+ assert(formFieldState !== undefined);
615
+
616
+ return formFieldState.valueOrValues;
617
+ })(),
618
+ displayErrorsImmediately: formAction.displayErrorsImmediately
619
+ });
620
+ }
621
+
622
+ break;
623
+ case "focus lost":
624
+ if (formFieldState.hasLostFocusAtLeastOnce instanceof Array) {
625
+ const { fieldIndex } = formAction;
626
+ assert(fieldIndex !== undefined);
627
+ formFieldState.hasLostFocusAtLeastOnce[fieldIndex] = true;
628
+ break;
629
+ }
630
+
631
+ formFieldState.hasLostFocusAtLeastOnce = true;
632
+ break;
633
+ }
634
+ this.state.update(state => ({
635
+ ...state,
636
+ formFieldStates: state.formFieldStates.map(f => {
637
+ if (f.attribute === formFieldState.attribute) return formFieldState;
638
+ return f;
639
+ })
640
+ }));
641
+ }
642
+
643
+ private getIsMultivaluedSingleField(params: { attribute: Attribute }) {
644
+ const { attribute } = params;
645
+
646
+ return attribute.annotations.inputType?.startsWith("multiselect") ?? false;
647
+ }
648
+
649
+ private getErrors(params: {
650
+ attributeName: string;
651
+ formFieldStates: {
652
+ attribute: Attribute;
653
+ valueOrValues: string | string[];
654
+ }[];
655
+ }): FormFieldError[] {
656
+ const { messagesPerField, passwordPolicies } = this.kcContext;
657
+
658
+ const { msgStr, advancedMsgStr } = this.i18n;
659
+ const { attributeName, formFieldStates } = params;
660
+
661
+ const formFieldState = formFieldStates.find(
662
+ ({ attribute }) => attribute.name === attributeName
663
+ );
664
+
665
+ assert(formFieldState !== undefined);
666
+
667
+ const { attribute } = formFieldState;
668
+
669
+ const valueOrValues = (() => {
670
+ let { valueOrValues } = formFieldState;
671
+
672
+ unFormat_number: {
673
+ const { kcNumberUnFormat } = attribute.html5DataAnnotations ?? {};
674
+
675
+ if (!kcNumberUnFormat) {
676
+ break unFormat_number;
677
+ }
678
+
679
+ if (valueOrValues instanceof Array) {
680
+ valueOrValues = valueOrValues.map(value =>
681
+ formatNumber(value, kcNumberUnFormat)
682
+ );
683
+ } else {
684
+ valueOrValues = formatNumber(valueOrValues, kcNumberUnFormat);
685
+ }
686
+ }
687
+
688
+ return valueOrValues;
689
+ })();
690
+
691
+ assert(attribute !== undefined);
692
+
693
+ server_side_error: {
694
+ if (attribute.multivalued) {
695
+ const defaultValues = attribute.values?.length ? attribute.values : [""];
696
+
697
+ assert(valueOrValues instanceof Array);
698
+
699
+ const values = valueOrValues;
700
+
701
+ if (
702
+ JSON.stringify(defaultValues) !==
703
+ JSON.stringify(values.slice(0, defaultValues.length))
704
+ ) {
705
+ break server_side_error;
706
+ }
707
+ } else {
708
+ const defaultValue = attribute.value ?? "";
709
+
710
+ assert(typeof valueOrValues === "string");
711
+
712
+ const value = valueOrValues;
713
+
714
+ if (defaultValue !== value) {
715
+ break server_side_error;
716
+ }
717
+ }
718
+
719
+ let doesErrorExist: boolean;
720
+
721
+ try {
722
+ doesErrorExist = messagesPerField.existsError(attributeName);
723
+ } catch {
724
+ break server_side_error;
725
+ }
726
+
727
+ if (!doesErrorExist) {
728
+ break server_side_error;
729
+ }
730
+
731
+ const errorMessageStr = messagesPerField.get(attributeName);
732
+
733
+ return [
734
+ {
735
+ errorMessageStr,
736
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
737
+ `<span>${errorMessageStr}</span>`
738
+ ),
739
+ fieldIndex: undefined,
740
+ source: {
741
+ type: "server"
742
+ }
743
+ }
744
+ ];
745
+ }
746
+
747
+ handle_multi_valued_multi_fields: {
748
+ if (!attribute.multivalued) {
749
+ break handle_multi_valued_multi_fields;
750
+ }
751
+
752
+ if (this.getIsMultivaluedSingleField({ attribute })) {
753
+ break handle_multi_valued_multi_fields;
754
+ }
755
+
756
+ assert(valueOrValues instanceof Array);
757
+
758
+ const values = valueOrValues;
759
+
760
+ const errors = values
761
+ .map((...[, index]) => {
762
+ const specificValueErrors = this.getErrors({
763
+ attributeName,
764
+ formFieldStates: formFieldStates.map(formFieldState => {
765
+ if (formFieldState.attribute.name === attributeName) {
766
+ assert(formFieldState.valueOrValues instanceof Array);
767
+ return {
768
+ attribute: {
769
+ ...attribute,
770
+ annotations: {
771
+ ...attribute.annotations,
772
+ inputType: undefined
773
+ },
774
+ multivalued: false
775
+ },
776
+ valueOrValues: formFieldState.valueOrValues[index]
777
+ };
778
+ }
779
+
780
+ return formFieldState;
781
+ })
782
+ });
783
+
784
+ return specificValueErrors
785
+ .filter(error => {
786
+ if (
787
+ error.source.type === "other" &&
788
+ error.source.rule === "requiredField"
789
+ ) {
790
+ return false;
791
+ }
792
+
793
+ return true;
794
+ })
795
+ .map(
796
+ (error): FormFieldError => ({
797
+ ...error,
798
+ fieldIndex: index
799
+ })
800
+ );
801
+ })
802
+ .reduce((acc, errors) => [...acc, ...errors], []);
803
+
804
+ required_field: {
805
+ if (!attribute.required) {
806
+ break required_field;
807
+ }
808
+
809
+ if (values.every(value => value !== "")) {
810
+ break required_field;
811
+ }
812
+
813
+ const msgArgs = ["error-user-attribute-required"] as const;
814
+
815
+ errors.push({
816
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
817
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
818
+ ),
819
+ errorMessageStr: msgStr(...msgArgs),
820
+ fieldIndex: undefined,
821
+ source: {
822
+ type: "other",
823
+ rule: "requiredField"
824
+ }
825
+ });
826
+ }
827
+
828
+ return errors;
829
+ }
830
+
831
+ handle_multi_valued_single_field: {
832
+ if (!attribute.multivalued) {
833
+ break handle_multi_valued_single_field;
834
+ }
835
+
836
+ if (!this.getIsMultivaluedSingleField({ attribute })) {
837
+ break handle_multi_valued_single_field;
838
+ }
839
+
840
+ const validatorName = "multivalued";
841
+
842
+ const validator = attribute.validators[validatorName];
843
+
844
+ if (validator === undefined) {
845
+ return [];
846
+ }
847
+
848
+ const { min: minStr } = validator;
849
+
850
+ const min = minStr ? parseInt(`${minStr}`) : attribute.required ? 1 : 0;
851
+
852
+ assert(!isNaN(min));
853
+
854
+ const { max: maxStr } = validator;
855
+
856
+ const max = !maxStr ? Infinity : parseInt(`${maxStr}`);
857
+
858
+ assert(!isNaN(max));
859
+
860
+ assert(valueOrValues instanceof Array);
861
+
862
+ const values = valueOrValues;
863
+
864
+ if (min <= values.length && values.length <= max) {
865
+ return [];
866
+ }
867
+
868
+ const msgArgs = [
869
+ "error-invalid-multivalued-size",
870
+ `${min}`,
871
+ `${max}`
872
+ ] as const;
873
+
874
+ return [
875
+ {
876
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
877
+ `<span data-key="0">${msgStr(...msgArgs)}</span>`
878
+ ),
879
+ errorMessageStr: msgStr(...msgArgs),
880
+ fieldIndex: undefined,
881
+ source: {
882
+ type: "validator",
883
+ name: validatorName
884
+ }
885
+ }
886
+ ];
887
+ }
888
+
889
+ assert(typeof valueOrValues === "string");
890
+
891
+ const value = valueOrValues;
892
+
893
+ const errors: FormFieldError[] = [];
894
+
895
+ check_password_policies: {
896
+ if (attributeName !== "password") {
897
+ break check_password_policies;
898
+ }
899
+
900
+ if (passwordPolicies === undefined) {
901
+ break check_password_policies;
902
+ }
903
+
904
+ check_password_policy_x: {
905
+ const policyName = "length";
906
+
907
+ const policy = passwordPolicies[policyName];
908
+
909
+ if (!policy) {
910
+ break check_password_policy_x;
911
+ }
912
+
913
+ const minLength = policy;
914
+
915
+ if (value.length >= minLength) {
916
+ break check_password_policy_x;
917
+ }
918
+
919
+ const msgArgs = [
920
+ "invalidPasswordMinLengthMessage",
921
+ `${minLength}`
922
+ ] as const;
923
+
924
+ errors.push({
925
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
926
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
927
+ ),
928
+ errorMessageStr: msgStr(...msgArgs),
929
+ fieldIndex: undefined,
930
+ source: {
931
+ type: "passwordPolicy",
932
+ name: policyName
933
+ }
934
+ });
935
+ }
936
+
937
+ check_password_policy_x: {
938
+ const policyName = "digits";
939
+
940
+ const policy = passwordPolicies[policyName];
941
+
942
+ if (!policy) {
943
+ break check_password_policy_x;
944
+ }
945
+
946
+ const minNumberOfDigits = policy;
947
+
948
+ if (
949
+ value.split("").filter(char => !isNaN(parseInt(char))).length >=
950
+ minNumberOfDigits
951
+ ) {
952
+ break check_password_policy_x;
953
+ }
954
+
955
+ const msgArgs = [
956
+ "invalidPasswordMinDigitsMessage",
957
+ `${minNumberOfDigits}`
958
+ ] as const;
959
+
960
+ errors.push({
961
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
962
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
963
+ ),
964
+ errorMessageStr: msgStr(...msgArgs),
965
+ fieldIndex: undefined,
966
+ source: {
967
+ type: "passwordPolicy",
968
+ name: policyName
969
+ }
970
+ });
971
+ }
972
+
973
+ check_password_policy_x: {
974
+ const policyName = "lowerCase";
975
+
976
+ const policy = passwordPolicies[policyName];
977
+
978
+ if (!policy) {
979
+ break check_password_policy_x;
980
+ }
981
+
982
+ const minNumberOfLowerCaseChar = policy;
983
+
984
+ if (
985
+ value
986
+ .split("")
987
+ .filter(
988
+ char =>
989
+ char === char.toLowerCase() && char !== char.toUpperCase()
990
+ ).length >= minNumberOfLowerCaseChar
991
+ ) {
992
+ break check_password_policy_x;
993
+ }
994
+
995
+ const msgArgs = [
996
+ "invalidPasswordMinLowerCaseCharsMessage",
997
+ `${minNumberOfLowerCaseChar}`
998
+ ] as const;
999
+
1000
+ errors.push({
1001
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1002
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1003
+ ),
1004
+ errorMessageStr: msgStr(...msgArgs),
1005
+ fieldIndex: undefined,
1006
+ source: {
1007
+ type: "passwordPolicy",
1008
+ name: policyName
1009
+ }
1010
+ });
1011
+ }
1012
+
1013
+ check_password_policy_x: {
1014
+ const policyName = "upperCase";
1015
+
1016
+ const policy = passwordPolicies[policyName];
1017
+
1018
+ if (!policy) {
1019
+ break check_password_policy_x;
1020
+ }
1021
+
1022
+ const minNumberOfUpperCaseChar = policy;
1023
+
1024
+ if (
1025
+ value
1026
+ .split("")
1027
+ .filter(
1028
+ char =>
1029
+ char === char.toUpperCase() && char !== char.toLowerCase()
1030
+ ).length >= minNumberOfUpperCaseChar
1031
+ ) {
1032
+ break check_password_policy_x;
1033
+ }
1034
+
1035
+ const msgArgs = [
1036
+ "invalidPasswordMinUpperCaseCharsMessage",
1037
+ `${minNumberOfUpperCaseChar}`
1038
+ ] as const;
1039
+
1040
+ errors.push({
1041
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1042
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1043
+ ),
1044
+ errorMessageStr: msgStr(...msgArgs),
1045
+ fieldIndex: undefined,
1046
+ source: {
1047
+ type: "passwordPolicy",
1048
+ name: policyName
1049
+ }
1050
+ });
1051
+ }
1052
+
1053
+ check_password_policy_x: {
1054
+ const policyName = "specialChars";
1055
+
1056
+ const policy = passwordPolicies[policyName];
1057
+
1058
+ if (!policy) {
1059
+ break check_password_policy_x;
1060
+ }
1061
+
1062
+ const minNumberOfSpecialChar = policy;
1063
+
1064
+ if (
1065
+ value.split("").filter(char => !char.match(/[a-zA-Z0-9]/)).length >=
1066
+ minNumberOfSpecialChar
1067
+ ) {
1068
+ break check_password_policy_x;
1069
+ }
1070
+
1071
+ const msgArgs = [
1072
+ "invalidPasswordMinSpecialCharsMessage",
1073
+ `${minNumberOfSpecialChar}`
1074
+ ] as const;
1075
+
1076
+ errors.push({
1077
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1078
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1079
+ ),
1080
+ errorMessageStr: msgStr(...msgArgs),
1081
+ fieldIndex: undefined,
1082
+ source: {
1083
+ type: "passwordPolicy",
1084
+ name: policyName
1085
+ }
1086
+ });
1087
+ }
1088
+
1089
+ check_password_policy_x: {
1090
+ const policyName = "notUsername";
1091
+
1092
+ const notUsername = passwordPolicies[policyName];
1093
+
1094
+ if (!notUsername) {
1095
+ break check_password_policy_x;
1096
+ }
1097
+
1098
+ const usernameFormFieldState = formFieldStates.find(
1099
+ formFieldState => formFieldState.attribute.name === "username"
1100
+ );
1101
+
1102
+ if (!usernameFormFieldState) {
1103
+ break check_password_policy_x;
1104
+ }
1105
+
1106
+ const usernameValue = (() => {
1107
+ let { valueOrValues } = usernameFormFieldState;
1108
+
1109
+ assert(typeof valueOrValues === "string");
1110
+
1111
+ unFormat_number: {
1112
+ const { kcNumberUnFormat } = attribute.html5DataAnnotations ?? {};
1113
+
1114
+ if (!kcNumberUnFormat) {
1115
+ break unFormat_number;
1116
+ }
1117
+
1118
+ valueOrValues = formatNumber(valueOrValues, kcNumberUnFormat);
1119
+ }
1120
+
1121
+ return valueOrValues;
1122
+ })();
1123
+
1124
+ if (usernameValue === "") {
1125
+ break check_password_policy_x;
1126
+ }
1127
+
1128
+ if (value !== usernameValue) {
1129
+ break check_password_policy_x;
1130
+ }
1131
+
1132
+ const msgArgs = ["invalidPasswordNotUsernameMessage"] as const;
1133
+
1134
+ errors.push({
1135
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1136
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1137
+ ),
1138
+ errorMessageStr: msgStr(...msgArgs),
1139
+ fieldIndex: undefined,
1140
+ source: {
1141
+ type: "passwordPolicy",
1142
+ name: policyName
1143
+ }
1144
+ });
1145
+ }
1146
+
1147
+ check_password_policy_x: {
1148
+ const policyName = "notEmail";
1149
+
1150
+ const notEmail = passwordPolicies[policyName];
1151
+
1152
+ if (!notEmail) {
1153
+ break check_password_policy_x;
1154
+ }
1155
+
1156
+ const emailFormFieldState = formFieldStates.find(
1157
+ formFieldState => formFieldState.attribute.name === "email"
1158
+ );
1159
+
1160
+ if (!emailFormFieldState) {
1161
+ break check_password_policy_x;
1162
+ }
1163
+
1164
+ assert(typeof emailFormFieldState.valueOrValues === "string");
1165
+
1166
+ {
1167
+ const emailValue = emailFormFieldState.valueOrValues;
1168
+
1169
+ if (emailValue === "") {
1170
+ break check_password_policy_x;
1171
+ }
1172
+
1173
+ if (value !== emailValue) {
1174
+ break check_password_policy_x;
1175
+ }
1176
+ }
1177
+
1178
+ const msgArgs = ["invalidPasswordNotEmailMessage"] as const;
1179
+
1180
+ errors.push({
1181
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1182
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1183
+ ),
1184
+ errorMessageStr: msgStr(...msgArgs),
1185
+ fieldIndex: undefined,
1186
+ source: {
1187
+ type: "passwordPolicy",
1188
+ name: policyName
1189
+ }
1190
+ });
1191
+ }
1192
+ }
1193
+
1194
+ password_confirm_matches_password: {
1195
+ if (attributeName !== "password-confirm") {
1196
+ break password_confirm_matches_password;
1197
+ }
1198
+
1199
+ const passwordFormFieldState = formFieldStates.find(
1200
+ formFieldState => formFieldState.attribute.name === "password"
1201
+ );
1202
+
1203
+ assert(passwordFormFieldState !== undefined);
1204
+
1205
+ assert(typeof passwordFormFieldState.valueOrValues === "string");
1206
+
1207
+ {
1208
+ const passwordValue = passwordFormFieldState.valueOrValues;
1209
+
1210
+ if (value === passwordValue) {
1211
+ break password_confirm_matches_password;
1212
+ }
1213
+ }
1214
+
1215
+ const msgArgs = ["invalidPasswordConfirmMessage"] as const;
1216
+
1217
+ errors.push({
1218
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1219
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1220
+ ),
1221
+ errorMessageStr: msgStr(...msgArgs),
1222
+ fieldIndex: undefined,
1223
+ source: {
1224
+ type: "other",
1225
+ rule: "passwordConfirmMatchesPassword"
1226
+ }
1227
+ });
1228
+ }
1229
+
1230
+ const { validators } = attribute;
1231
+
1232
+ required_field: {
1233
+ if (!attribute.required) {
1234
+ break required_field;
1235
+ }
1236
+
1237
+ if (value !== "") {
1238
+ break required_field;
1239
+ }
1240
+
1241
+ const msgArgs = ["error-user-attribute-required"] as const;
1242
+
1243
+ errors.push({
1244
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1245
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1246
+ ),
1247
+ errorMessageStr: msgStr(...msgArgs),
1248
+ fieldIndex: undefined,
1249
+ source: {
1250
+ type: "other",
1251
+ rule: "requiredField"
1252
+ }
1253
+ });
1254
+ }
1255
+
1256
+ validator_x: {
1257
+ const validatorName = "length";
1258
+
1259
+ const validator = validators[validatorName];
1260
+
1261
+ if (!validator) {
1262
+ break validator_x;
1263
+ }
1264
+
1265
+ const {
1266
+ "ignore.empty.value": ignoreEmptyValue = false,
1267
+ max,
1268
+ min
1269
+ } = validator;
1270
+
1271
+ if (ignoreEmptyValue && value === "") {
1272
+ break validator_x;
1273
+ }
1274
+
1275
+ const source: FormFieldError.Source = {
1276
+ type: "validator",
1277
+ name: validatorName
1278
+ };
1279
+
1280
+ if (max && value.length > parseInt(`${max}`)) {
1281
+ const msgArgs = ["error-invalid-length-too-long", `${max}`] as const;
1282
+
1283
+ errors.push({
1284
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1285
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1286
+ ),
1287
+ errorMessageStr: msgStr(...msgArgs),
1288
+ fieldIndex: undefined,
1289
+ source
1290
+ });
1291
+ }
1292
+
1293
+ if (min && value.length < parseInt(`${min}`)) {
1294
+ const msgArgs = ["error-invalid-length-too-short", `${min}`] as const;
1295
+
1296
+ errors.push({
1297
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1298
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1299
+ ),
1300
+ errorMessageStr: msgStr(...msgArgs),
1301
+ fieldIndex: undefined,
1302
+ source
1303
+ });
1304
+ }
1305
+ }
1306
+
1307
+ validator_x: {
1308
+ const validatorName = "pattern";
1309
+
1310
+ const validator = validators[validatorName];
1311
+
1312
+ if (validator === undefined) {
1313
+ break validator_x;
1314
+ }
1315
+
1316
+ const {
1317
+ "ignore.empty.value": ignoreEmptyValue = false,
1318
+ pattern,
1319
+ "error-message": errorMessageKey
1320
+ } = validator;
1321
+
1322
+ if (ignoreEmptyValue && value === "") {
1323
+ break validator_x;
1324
+ }
1325
+
1326
+ if (new RegExp(pattern).test(value)) {
1327
+ break validator_x;
1328
+ }
1329
+
1330
+ const msgArgs = [
1331
+ errorMessageKey ?? id<MessageKey_defaultSet>("shouldMatchPattern"),
1332
+ pattern
1333
+ ] as const;
1334
+
1335
+ errors.push({
1336
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1337
+ `<span data-key="${attributeName}-${errors.length}">${advancedMsgStr(...msgArgs)}</span>`
1338
+ ),
1339
+ errorMessageStr: advancedMsgStr(...msgArgs),
1340
+ fieldIndex: undefined,
1341
+ source: {
1342
+ type: "validator",
1343
+ name: validatorName
1344
+ }
1345
+ });
1346
+ }
1347
+
1348
+ validator_x: {
1349
+ {
1350
+ const lastError = errors[errors.length - 1];
1351
+ if (
1352
+ lastError !== undefined &&
1353
+ lastError.source.type === "validator" &&
1354
+ lastError.source.name === "pattern"
1355
+ ) {
1356
+ break validator_x;
1357
+ }
1358
+ }
1359
+
1360
+ const validatorName = "email";
1361
+
1362
+ const validator = validators[validatorName];
1363
+
1364
+ if (validator === undefined) {
1365
+ break validator_x;
1366
+ }
1367
+
1368
+ const { "ignore.empty.value": ignoreEmptyValue = false } = validator;
1369
+
1370
+ if (ignoreEmptyValue && value === "") {
1371
+ break validator_x;
1372
+ }
1373
+
1374
+ if (emailRegexp.test(value)) {
1375
+ break validator_x;
1376
+ }
1377
+
1378
+ const msgArgs = [id<MessageKey_defaultSet>("invalidEmailMessage")] as const;
1379
+
1380
+ errors.push({
1381
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1382
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1383
+ ),
1384
+ errorMessageStr: msgStr(...msgArgs),
1385
+ fieldIndex: undefined,
1386
+ source: {
1387
+ type: "validator",
1388
+ name: validatorName
1389
+ }
1390
+ });
1391
+ }
1392
+
1393
+ validator_x: {
1394
+ const validatorName = "integer";
1395
+
1396
+ const validator = validators[validatorName];
1397
+
1398
+ if (validator === undefined) {
1399
+ break validator_x;
1400
+ }
1401
+
1402
+ const {
1403
+ "ignore.empty.value": ignoreEmptyValue = false,
1404
+ max,
1405
+ min
1406
+ } = validator;
1407
+
1408
+ if (ignoreEmptyValue && value === "") {
1409
+ break validator_x;
1410
+ }
1411
+
1412
+ const intValue = parseInt(value);
1413
+
1414
+ const source: FormFieldError.Source = {
1415
+ type: "validator",
1416
+ name: validatorName
1417
+ };
1418
+
1419
+ if (isNaN(intValue)) {
1420
+ const msgArgs = ["mustBeAnInteger"] as const;
1421
+
1422
+ errors.push({
1423
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1424
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1425
+ ),
1426
+ errorMessageStr: msgStr(...msgArgs),
1427
+ fieldIndex: undefined,
1428
+ source
1429
+ });
1430
+
1431
+ break validator_x;
1432
+ }
1433
+
1434
+ if (max && intValue > parseInt(`${max}`)) {
1435
+ const msgArgs = ["error-number-out-of-range-too-big", `${max}`] as const;
1436
+
1437
+ errors.push({
1438
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1439
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1440
+ ),
1441
+ errorMessageStr: msgStr(...msgArgs),
1442
+ fieldIndex: undefined,
1443
+ source
1444
+ });
1445
+
1446
+ break validator_x;
1447
+ }
1448
+
1449
+ if (min && intValue < parseInt(`${min}`)) {
1450
+ const msgArgs = [
1451
+ "error-number-out-of-range-too-small",
1452
+ `${min}`
1453
+ ] as const;
1454
+
1455
+ errors.push({
1456
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1457
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1458
+ ),
1459
+ errorMessageStr: msgStr(...msgArgs),
1460
+ fieldIndex: undefined,
1461
+ source
1462
+ });
1463
+
1464
+ break validator_x;
1465
+ }
1466
+ }
1467
+
1468
+ validator_x: {
1469
+ const validatorName = "options";
1470
+
1471
+ const validator = validators[validatorName];
1472
+
1473
+ if (validator === undefined) {
1474
+ break validator_x;
1475
+ }
1476
+
1477
+ if (value === "") {
1478
+ break validator_x;
1479
+ }
1480
+
1481
+ if (validator.options.indexOf(value) >= 0) {
1482
+ break validator_x;
1483
+ }
1484
+
1485
+ const msgArgs = [id<MessageKey_defaultSet>("notAValidOption")] as const;
1486
+
1487
+ errors.push({
1488
+ errorMessage: this.sanitizer.bypassSecurityTrustHtml(
1489
+ `<span data-key="${attributeName}-${errors.length}">${msgStr(...msgArgs)}</span>`
1490
+ ),
1491
+ errorMessageStr: msgStr(...msgArgs),
1492
+ fieldIndex: undefined,
1493
+ source: {
1494
+ type: "validator",
1495
+ name: validatorName
1496
+ }
1497
+ });
1498
+ }
1499
+
1500
+ //TODO: Implement missing validators. See Validators type definition.
1501
+
1502
+ return errors;
1503
+ }
1504
+ }