diff --git a/package.json b/package.json index 483687f..74b4dc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate-react", - "version": "5.2.9", + "version": "5.3.0", "description": "This UI Kit allows you to build Bootstrap 5 webapp with some extra UI features. It's easy to extend and easy to convert HTML templates to CMS templates.", "author": "Tony Air ", "license": "BSD-2-Clause", diff --git a/src/js/ajax/form.js b/src/js/ajax/form.js index 31cd27a..1a18e7a 100644 --- a/src/js/ajax/form.js +++ b/src/js/ajax/form.js @@ -22,9 +22,7 @@ const submitForm = (e) => { data.append('ajax', '1') - form.querySelectorAll('.field__alert').forEach((el) => { - el.remove() - }) + clearAlerts(form) parent.classList.remove('loaded') parent.classList.add('loading') @@ -54,6 +52,12 @@ const submitForm = (e) => { }) } +const clearAlerts = (form) => { + form.querySelectorAll('.field__alert,.form__message').forEach((el) => { + el.remove() + }) +} + const processResponse = (html) => { try { let json = JSON.parse(html) @@ -95,27 +99,47 @@ const isAlertResponse = (msg) => { const formProcessJson = (form, json) => { const status = json.status === 'good' || 'success' ? 'success' : 'danger' + if (json.location) { + console.log(`${NAME}: Redirect`) + + //if (!json.loadAjax && typeof window.app.Router !== 'undefined') { + const link = document.createElement('a') + link.setAttribute('href', json.location) + window.app.Router.linkClick(link, new Event('click')) + //} else { + // window.location = json.location + //} + + return setLoaded(form) + } + if (json.msgs) { + const fieldset = form.querySelector('.form__fieldset') + json.msgs.forEach((i) => { + const msg = document.createElement('div') + msg.classList.add(...['field__alert']) + if (!isAlertResponse(i.message)) { + msg.classList.add(...['alert', `alert-${status}`, `alert-${i.messageCast}`, `${i.messageType}`]) + } + + msg.innerHTML = i.message + + const field = form.querySelector(`[name="${i.fieldName}"],[name^="${i.fieldName}["]`) + if (field) { field.classList.add('error') const fieldContainer = field.closest('.form__field') if (fieldContainer) { fieldContainer.classList.add('error') - - const msg = document.createElement('div') - msg.classList.add(...['field__alert']) - if (!isAlertResponse(i.message)) { - msg.classList.add(...['alert', `alert-${status}`, `alert-${i.messageCast}`, `${i.messageType}`]) - } - - msg.innerHTML = i.message - fieldContainer.appendChild(msg) + return } } + + form.insertBefore(msg, fieldset) }) return setLoaded(form) diff --git a/src/js/ui/password.js b/src/js/ui/password.js index 4af72f2..555911c 100644 --- a/src/js/ui/password.js +++ b/src/js/ui/password.js @@ -5,14 +5,15 @@ const PasswordUI = ((window) => { const init = () => { console.log(`${NAME}: init`) + let timer - let timer; const toggle = (input) => { - if (input.getAttribute('type') === 'password') { - show(input) - } else { - hide(input) + console.log(`${NAME}: toggle`) + if (timer) { + clearTimeout(timer); } + + show(input) } const show = (input) => { @@ -24,18 +25,18 @@ const PasswordUI = ((window) => { const hide = (input) => { input.setAttribute('type', 'password') - if(timer){ + if (timer) { clearTimeout(timer); } } document.querySelectorAll(`${NAME}-show, .show-password`).forEach((el) => { - if(el.classList.contains(`${NAME}-active`)){ + if (el.classList.contains(`${NAME}-active`)) { return } el.addEventListener('click', (e) => { - const input = e.currentTarget.closest('.field').querySelector('input'); + const input = e.currentTarget.closest('.field').querySelector('input') if (!input) { return } diff --git a/src/js/ui/turnstile.js b/src/js/ui/turnstile.js index c43f51a..31db586 100644 --- a/src/js/ui/turnstile.js +++ b/src/js/ui/turnstile.js @@ -1,52 +1,71 @@ import Events from '../_events' const NAME = 'uiTurnstile' -const SELECTOR = '.cf-turnstile' +const SELECTOR = `.${NAME},.js-turnstile` const init = () => { + console.log(`${NAME}: init`) + const captchas = document.querySelectorAll(SELECTOR) if (!captchas.length) { console.log(`${NAME}: No Captcha fields.`) return } - if (typeof window.turnstile === 'undefined') { + if (!document.querySelector('#captchaAPI') && typeof window.turnstile === 'undefined') { loadScript(init) return } - console.log(`${NAME}: init`) + renderCaptcha() +} + +const renderCaptcha = () => { + console.log(`${NAME}: renderCaptcha`) + + const captchas = document.querySelectorAll(SELECTOR) + captchas.forEach((el) => { if (el.dataset[NAME] || el.innerHTML.length > 0) { + + if (el.dataset.widgetid) { + turnstile.reset(el.dataset.widgetid) + } + return } - window.turnstile.render(el) + const widgetid = window.turnstile.render(el, { + sitekey: el.dataset.sitekey, + callback: function (token) { + console.log(`${NAME}: Challenge Success ${token}`); + }, + }) + + const form = el.closest('form') + form.addEventListener('submit', () => { + console.log(`${NAME}: submit`) + window.turnstile.reset(el.dataset.widgetid) + }) + + el.dataset.widgetid = widgetid + el.dataset[NAME] = true }) } - -window.turnstileFieldRender = init - -const loadScript = (callback) => { - if (typeof window.turnstile !== 'undefined') { - callback() - } +const loadScript = () => { console.log(`${NAME}: Loading Captcha API ...`) - const script = document.createElement('script'); script.id = 'captchaAPI'; - script.src = `https://challenges.cloudflare.com/turnstile/v0/api.js?hl=${document.querySelector('html').getAttribute('lang').substr(0, 2)}` + script.src = `https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=renderCaptcha&hl=${document.querySelector('html').getAttribute('lang').substr(0, 2)}` script.async = true - script.onload = function () { - console.log(`${NAME}: Turnstile Captcha API is loaded.`) - callback() - } document.body.append(script) } +window.renderCaptcha = renderCaptcha + window.addEventListener(`${Events.LODEDANDREADY}`, init) window.addEventListener(`${Events.AJAX}`, init)