UI: captcha on window load and on AJAX

This commit is contained in:
Tony Air 2022-09-12 22:07:08 +02:00
parent 5f54ca9d6a
commit 35bd02ac50
5 changed files with 291 additions and 232 deletions

74
src/js/ui/captcha.js Normal file
View File

@ -0,0 +1,74 @@
import Events from '../_events'
const CaptchaUI = ((window) => {
const NAME = 'js-captcha'
const init = () => {
console.log(`${NAME}: init`)
const submitListener = (e) => {
console.log(`${NAME}: Validating Captcha ...`)
const field = e.currentTarget.querySelectorAll(`.${NAME}, .g-recaptcha`).forEach((el) => {
grecaptcha.execute(el.dataset.widgetid)
})
}
const attachCaptcha = () => {
console.log(`${NAME}: Rendering Captcha ...`)
const fields = document.querySelectorAll(`.${NAME}, .g-recaptcha`)
const grecaptcha = window.grecaptcha
fields.forEach((el, i) => {
if (el.dataset.widgetid || el.innerHTML !== '') {
// already initialized
return
}
const form = el.closest(form)
const widgetid = grecaptcha.render(el, el.dataset)
el.dataset.widgetid = widgetid
if(el.dataset.size === 'invisible' && !el.dataset.callback){
grecaptcha.execute(widgetid)
form.addEventListener('submit', submitListener)
}
el.classList.add(`${NAME}-active`)
el.dispatchEvent(new Event(`${NAME}-ready`))
})
}
const loadScript = (callback) => {
if(typeof window.grecaptcha !== 'undefined'){
callback()
}
console.log(`${NAME}: Loading Captcha API ...`)
const script = document.createElement('script');
script.id = 'captchaAPI';
script.src = 'https://www.google.com/recaptcha/api.js?render=explicit&hl=' + document.querySelector('html').getAttribute('lang').substr(0,2)
script.async = true
script.onload = function() {
console.log(`${NAME}: Captcha API is loaded.`)
callback()
}
document.body.append(script)
}
if(document.querySelectorAll('.g-recaptcha').length){
loadScript(attachCaptcha);
}else{
console.log(`${NAME}: No Captcha fields.`)
}
window.noCaptchaFieldRender = attachCaptcha
}
window.addEventListener(`${Events.LODEDANDREADY}`, init)
window.addEventListener(`${Events.AJAX}`, init)
})(window)
export default CaptchaUI

View File

@ -187,6 +187,7 @@ const CarouselUI = ((window) => {
el.dataset.ui = el.ui el.dataset.ui = el.ui
el.classList.add(`${NAME}-active`) el.classList.add(`${NAME}-active`)
el.dispatchEvent(new Event(`${NAME}-ready`))
}) })
} }

View File

