Updates
1
1413.d9e52d4c.iframe.bundle.js
Normal file
1
2140.4e19e997.iframe.bundle.js
Normal file
1
2370.19aba2fd.iframe.bundle.js
Normal file
1
2977.720fa7c3.iframe.bundle.js
Normal file
1
3008.8610ce22.iframe.bundle.js
Normal file
1
3875.fb32e60a.iframe.bundle.js
Normal file
1
4062.091bd493.iframe.bundle.js
Normal file
1
4415.fc4ed6d8.iframe.bundle.js
Normal file
1
4774.337d2f43.iframe.bundle.js
Normal file
1
5119.9b2de070.iframe.bundle.js
Normal file
1
5749.43f2f1af.iframe.bundle.js
Normal file
1
7371.1fe2cdcf.iframe.bundle.js
Normal file
1
7699.c1d5ac79.iframe.bundle.js
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunkkeycloakify=self.webpackChunkkeycloakify||[]).push([[7699],{"./dist/login/pages/LoginIdpLinkConfirmOverride.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{default:()=>LoginIdpLinkConfirmOverride});__webpack_require__("./node_modules/core-js/modules/es.object.assign.js");var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__("./node_modules/react/jsx-runtime.js"),_login_lib_kcClsx__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__("./dist/login/lib/kcClsx.js");function LoginIdpLinkConfirmOverride(props){var kcContext=props.kcContext,i18n=props.i18n,doUseDefaultCss=props.doUseDefaultCss,Template=props.Template,classes=props.classes,kcClsx=(0,_login_lib_kcClsx__WEBPACK_IMPORTED_MODULE_2__.$)({doUseDefaultCss,classes}).kcClsx,url=kcContext.url,idpDisplayName=kcContext.idpDisplayName,msg=i18n.msg;return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(Template,Object.assign({kcContext,i18n,doUseDefaultCss,classes,headerNode:msg("confirmOverrideIdpTitle")},{children:(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("form",Object.assign({id:"kc-register-form",action:url.loginAction,method:"post"},{children:[msg("pageExpiredMsg1")," ",(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("a",Object.assign({id:"loginRestartLink",href:url.loginRestartFlowUrl},{children:msg("doClickHere")})),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("br",{}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("br",{}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("button",Object.assign({type:"submit",className:kcClsx("kcButtonClass","kcButtonDefaultClass","kcButtonBlockClass","kcButtonLargeClass"),name:"submitAction",id:"confirmOverride",value:"confirmOverride"},{children:msg("confirmOverrideIdpContinue",idpDisplayName)}))]}))}))}}}]);
|
1
8318.01320622.iframe.bundle.js
Normal file
1
8394.3c085db7.iframe.bundle.js
Normal file
1
8837.588afa85.iframe.bundle.js
Normal file
1
9286.50cdbc42.iframe.bundle.js
Normal file
1
9353.655ed18c.iframe.bundle.js
Normal file
1
9790.1ac482eb.iframe.bundle.js
Normal file
@ -375,4 +375,4 @@
|
||||
|
||||
|
||||
|
||||
window['STORIES'] = [{"titlePrefix":"","directory":"./stories","files":"**/*.stories.tsx","importPathMatcher":"^\\.[\\\\/](?:stories(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.tsx)$"}];</script><script src="runtime~main.efb2bdea.iframe.bundle.js"></script><script src="3264.5bd4f49b.iframe.bundle.js"></script><script src="main.dd12b67b.iframe.bundle.js"></script></body></html>
|
||||
window['STORIES'] = [{"titlePrefix":"","directory":"./stories","files":"**/*.stories.tsx","importPathMatcher":"^\\.[\\\\/](?:stories(?:\\/(?!\\.)(?:(?:(?!(?:^|\\/)\\.).)*?)\\/|\\/|$)(?!\\.)(?=.)[^/]*?\\.stories\\.tsx)$"}];</script><script src="runtime~main.6ebe0eec.iframe.bundle.js"></script><script src="3264.5bd4f49b.iframe.bundle.js"></script><script src="main.d5392dfe.iframe.bundle.js"></script></body></html>
|
@ -1,2 +0,0 @@
|
||||
This is just a test folder that helps develop the login and register page without having to run a Keycloak container
|
||||
This directory will be automatically excluded from the final build.
|
@ -1,277 +0,0 @@
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #F9F9F9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
header .navbar {
|
||||
margin-bottom: 0;
|
||||
min-height: inherit;
|
||||
}
|
||||
|
||||
.header .container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-title {
|
||||
background-image: url('../img/logo.png');
|
||||
height: 25px;
|
||||
background-repeat: no-repeat;
|
||||
width: 123px;
|
||||
margin: 3px 10px 5px;
|
||||
text-indent: -99999px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility {
|
||||
right: 20px;
|
||||
top: -34px !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility > li > a {
|
||||
color: #fff !important;
|
||||
padding-bottom: 12px;
|
||||
padding-top: 11px;
|
||||
border-left: medium none;
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
background-color: #fff;
|
||||
border-color: #CECECE;
|
||||
border-style: solid;
|
||||
border-width: 0 1px;
|
||||
height: 100%;
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.margin-bottom {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
|
||||
.bs-sidebar {
|
||||
background-color: #f9f9f9;
|
||||
padding-top: 44px;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
.bs-sidebar ul {
|
||||
list-style: none;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.bs-sidebar ul li {
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
.bs-sidebar ul li a {
|
||||
font-size: 14px;
|
||||
padding-left: 25px;
|
||||
color: #4d5258;
|
||||
line-height: 28px;
|
||||
display: block;
|
||||
border-width: 1px 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: #f9f9f9;
|
||||
}
|
||||
.bs-sidebar ul li a:hover,
|
||||
.bs-sidebar ul li a:focus {
|
||||
text-decoration: none;
|
||||
color: #777777;
|
||||
border-right: 2px solid #aaa;
|
||||
}
|
||||
.bs-sidebar ul li.active a {
|
||||
background-color: #c7e5f0;
|
||||
border-color: #56bae0;
|
||||
font-weight: bold;
|
||||
background-image: url(../img/icon-sidebar-active.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.bs-sidebar ul li.active a:hover {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
|
||||
.content-area h2 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 100;
|
||||
font-size: 24px;
|
||||
margin-bottom: 25px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #CB2915;
|
||||
}
|
||||
|
||||
|
||||
.alert {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.feedback-aligner .alert {
|
||||
background-position: 1.27273em center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 2px;
|
||||
border-width: 1px;
|
||||
color: #4D5258;
|
||||
display: inline-block;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.4em;
|
||||
margin: 0;
|
||||
padding: 0.909091em 3.63636em;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
}
|
||||
.alert.alert-success {
|
||||
background-color: #E4F1E1;
|
||||
border-color: #4B9E39;
|
||||
}
|
||||
.alert.alert-error {
|
||||
background-color: #F8E7E7;
|
||||
border-color: #B91415;
|
||||
}
|
||||
.alert.alert-warning {
|
||||
background-color: #FEF1E9;
|
||||
border-color: #F17528;
|
||||
}
|
||||
.alert.alert-info {
|
||||
background-color: #E4F3FA;
|
||||
border-color: #5994B2;
|
||||
}
|
||||
|
||||
.form-horizontal {
|
||||
border-top: 1px solid #E9E8E8;
|
||||
padding-top: 23px;
|
||||
}
|
||||
|
||||
.form-horizontal .control-label {
|
||||
color: #909090;
|
||||
line-height: 1.4em;
|
||||
padding-top: 5px;
|
||||
position: relative;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.control-label + .required {
|
||||
position: absolute;
|
||||
right: -2px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#kc-form-buttons {
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#kc-form-buttons .btn-primary {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Authenticator page */
|
||||
|
||||
ol {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ol li {
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ol li img {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
hr + .form-horizontal {
|
||||
border: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.kc-dropdown{
|
||||
position: relative;
|
||||
}
|
||||
.kc-dropdown > a{
|
||||
display:block;
|
||||
padding: 11px 10px 12px;
|
||||
line-height: 12px;
|
||||
font-size: 12px;
|
||||
color: #fff !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
.kc-dropdown > a::after{
|
||||
content: "\2c5";
|
||||
margin-left: 4px;
|
||||
}
|
||||
.kc-dropdown:hover > a{
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
.kc-dropdown ul li a{
|
||||
padding: 1px 11px;
|
||||
font-size: 12px;
|
||||
color: #000 !important;
|
||||
border: 1px solid #fff;
|
||||
text-decoration: none;
|
||||
display:block;
|
||||
line-height: 20px;
|
||||
}
|
||||
.kc-dropdown ul li a:hover{
|
||||
color: #4d5258;
|
||||
background-color: #d4edfa;
|
||||
border-color: #b3d3e7;
|
||||
}
|
||||
.kc-dropdown ul{
|
||||
position: absolute;
|
||||
z-index: 2000;
|
||||
list-style:none;
|
||||
display:none;
|
||||
padding: 5px 0px;
|
||||
margin: 0px;
|
||||
background-color: #fff !important;
|
||||
border: 1px solid #b6b6b6;
|
||||
border-radius: 1px;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
background-clip: padding-box;
|
||||
min-width: 100px;
|
||||
}
|
||||
.kc-dropdown:hover ul{
|
||||
display:block;
|
||||
}
|
||||
|
||||
|
||||
#kc-totp-secret-key {
|
||||
border: 1px solid #eee;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
margin: 50px 0;
|
||||
}
|
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 627 B |
@ -1,11 +0,0 @@
|
||||
{
|
||||
"destDirPath": "/home/runner/work/keycloakify/keycloakify/.storybook/static/keycloak-resources",
|
||||
"keycloakifyVersion": "10.0.6",
|
||||
"buildContext": {
|
||||
"loginThemeResourcesFromKeycloakVersion": "10.0.6",
|
||||
"cacheDirPath": "../../../node_modules/.cache/scripts",
|
||||
"fetchOptions": {
|
||||
"strictSSL": false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,629 +0,0 @@
|
||||
/* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class.
|
||||
This clashes with the "keycloak-bg.png' background defined on the body below.
|
||||
Therefore the Patternfly background must be set to none. */
|
||||
.login-pf {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.login-pf body {
|
||||
background: url("../img/keycloak-bg.png") no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
textarea.pf-c-form-control {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.pf-c-alert__title {
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
}
|
||||
|
||||
p.instruction {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-control {
|
||||
border-color: rgba(230, 230, 230, 0.5);
|
||||
}
|
||||
|
||||
h1#kc-page-title {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#kc-locale ul {
|
||||
background-color: var(--pf-global--BackgroundColor--100);
|
||||
display: none;
|
||||
top: 20px;
|
||||
min-width: 100px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown:hover ul {
|
||||
display:block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown a {
|
||||
color: var(--pf-global--Color--200);
|
||||
text-align: right;
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
#kc-locale-dropdown button {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
color: var(--pf-global--Color--200);
|
||||
text-align: right;
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
button#kc-current-locale-link::after {
|
||||
content: "\2c5";
|
||||
margin-left: var(--pf-global--spacer--xs)
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.login-pf a:hover {
|
||||
color: #0099d3;
|
||||
}
|
||||
|
||||
#kc-logo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
background-image: url(../img/keycloak-logo-text.png);
|
||||
background-repeat: no-repeat;
|
||||
height: 63px;
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
div.kc-logo-text span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
color: #ededed;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 29px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 3px;
|
||||
line-height: 1.2em;
|
||||
padding: 62px 10px 20px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
#kc-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-attempted-username {
|
||||
font-size: 20px;
|
||||
font-family: inherit;
|
||||
font-weight: normal;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#kc-username {
|
||||
text-align: center;
|
||||
margin-bottom:-10px;
|
||||
}
|
||||
|
||||
#kc-webauthn-settings-form {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-parent {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-desc {
|
||||
color: var(--pf-global--palette--black-600);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-headline {
|
||||
color: var(--pf-global--Color--300);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon {
|
||||
flex: 0 0 3em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties {
|
||||
margin-top: 10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .pf-l-stack__item {
|
||||
margin: -1px 0;
|
||||
}
|
||||
|
||||
#kc-content-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#kc-form-wrapper {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#kc-info {
|
||||
margin: 20px -40px -30px;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
font-size: 13px;
|
||||
padding: 15px 35px;
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
#kc-form-options span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#kc-form-options .checkbox {
|
||||
margin-top: 0;
|
||||
color: #72767b;
|
||||
}
|
||||
|
||||
#kc-terms-text {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#kc-registration-terms-text {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#kc-registration {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* TOTP */
|
||||
|
||||
.subtitle {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--pf-global--danger-color--200);
|
||||
}
|
||||
|
||||
ol#kc-totp-settings {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul#kc-totp-supported-apps {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-qr-code {
|
||||
max-width:150px;
|
||||
max-height:150px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-key {
|
||||
background-color: #fff;
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* OAuth */
|
||||
|
||||
#kc-oauth h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 12px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth .kc-role {
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
#kc-code textarea {
|
||||
width: 100%;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
/* Social */
|
||||
.kc-social-links {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.kc-social-links li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.kc-social-provider-logo {
|
||||
font-size: 23px;
|
||||
width: 30px;
|
||||
height: 25px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.kc-social-gray {
|
||||
color: var(--pf-global--Color--200);
|
||||
}
|
||||
|
||||
.kc-social-gray h2 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.kc-social-item {
|
||||
margin-bottom: var(--pf-global--spacer--sm);
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-provider-name {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
display:grid;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 5px;
|
||||
grid-column-end: span 6;
|
||||
--pf-l-grid__item--GridColumnEnd: span 6;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
.kc-login-tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.kc-social-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-section hr{
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.kc-login-tooltip .kc-tooltip-text{
|
||||
top:-3px;
|
||||
left:160%;
|
||||
background-color: black;
|
||||
visibility: hidden;
|
||||
color: #fff;
|
||||
|
||||
min-width:130px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-shadow:0 1px 8px rgba(0,0,0,0.6);
|
||||
padding: 5px;
|
||||
|
||||
position: absolute;
|
||||
opacity:0;
|
||||
transition:opacity 0.5s;
|
||||
}
|
||||
|
||||
/* Show tooltip */
|
||||
.kc-login-tooltip:hover .kc-tooltip-text {
|
||||
visibility: visible;
|
||||
opacity:0.7;
|
||||
}
|
||||
|
||||
/* Arrow for tooltip */
|
||||
.kc-login-tooltip .kc-tooltip-text::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 100%;
|
||||
margin-top: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent black transparent transparent;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#kc-container-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-right: 80px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: relative;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.login-pf body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
float: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 20px 60px 0 0;
|
||||
color: #72767b;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
margin: 0;
|
||||
width: 150px;
|
||||
height: 32px;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
#kc-form {
|
||||
float: none;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 646px) {
|
||||
#kc-container-wrapper {
|
||||
bottom: 12%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 645px) {
|
||||
#kc-container-wrapper {
|
||||
padding-top: 50px;
|
||||
top: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-pf form.form-actions .btn {
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#kc-form-buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-brand {
|
||||
margin-top: 20px;
|
||||
max-width: 360px;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.select-auth-box-arrow{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.select-auth-box-icon{
|
||||
display: flex;
|
||||
flex: 0 0 2em;
|
||||
justify-content: center;
|
||||
margin-right: 1rem;
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.select-auth-box-parent{
|
||||
border-top: 1px solid var(--pf-global--palette--black-200);
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
align-items: unset;
|
||||
background-color: unset;
|
||||
border-right: unset;
|
||||
border-bottom: unset;
|
||||
border-left: unset;
|
||||
}
|
||||
|
||||
.select-auth-box-parent:hover{
|
||||
background-color: #f7f8f8;
|
||||
}
|
||||
|
||||
.select-auth-container {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.select-auth-box-headline {
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
color: var(--pf-global--primary-color--100);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-auth-box-desc {
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
.select-auth-box-paragraph {
|
||||
text-align: center;
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.card-pf {
|
||||
margin: 0 auto;
|
||||
box-shadow: var(--pf-global--BoxShadow--lg);
|
||||
padding: 0 20px;
|
||||
max-width: 500px;
|
||||
border-top: 4px solid;
|
||||
border-color: var(--pf-global--primary-color--100);
|
||||
}
|
||||
|
||||
/*phone*/
|
||||
@media (max-width: 767px) {
|
||||
.login-pf-page .card-pf {
|
||||
max-width: none;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding-top: 0;
|
||||
border-top: 0;
|
||||
box-shadow: 0 0;
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
grid-column-end: 12;
|
||||
--pf-l-grid__item--GridColumnEnd: span 12;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-signup {
|
||||
font-size: 15px;
|
||||
color: #72767b;
|
||||
}
|
||||
#kc-content-wrapper .row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.login-pf-page.login-pf-page-accounts {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.login-pf-page .btn-primary {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf .list-group-item {
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf-description {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-form-login div.form-group:last-of-type,
|
||||
#kc-register-form div.form-group:last-of-type,
|
||||
#kc-update-profile-form div.form-group:last-of-type,
|
||||
#kc-update-email-form div.form-group:last-of-type{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.no-bottom-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#kc-back {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Recovery codes */
|
||||
.kc-recovery-codes-warning {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.kc-recovery-codes-warning .pf-c-alert__description p {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.kc-recovery-codes-list {
|
||||
list-style: none;
|
||||
columns: 2;
|
||||
margin: 16px 0;
|
||||
padding: 16px 16px 8px 16px;
|
||||
border: 1px solid #D2D2D2;
|
||||
}
|
||||
.kc-recovery-codes-list li {
|
||||
margin-bottom: 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.kc-recovery-codes-list li span {
|
||||
color: #6A6E73;
|
||||
width: 16px;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-actions {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.kc-recovery-codes-actions button {
|
||||
padding-left: 0;
|
||||
}
|
||||
.kc-recovery-codes-actions button i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-confirmation {
|
||||
align-items: baseline;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#certificate_subjectDN {
|
||||
overflow-wrap: break-word
|
||||
}
|
||||
/* End Recovery codes */
|
Before Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 410 B |
Before Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 646 B |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 5.2 KiB |
@ -1,74 +0,0 @@
|
||||
const CHECK_INTERVAL_MILLISECS = 2000;
|
||||
const initialSession = getSession();
|
||||
|
||||
export function checkCookiesAndSetTimer(authSessionId, tabId, loginRestartUrl) {
|
||||
if (initialSession) {
|
||||
// We started with a session, so there is nothing to do, exit.
|
||||
return;
|
||||
}
|
||||
|
||||
const session = getSession();
|
||||
|
||||
if (!session) {
|
||||
// The session is not present, check again later.
|
||||
setTimeout(
|
||||
() => checkCookiesAndSetTimer(authSessionId, tabId, loginRestartUrl),
|
||||
CHECK_INTERVAL_MILLISECS
|
||||
);
|
||||
} else {
|
||||
// The session is present, check the auth state.
|
||||
checkAuthState(authSessionId, tabId, loginRestartUrl);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAuthState(authSessionId, tabId, loginRestartUrl) {
|
||||
const authStateRaw = getAuthState();
|
||||
|
||||
if (!authStateRaw) {
|
||||
// The auth state is not present, exit.
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to parse the auth state as JSON.
|
||||
let authState;
|
||||
try {
|
||||
authState = JSON.parse(decodeURIComponent(authStateRaw));
|
||||
} catch (error) {
|
||||
// The auth state is not valid JSON, exit.
|
||||
return;
|
||||
}
|
||||
|
||||
if (authState.authSessionId !== authSessionId) {
|
||||
// The session ID does not match, exit.
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!Array.isArray(authState.remainingTabs) ||
|
||||
!authState.remainingTabs.includes(tabId)
|
||||
) {
|
||||
// The remaining tabs don't include the provided tab ID, exit.
|
||||
return;
|
||||
}
|
||||
|
||||
// We made it this far, redirect to the login restart URL.
|
||||
location.href = loginRestartUrl;
|
||||
}
|
||||
|
||||
function getSession() {
|
||||
return getCookieByName("KEYCLOAK_SESSION");
|
||||
}
|
||||
|
||||
function getAuthState() {
|
||||
return getCookieByName("KC_AUTH_STATE");
|
||||
}
|
||||
|
||||
function getCookieByName(name) {
|
||||
for (const cookie of document.cookie.split(";")) {
|
||||
const [key, value] = cookie.split("=").map((value) => value.trim());
|
||||
if (key === name) {
|
||||
return value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
// for embedded scripts, quoted and modified from https://github.com/swansontec/rfc4648.js by William Swanson
|
||||
'use strict';
|
||||
var base64url = base64url || {};
|
||||
(function(base64url) {
|
||||
|
||||
function parse (string, encoding, opts = {}) {
|
||||
// Build the character lookup table:
|
||||
if (!encoding.codes) {
|
||||
encoding.codes = {};
|
||||
for (let i = 0; i < encoding.chars.length; ++i) {
|
||||
encoding.codes[encoding.chars[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// The string must have a whole number of bytes:
|
||||
if (!opts.loose && (string.length * encoding.bits) & 7) {
|
||||
throw new SyntaxError('Invalid padding');
|
||||
}
|
||||
|
||||
// Count the padding bytes:
|
||||
let end = string.length;
|
||||
while (string[end - 1] === '=') {
|
||||
--end;
|
||||
|
||||
// If we get a whole number of bytes, there is too much padding:
|
||||
if (!opts.loose && !(((string.length - end) * encoding.bits) & 7)) {
|
||||
throw new SyntaxError('Invalid padding');
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the output:
|
||||
const out = new (opts.out || Uint8Array)(((end * encoding.bits) / 8) | 0);
|
||||
|
||||
// Parse the data:
|
||||
let bits = 0; // Number of bits currently in the buffer
|
||||
let buffer = 0; // Bits waiting to be written out, MSB first
|
||||
let written = 0; // Next byte to write
|
||||
for (let i = 0; i < end; ++i) {
|
||||
// Read one character from the string:
|
||||
const value = encoding.codes[string[i]];
|
||||
if (value === void 0) {
|
||||
throw new SyntaxError('Invalid character ' + string[i]);
|
||||
}
|
||||
|
||||
// Append the bits to the buffer:
|
||||
buffer = (buffer << encoding.bits) | value;
|
||||
bits += encoding.bits;
|
||||
|
||||
// Write out some bits if the buffer has a byte's worth:
|
||||
if (bits >= 8) {
|
||||
bits -= 8;
|
||||
out[written++] = 0xff & (buffer >> bits);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that we have received just enough bits:
|
||||
if (bits >= encoding.bits || 0xff & (buffer << (8 - bits))) {
|
||||
throw new SyntaxError('Unexpected end of data');
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
function stringify (data, encoding, opts = {}) {
|
||||
const { pad = true } = opts;
|
||||
const mask = (1 << encoding.bits) - 1;
|
||||
let out = '';
|
||||
|
||||
let bits = 0; // Number of bits currently in the buffer
|
||||
let buffer = 0; // Bits waiting to be written out, MSB first
|
||||
for (let i = 0; i < data.length; ++i) {
|
||||
// Slurp data into the buffer:
|
||||
buffer = (buffer << 8) | (0xff & data[i]);
|
||||
bits += 8;
|
||||
|
||||
// Write out as much as we can:
|
||||
while (bits > encoding.bits) {
|
||||
bits -= encoding.bits;
|
||||
out += encoding.chars[mask & (buffer >> bits)];
|
||||
}
|
||||
}
|
||||
|
||||
// Partial character:
|
||||
if (bits) {
|
||||
out += encoding.chars[mask & (buffer << (encoding.bits - bits))];
|
||||
}
|
||||
|
||||
// Add padding characters until we hit a byte boundary:
|
||||
if (pad) {
|
||||
while ((out.length * encoding.bits) & 7) {
|
||||
out += '=';
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const encoding = {
|
||||
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
|
||||
bits: 6
|
||||
}
|
||||
|
||||
base64url.decode = function (string, opts) {
|
||||
return parse(string, encoding, opts);
|
||||
}
|
||||
|
||||
base64url.encode = function (data, opts) {
|
||||
return stringify(data, encoding, opts)
|
||||
}
|
||||
|
||||
return base64url;
|
||||
}(base64url));
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
export const formatNumber = (input, format) => {
|
||||
if (!input) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// array holding the patterns for the number of expected digits in each part
|
||||
const digitPattern = format.match(/{\d+}/g);
|
||||
|
||||
if (!digitPattern) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// calculate the maximum size of the given pattern based on the sum of the expected digits
|
||||
const maxSize = digitPattern.reduce((total, p) => total + parseInt(p.replace("{", "").replace("}", "")), 0)
|
||||
|
||||
// keep only digits
|
||||
let rawValue = input.replace(/\D+/g, '');
|
||||
|
||||
// make sure the value is a number
|
||||
if (parseInt(rawValue) != rawValue) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// make sure the number of digits does not exceed the maximum size
|
||||
if (rawValue.length > maxSize) {
|
||||
rawValue = rawValue.substring(0, maxSize);
|
||||
}
|
||||
|
||||
// build the regex based based on the expected digits in each part
|
||||
const formatter = digitPattern.reduce((result, p) => result + `(\\d${p})`, "^");
|
||||
|
||||
// if the current digits match the pattern we have each group of digits in an array
|
||||
let digits = new RegExp(formatter).exec(rawValue);
|
||||
|
||||
// no match, return the raw value without any format
|
||||
if (!digits) {
|
||||
return input;
|
||||
}
|
||||
|
||||
let result = format;
|
||||
|
||||
// finally format the current digits accordingly to the given format
|
||||
for (let i = 0; i < digitPattern.length; i++) {
|
||||
result = result.replace(digitPattern[i], digits[i + 1]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
const DATA_KC_MULTIVALUED = 'data-kcMultivalued';
|
||||
const KC_ADD_ACTION_PREFIX = "kc-add-";
|
||||
const KC_REMOVE_ACTION_PREFIX = "kc-remove-";
|
||||
const KC_ACTION_CLASS = "pf-c-button pf-m-inline pf-m-link";
|
||||
|
||||
function createAddAction(element) {
|
||||
const action = createAction("Add value",
|
||||
KC_ADD_ACTION_PREFIX,
|
||||
element,
|
||||
() => {
|
||||
const name = element.getAttribute("name");
|
||||
const elements = getInputElementsByName().get(name);
|
||||
const length = elements.length;
|
||||
|
||||
if (length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastNode = elements[length - 1];
|
||||
const newNode = lastNode.cloneNode(true);
|
||||
newNode.setAttribute("id", name + "-" + elements.length);
|
||||
newNode.value = "";
|
||||
lastNode.after(newNode);
|
||||
|
||||
render();
|
||||
});
|
||||
|
||||
element.after(action);
|
||||
}
|
||||
|
||||
function createRemoveAction(element, isLastElement) {
|
||||
let text = "Remove";
|
||||
|
||||
if (isLastElement) {
|
||||
text = text + " | ";
|
||||
}
|
||||
|
||||
const action = createAction(text, KC_REMOVE_ACTION_PREFIX, element, () => {
|
||||
removeActions(element);
|
||||
element.remove();
|
||||
render();
|
||||
});
|
||||
|
||||
element.insertAdjacentElement('afterend', action);
|
||||
}
|
||||
|
||||
function getInputElementsByName() {
|
||||
const selector = document.querySelectorAll(`[${DATA_KC_MULTIVALUED}]`);
|
||||
const elementsByName = new Map();
|
||||
|
||||
for (let element of Array.from(selector.values())) {
|
||||
let name = element.getAttribute("name");
|
||||
let elements = elementsByName.get(name);
|
||||
|
||||
if (!elements) {
|
||||
elements = [];
|
||||
elementsByName.set(name, elements);
|
||||
}
|
||||
|
||||
elements.push(element);
|
||||
}
|
||||
|
||||
return elementsByName;
|
||||
}
|
||||
|
||||
function removeActions(element) {
|
||||
for (let actionPrefix of [KC_ADD_ACTION_PREFIX, KC_REMOVE_ACTION_PREFIX]) {
|
||||
const action = document.getElementById(actionPrefix + element.getAttribute("id"));
|
||||
|
||||
if (action) {
|
||||
action.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createAction(text, type, element, onClick) {
|
||||
const action = document.createElement("button")
|
||||
action.setAttribute("id", type + element.getAttribute("id"));
|
||||
action.setAttribute("type", "button");
|
||||
action.innerText = text;
|
||||
action.setAttribute("class", KC_ACTION_CLASS);
|
||||
action.addEventListener("click", onClick);
|
||||
return action;
|
||||
}
|
||||
|
||||
function render() {
|
||||
getInputElementsByName().forEach((elements, name) => {
|
||||
elements.forEach((element, index) => {
|
||||
removeActions(element);
|
||||
|
||||
element.setAttribute("id", name + "-" + index);
|
||||
|
||||
const lastNode = element === elements[elements.length - 1];
|
||||
|
||||
if (lastNode) {
|
||||
createAddAction(element);
|
||||
}
|
||||
|
||||
if (elements.length > 1) {
|
||||
createRemoveAction(element, lastNode);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render();
|
@ -1,21 +0,0 @@
|
||||
// @ts-check
|
||||
import { formatNumber } from "./common.js";
|
||||
import { registerElementAnnotatedBy } from "./userProfile.js";
|
||||
|
||||
const KC_NUMBER_FORMAT = "kcNumberFormat";
|
||||
|
||||
registerElementAnnotatedBy({
|
||||
name: KC_NUMBER_FORMAT,
|
||||
onAdd(element) {
|
||||
const formatValue = () => {
|
||||
const format = element.getAttribute(`data-${KC_NUMBER_FORMAT}`);
|
||||
element.value = formatNumber(element.value, format);
|
||||
};
|
||||
|
||||
element.addEventListener("keyup", formatValue);
|
||||
|
||||
formatValue();
|
||||
|
||||
return () => element.removeEventListener("keyup", formatValue);
|
||||
},
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
// @ts-check
|
||||
import { formatNumber } from "./common.js";
|
||||
import { registerElementAnnotatedBy } from "./userProfile.js";
|
||||
|
||||
const KC_NUMBER_UNFORMAT = 'kcNumberUnFormat';
|
||||
|
||||
registerElementAnnotatedBy({
|
||||
name: KC_NUMBER_UNFORMAT,
|
||||
onAdd(element) {
|
||||
for (let form of document.forms) {
|
||||
form.addEventListener('submit', (event) => {
|
||||
const rawFormat = element.getAttribute(`data-${KC_NUMBER_UNFORMAT}`);
|
||||
if (rawFormat) {
|
||||
element.value = formatNumber(element.value, rawFormat);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
@ -1,315 +0,0 @@
|
||||
// @ts-check
|
||||
/*
|
||||
* This content is licensed according to the W3C Software License at
|
||||
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
||||
*
|
||||
* File: menu-button-links.js
|
||||
*
|
||||
* Desc: Creates a menu button that opens a menu of links
|
||||
*
|
||||
* Modified by Peter Keuter to adhere to the coding standards of Keycloak
|
||||
* Original file: https://www.w3.org/WAI/content-assets/wai-aria-practices/patterns/menu-button/examples/js/menu-button-links.js
|
||||
* Source: https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-links.html
|
||||
*/
|
||||
|
||||
class MenuButtonLinks {
|
||||
constructor(domNode) {
|
||||
this.domNode = domNode;
|
||||
this.buttonNode = domNode.querySelector("button");
|
||||
this.menuNode = domNode.querySelector('[role="menu"]');
|
||||
this.menuitemNodes = [];
|
||||
this.firstMenuitem = false;
|
||||
this.lastMenuitem = false;
|
||||
this.firstChars = [];
|
||||
|
||||
this.buttonNode.addEventListener("keydown", (e) => this.onButtonKeydown(e));
|
||||
this.buttonNode.addEventListener("click", (e) => this.onButtonClick(e));
|
||||
|
||||
const nodes = domNode.querySelectorAll('[role="menuitem"]');
|
||||
|
||||
for (const menuitem of nodes) {
|
||||
this.menuitemNodes.push(menuitem);
|
||||
menuitem.tabIndex = -1;
|
||||
this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase());
|
||||
|
||||
menuitem.addEventListener("keydown", (e) => this.onMenuitemKeydown(e));
|
||||
|
||||
menuitem.addEventListener("mouseover", (e) =>
|
||||
this.onMenuitemMouseover(e)
|
||||
);
|
||||
|
||||
if (!this.firstMenuitem) {
|
||||
this.firstMenuitem = menuitem;
|
||||
}
|
||||
this.lastMenuitem = menuitem;
|
||||
}
|
||||
|
||||
domNode.addEventListener("focusin", () => this.onFocusin());
|
||||
domNode.addEventListener("focusout", () => this.onFocusout());
|
||||
|
||||
window.addEventListener(
|
||||
"mousedown",
|
||||
(e) => this.onBackgroundMousedown(e),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
setFocusToMenuitem = (newMenuitem) =>
|
||||
this.menuitemNodes.forEach((item) => {
|
||||
if (item === newMenuitem) {
|
||||
item.tabIndex = 0;
|
||||
newMenuitem.focus();
|
||||
} else {
|
||||
item.tabIndex = -1;
|
||||
}
|
||||
});
|
||||
|
||||
setFocusToFirstMenuitem = () => this.setFocusToMenuitem(this.firstMenuitem);
|
||||
|
||||
setFocusToLastMenuitem = () => this.setFocusToMenuitem(this.lastMenuitem);
|
||||
|
||||
setFocusToPreviousMenuitem = (currentMenuitem) => {
|
||||
let newMenuitem, index;
|
||||
|
||||
if (currentMenuitem === this.firstMenuitem) {
|
||||
newMenuitem = this.lastMenuitem;
|
||||
} else {
|
||||
index = this.menuitemNodes.indexOf(currentMenuitem);
|
||||
newMenuitem = this.menuitemNodes[index - 1];
|
||||
}
|
||||
|
||||
this.setFocusToMenuitem(newMenuitem);
|
||||
|
||||
return newMenuitem;
|
||||
};
|
||||
|
||||
setFocusToNextMenuitem = (currentMenuitem) => {
|
||||
let newMenuitem, index;
|
||||
|
||||
if (currentMenuitem === this.lastMenuitem) {
|
||||
newMenuitem = this.firstMenuitem;
|
||||
} else {
|
||||
index = this.menuitemNodes.indexOf(currentMenuitem);
|
||||
newMenuitem = this.menuitemNodes[index + 1];
|
||||
}
|
||||
this.setFocusToMenuitem(newMenuitem);
|
||||
|
||||
return newMenuitem;
|
||||
};
|
||||
|
||||
setFocusByFirstCharacter = (currentMenuitem, char) => {
|
||||
let start, index;
|
||||
|
||||
if (char.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
char = char.toLowerCase();
|
||||
|
||||
// Get start index for search based on position of currentItem
|
||||
start = this.menuitemNodes.indexOf(currentMenuitem) + 1;
|
||||
if (start >= this.menuitemNodes.length) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
// Check remaining slots in the menu
|
||||
index = this.firstChars.indexOf(char, start);
|
||||
|
||||
// If not found in remaining slots, check from beginning
|
||||
if (index === -1) {
|
||||
index = this.firstChars.indexOf(char, 0);
|
||||
}
|
||||
|
||||
// If match was found...
|
||||
if (index > -1) {
|
||||
this.setFocusToMenuitem(this.menuitemNodes[index]);
|
||||
}
|
||||
};
|
||||
|
||||
// Utilities
|
||||
|
||||
getIndexFirstChars = (startIndex, char) => {
|
||||
for (let i = startIndex; i < this.firstChars.length; i++) {
|
||||
if (char === this.firstChars[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Popup menu methods
|
||||
|
||||
openPopup = () => {
|
||||
this.menuNode.style.display = "block";
|
||||
this.buttonNode.setAttribute("aria-expanded", "true");
|
||||
};
|
||||
|
||||
closePopup = () => {
|
||||
if (this.isOpen()) {
|
||||
this.buttonNode.setAttribute("aria-expanded", "false");
|
||||
this.menuNode.style.removeProperty("display");
|
||||
}
|
||||
};
|
||||
|
||||
isOpen = () => {
|
||||
return this.buttonNode.getAttribute("aria-expanded") === "true";
|
||||
};
|
||||
|
||||
// Menu event handlers
|
||||
|
||||
onFocusin = () => {
|
||||
this.domNode.classList.add("focus");
|
||||
};
|
||||
|
||||
onFocusout = () => {
|
||||
this.domNode.classList.remove("focus");
|
||||
};
|
||||
|
||||
onButtonKeydown = (event) => {
|
||||
const key = event.key;
|
||||
let flag = false;
|
||||
|
||||
switch (key) {
|
||||
case " ":
|
||||
case "Enter":
|
||||
case "ArrowDown":
|
||||
case "Down":
|
||||
this.openPopup();
|
||||
this.setFocusToFirstMenuitem();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "Esc":
|
||||
case "Escape":
|
||||
this.closePopup();
|
||||
this.buttonNode.focus();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "Up":
|
||||
case "ArrowUp":
|
||||
this.openPopup();
|
||||
this.setFocusToLastMenuitem();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
onButtonClick(event) {
|
||||
if (this.isOpen()) {
|
||||
this.closePopup();
|
||||
this.buttonNode.focus();
|
||||
} else {
|
||||
this.openPopup();
|
||||
this.setFocusToFirstMenuitem();
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
onMenuitemKeydown(event) {
|
||||
const tgt = event.currentTarget;
|
||||
const key = event.key;
|
||||
let flag = false;
|
||||
|
||||
const isPrintableCharacter = (str) => str.length === 1 && str.match(/\S/);
|
||||
|
||||
if (event.ctrlKey || event.altKey || event.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.shiftKey) {
|
||||
if (isPrintableCharacter(key)) {
|
||||
this.setFocusByFirstCharacter(tgt, key);
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (event.key === "Tab") {
|
||||
this.buttonNode.focus();
|
||||
this.closePopup();
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
switch (key) {
|
||||
case " ":
|
||||
window.location.href = tgt.href;
|
||||
break;
|
||||
|
||||
case "Esc":
|
||||
case "Escape":
|
||||
this.closePopup();
|
||||
this.buttonNode.focus();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "Up":
|
||||
case "ArrowUp":
|
||||
this.setFocusToPreviousMenuitem(tgt);
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "ArrowDown":
|
||||
case "Down":
|
||||
this.setFocusToNextMenuitem(tgt);
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "Home":
|
||||
case "PageUp":
|
||||
this.setFocusToFirstMenuitem();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "End":
|
||||
case "PageDown":
|
||||
this.setFocusToLastMenuitem();
|
||||
flag = true;
|
||||
break;
|
||||
|
||||
case "Tab":
|
||||
this.closePopup();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isPrintableCharacter(key)) {
|
||||
this.setFocusByFirstCharacter(tgt, key);
|
||||
flag = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
onMenuitemMouseover(event) {
|
||||
const tgt = event.currentTarget;
|
||||
tgt.focus();
|
||||
}
|
||||
|
||||
onBackgroundMousedown(event) {
|
||||
if (!this.domNode.contains(event.target)) {
|
||||
if (this.isOpen()) {
|
||||
this.closePopup();
|
||||
this.buttonNode.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const menuButtons = document.querySelectorAll(".menu-button-links");
|
||||
for (const button of menuButtons) {
|
||||
new MenuButtonLinks(button);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
const toggle = (button) => {
|
||||
const passwordElement = document.getElementById(button.getAttribute('aria-controls'));
|
||||
if (passwordElement.type === "password") {
|
||||
passwordElement.type = "text";
|
||||
button.children.item(0).className = button.dataset.iconHide;
|
||||
button.setAttribute("aria-label", button.dataset.labelHide);
|
||||
} else if(passwordElement.type === "text") {
|
||||
passwordElement.type = "password";
|
||||
button.children.item(0).className = button.dataset.iconShow;
|
||||
button.setAttribute("aria-label", button.dataset.labelShow);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-password-toggle]')
|
||||
.forEach(button => button.onclick = () => toggle(button));
|
@ -1,71 +0,0 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* @typedef {Object} AnnotationDescriptor
|
||||
* @property {string} name - The name of the field to register (e.g. `numberFormat`).
|
||||
* @property {(element: HTMLElement) => (() => void) | void} onAdd - The function to call when a new element is added to the DOM.
|
||||
*/
|
||||
|
||||
const observer = new MutationObserver(onMutate);
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
/** @type {AnnotationDescriptor[]} */
|
||||
const descriptors = [];
|
||||
|
||||
/** @type {WeakMap<HTMLElement, () => void>} */
|
||||
const cleanupFunctions = new WeakMap();
|
||||
|
||||
/**
|
||||
* @param {AnnotationDescriptor} descriptor
|
||||
*/
|
||||
export function registerElementAnnotatedBy(descriptor) {
|
||||
descriptors.push(descriptor);
|
||||
|
||||
document.querySelectorAll(`[data-${descriptor.name}]`).forEach((element) => {
|
||||
if (element instanceof HTMLElement) {
|
||||
handleNewElement(element, descriptor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {MutationCallback}
|
||||
*/
|
||||
function onMutate(mutations) {
|
||||
const removedNodes = mutations.flatMap((mutation) => Array.from(mutation.removedNodes));
|
||||
|
||||
for (const node of removedNodes) {
|
||||
if (!(node instanceof HTMLElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const handleRemovedElement = cleanupFunctions.get(node);
|
||||
|
||||
if (handleRemovedElement) {
|
||||
handleRemovedElement();
|
||||
}
|
||||
|
||||
cleanupFunctions.delete(node);
|
||||
}
|
||||
|
||||
const addedNodes = mutations.flatMap((mutation) => Array.from(mutation.addedNodes));
|
||||
|
||||
for (const descriptor of descriptors) {
|
||||
for (const node of addedNodes) {
|
||||
if (node instanceof HTMLElement && node.hasAttribute(`data-${descriptor.name}`)) {
|
||||
handleNewElement(node, descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
* @param {AnnotationDescriptor} descriptor
|
||||
*/
|
||||
function handleNewElement(element, descriptor) {
|
||||
const cleanup = descriptor.onAdd(element);
|
||||
|
||||
if (cleanup) {
|
||||
cleanupFunctions.set(element, cleanup);
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 627 B |
@ -1,22 +0,0 @@
|
||||
/*!
|
||||
* This folder contains updated PatternFly4 icons (version 2020.13).
|
||||
* After the PF4 transition is finished this folder will be deleted.
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: "pficon-tmp";
|
||||
src: url("./pficon.woff2") format("woff2");
|
||||
}
|
||||
|
||||
.pf-icon-openshift:before {
|
||||
font-family: "pficon-tmp";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
text-transform: none; }
|
||||
|
||||
.pf-icon-openshift:before {
|
||||
content: ""; }
|