@ -22,22 +22,22 @@ const DropdownHoverUI = ((window) => {
const Toggle = (el) => { const Toggle = (el) => {
HideAll() HideAll()
if (el.querySelector('.dropdown-menu').classList.contains('show')) { el.querySelector('.dropdown-menu').classList.toggle('show')
Hide(el)
} else {
Show(el)
}
} }
const Show = (el) => { const Show = (e) => {
e.stopPropagation()
const el = e.currentTarget
el.classList.add(...ACTIVECLS) el.classList.add(...ACTIVECLS)
el.closest('.dropdown').classList.add(...ACTIVECLS)
el.querySelector('.dropdown-menu').classList.add('show') el.querySelector('.dropdown-menu').classList.add('show')
} }
const Hide = (el) => { const Hide = (e) => {
e.stopPropagation()
const el = e.currentTarget
el.classList.remove(...ACTIVECLS) el.classList.remove(...ACTIVECLS)
el.closest('.dropdown').classList.remove(...ACTIVECLS)
el.querySelector('.dropdown-menu').classList.remove('show') el.querySelector('.dropdown-menu').classList.remove('show')
} }
@ -48,14 +48,8 @@ const DropdownHoverUI = ((window) => {
const hoverableEls = document.querySelectorAll('[data-bs-toggle="hover"]') const hoverableEls = document.querySelectorAll('[data-bs-toggle="hover"]')
const attachHoverEvents = (el) => { const attachHoverEvents = (el) => {
el.addEventListener('mouseover', (e) => { el.addEventListener('mouseover', Show, false)
e.stopPropagation() el.addEventListener('mouseleave', Hide, false)
Show(e.currentTarget)
}, false)
el.addEventListener('mouseleave', (e) => {
e.stopPropagation()
Hide(e.currentTarget)
}, false)
el.classList.add(`${NAME}-active`) el.classList.add(`${NAME}-active`)
} }

View File

@ -2,6 +2,25 @@
@import "~bootstrap/scss/mixins"; @import "~bootstrap/scss/mixins";
/// Remove the unit of a length
/// @param {Number} $number - Number to remove unit from
/// @return {Number} - Unitless number
@function strip-unit($number) {
@if type-of($number) == 'number' and not unitless($number) {
@return $number / ($number * 0 + 1);
}
@return $number;
}
@function rem($pxValue) {
@return #{strip-unit($pxValue) / strip-unit($html-font-size)}rem;
}
/*.component {
font-size: rem(14px); // or rem(14)
}*/
@mixin hover-disabled() { @mixin hover-disabled() {
&:not(.disabled) { &:not(.disabled) {
&.active, &.active,
@ -14,9 +33,9 @@
} }
@mixin pseudo($display: block, $pos: absolute, $content: "") { @mixin pseudo($display: block, $pos: absolute, $content: "") {
content: $content;
display: $display;
position: $pos; position: $pos;
display: $display;
content: $content;
} }
@mixin responsive-ratio($x, $y, $pseudo: false) { @mixin responsive-ratio($x, $y, $pseudo: false) {
@ -24,9 +43,10 @@
@if $pseudo { @if $pseudo {
&:before { &:before {
@include pseudo($pos: relative);
padding-top: $padding;
width: 100%; width: 100%;
padding-top: $padding;
@include pseudo($pos: relative);
} }
} @else { } @else {
padding-top: $padding; padding-top: $padding;
@ -56,10 +76,10 @@
} }
@mixin truncate($truncation-boundary) { @mixin truncate($truncation-boundary) {
max-width: $truncation-boundary;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; max-width: $truncation-boundary;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis;
} }
@mixin fix-bold() { @mixin fix-bold() {
@ -67,14 +87,14 @@
flex-direction: column; flex-direction: column;
&:before { &:before {
font-weight: bold;
visibility: hidden;
overflow: hidden;
height: 0;
content: attr(data-text); content: attr(data-text);
content: attr(data-text) / ""; content: attr(data-text) / "";
font-weight: bold;
height: 0;
overflow: hidden;
pointer-events: none;
user-select: none; user-select: none;
visibility: hidden; pointer-events: none;
} }
} }
@ -93,8 +113,8 @@
.nav-link.show, .nav-link.show,
.navbar-nav .show > .nav-link { .navbar-nav .show > .nav-link {
background: $navbar-dark-show-background;
color: $navbar-dark-show-color; color: $navbar-dark-show-color;
background: $navbar-dark-show-background;
} }
} }
@ -109,8 +129,8 @@
} }
&.disabled { &.disabled {
color: $navbar-dark-disabled-color;
cursor: default; cursor: default;
color: $navbar-dark-disabled-color;
} }
} }
@ -123,8 +143,8 @@
.dropdown-item { .dropdown-item {
@include hover-focus { @include hover-focus {
background: $navbar-dark-hover-background;
color: $navbar-dark-hover-color; color: $navbar-dark-hover-color;
background: $navbar-dark-hover-background;
} }
&.active, &.active,
@ -172,11 +192,11 @@
} }
.dropdown-hover ul ul { .dropdown-hover ul ul {
display: none;
left: 0;
min-width: 250px;
position: absolute; position: absolute;
top: 100%; top: 100%;
left: 0;
display: none;
min-width: 250px;
} }
.dropdown-hover ul ul li { .dropdown-hover ul ul li {
@ -194,11 +214,11 @@
} }
.dropdown-hover ul ul ul { .dropdown-hover ul ul ul {
display: none;
left: 100%;
min-width: 250px;
position: absolute; position: absolute;
top: 0; top: 0;
left: 100%;
display: none;
min-width: 250px;
} }
.dropdown-hover ul ul ul li { .dropdown-hover ul ul ul li {
@ -216,12 +236,12 @@
} }
.dropdown-hover ul ul ul ul { .dropdown-hover ul ul ul ul {
display: none;
left: -100%;
min-width: 250px;
position: absolute; position: absolute;
top: 0;
z-index: 1; z-index: 1;
top: 0;
left: -100%;
display: none;
min-width: 250px;
} }
} }
} }

View File

@ -27,108 +27,78 @@ $container-max-widths: (
xxxl: 1536px, xxxl: 1536px,
xxxxl: 1836px, xxxxl: 1836px,
) !default; ) !default;
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; $font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
$font-family-base: "Roboto", $font-family-sans-serif !default; $font-family-base: "Roboto", $font-family-sans-serif !default;
$html-font-size: 14px!default;
$spacer: 1rem !default; $spacer: 1rem !default;
$headings-margin-bottom: $spacer !default; $headings-margin-bottom: $spacer !default;
$enable-rounded: false !default; $enable-rounded: false !default;
$enable-shadows: true !default; $enable-shadows: true !default;
$enable-gradients: false !default; $enable-gradients: false !default;
$enable-transitions: true !default; $enable-transitions: true !default;
$enable-reduced-motion: true !default; $enable-reduced-motion: true !default;
$enable-caret: false !default; $enable-caret: false !default;
$enable-grid-classes: true !default; $enable-grid-classes: true !default;
$enable-button-pointers: true !default; $enable-button-pointers: true !default;
$enable-rfs: true !default; $enable-rfs: true !default;
$enable-validation-icons: true !default; $enable-validation-icons: true !default;
$enable-negative-margins: true !default; $enable-negative-margins: true !default;
$enable-deprecation-messages: true !default; $enable-deprecation-messages: true !default;
$enable-important-utilities: true !default; $enable-important-utilities: true !default;
$breadcrumb-divider: quote("/") !default; $breadcrumb-divider: quote("/") !default;
// ui framework settings // ui framework settings
$body-gutter-x: $spacer !default; $body-gutter-x: $spacer !default;
$body-gutter-y: $spacer !default; $body-gutter-y: $spacer !default;
$body-double-gutter-x: $body-gutter-x * 2 !default; $body-double-gutter-x: $body-gutter-x * 2 !default;
$body-double-gutter-y: $body-gutter-y * 2 !default; $body-double-gutter-y: $body-gutter-y * 2 !default;
$body-gutter-reduced-x: $body-gutter-x * .5 !default;
$body-gutter-reduced-x: $body-gutter-x * 0.5 !default; $body-gutter-reduced-y: $body-gutter-y * .5 !default;
$body-gutter-reduced-y: $body-gutter-y * 0.5 !default; $body-gutter-reduced-d-x: $body-gutter-x * .25 !default;
$body-gutter-reduced-d-y: $body-gutter-y * .25 !default;
$body-gutter-reduced-d-x: $body-gutter-x * 0.25 !default;
$body-gutter-reduced-d-y: $body-gutter-y * 0.25 !default;
$form-spacer-x: $spacer !default; $form-spacer-x: $spacer !default;
$form-spacer-y: $spacer !default; $form-spacer-y: $spacer !default;
$element-spacer-x: map.get($spacers, 3) !default; $element-spacer-x: map.get($spacers, 3) !default;
$element-spacer-y: map.get($spacers, 3) !default; $element-spacer-y: map.get($spacers, 3) !default;
$element-reduced-spacer-x: map.get($spacers, 2) !default; $element-reduced-spacer-x: map.get($spacers, 2) !default;
$element-reduced-spacer-y: map.get($spacers, 2) !default; $element-reduced-spacer-y: map.get($spacers, 2) !default;
$element-reduced-d-spacer-x: map.get($spacers, 1) !default; $element-reduced-d-spacer-x: map.get($spacers, 1) !default;
$element-reduced-d-spacer-y: map.get($spacers, 1) !default; $element-reduced-d-spacer-y: map.get($spacers, 1) !default;
$body-bg: #fff !default; $body-bg: #fff !default;
$body-color: #212529 !default; $body-color: #212529 !default;
// site specific variables // site specific variables
$extra-large-screen: 2000px !default; $extra-large-screen: 2000px !default;
$full-body-min-width: map-get($grid-breakpoints, "lg") !default; $full-body-min-width: map-get($grid-breakpoints, "lg") !default;
$typography-breakpoint: map-get($grid-breakpoints, "sm") - 1 !default; $typography-breakpoint: map-get($grid-breakpoints, "sm") - 1 !default;
$header-bg: var(--bs-dark) !default; $header-bg: var(--bs-dark) !default;
$header-color: var(--bs-light) !default; $header-color: var(--bs-light) !default;
$header-link: var(--bs-white) !default; $header-link: var(--bs-white) !default;
$main-nav-link-color: var(--bs-white) !default; $main-nav-link-color: var(--bs-white) !default;
$main-nav-link-bg: none !default; $main-nav-link-bg: none !default;
$main-nav-toggler-size: 2rem !default; $main-nav-toggler-size: 2rem !default;
$main-nav-link-hover-bg: none !default; $main-nav-link-hover-bg: none !default;
$main-nav-link-hover-color: var(--bs-cyan) !default; $main-nav-link-hover-color: var(--bs-cyan) !default;
$main-nav-dropdown-bg: $header-bg !default; $main-nav-dropdown-bg: $header-bg !default;
$main-nav-dropdown-color: $header-link !default; $main-nav-dropdown-color: $header-link !default;
$main-nav-dropdown-hover-bg: var(--bs-black) !default; $main-nav-dropdown-hover-bg: var(--bs-black) !default;
$main-nav-dropdown-hover-color: $main-nav-link-hover-color !default; $main-nav-dropdown-hover-color: $main-nav-link-hover-color !default;
$sidebar-nav-link-hover-color: var(--bs-indigo) !default; $sidebar-nav-link-hover-color: var(--bs-indigo) !default;
$footer-bg: $header-bg !default; $footer-bg: $header-bg !default;
$footer-color: $header-color !default; $footer-color: $header-color !default;
$footer-link: $header-link !default; $footer-link: $header-link !default;
$footer-footer-bg: $main-nav-dropdown-hover-bg !default; $footer-footer-bg: $main-nav-dropdown-hover-bg !default;
$sliderelement-carousel-slide-max-y: 70vh !default; $sliderelement-carousel-slide-max-y: 70vh !default;
$sliderelement-carousel-slide-bg: $header-bg !default; $sliderelement-carousel-slide-bg: $header-bg !default;
$sliderelement-carousel-slide-ratio-x: 16 !default; $sliderelement-carousel-slide-ratio-x: 16 !default;
$sliderelement-carousel-slide-ratio-y: 9 !default; $sliderelement-carousel-slide-ratio-y: 9 !default;
$carousel-title-color: $white !default; $carousel-title-color: $white !default;
$carousel-slide-min-height: 4rem !default; $carousel-slide-min-height: 4rem !default;
$carousel-text-shadow: 1px 1px $black !default; $carousel-text-shadow: 1px 1px $black !default;
$carousel-controls-font-size: 3rem; $carousel-controls-font-size: 3rem;
$carousel-controls-zindex: 11 !default; $carousel-controls-zindex: 11 !default;
$carousel-controls-shadow: 1px 1px $black !default; $carousel-controls-shadow: 1px 1px $black !default;
$carousel-controls-hover-bg: transparentize($black, 0.4) !default; $carousel-controls-hover-bg: transparentize($black, .4) !default;
$carousel-slide-img-loading-max-height: 70vh !default; $carousel-slide-img-loading-max-height: 70vh !default;
$breadcrumb-active-color: $sidebar-nav-link-hover-color; $breadcrumb-active-color: $sidebar-nav-link-hover-color;