1(function(){'use strict';var CONFIG={CLICK_NO_REQUEST_TIMEOUT_MS:3000,SLOW_REQUEST_TIMEOUT_MS:8000,DEBUG:!1,DUPLICATE_LOG_TTL_MS:60000};var pendingClickTimers={};var inFlight={};var recentLogs={};var observedErrorMessages=new WeakSet();if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',init)}else{init()} 2function init(){if(typeof apadoreBricks==='undefined'||!apadoreBricks.restUrl){return} 3CONFIG.DEBUG=!!apadoreBricks.debugMode||localStorage.getItem('apadore_debug')==='1'||window.location.search.indexOf('apadore_debug=1')!==-1;if(typeof apadoreBricks.slowThresholdMs==='number'&&apadoreBricks.slowThresholdMs>0){CONFIG.SLOW_REQUEST_TIMEOUT_MS=apadoreBricks.slowThresholdMs} 4if(typeof apadoreBricks.clickTimeoutMs==='number'&&apadoreBricks.clickTimeoutMs>0){CONFIG.CLICK_NO_REQUEST_TIMEOUT_MS=apadoreBricks.clickTimeoutMs} 5interceptAjax();observeClicks();observeDomErrors();observeBricksEvents();log('Frontend monitor initialized',CONFIG)} 6function observeClicks(){document.addEventListener('click',function(event){var hit=findSubmitHit(event);if(!hit||!hit.button){return} 7var ctx=getFormContext(hit.button);if(!ctx.formId){return} 8if(ctx.formEl&&typeof ctx.formEl.checkValidity==='function'){try{if(!ctx.formEl.checkValidity()){return}}catch(e){}} 9startClickWatch(ctx,hit,event)},!0)} 10function observeDomErrors(){if(typeof MutationObserver==='undefined'){return} 11var observer=new MutationObserver(function(mutations){mutations.forEach(function(mutation){if(mutation.type==='attributes'&&mutation.attributeName==='class'){var target=mutation.target;if(target&&target.classList){if(target.classList.contains('recaptcha-error')&&target.classList.contains('show')){handleErrorMessage(target)} 12if(target.classList.contains('brxe-alert')&&target.classList.contains('danger')){handleErrorMessage(target)}} 13return} 14if(mutation.type!=='childList'||!mutation.addedNodes.length){return} 15mutation.addedNodes.forEach(function(node){if(node.nodeType!==Node.ELEMENT_NODE){return} 16if(isErrorMessageElement(node)){handleErrorMessage(node);return} 17if(node.querySelectorAll){var errorNodes=node.querySelectorAll(getErrorSelectors());errorNodes.forEach(function(errorNode){handleErrorMessage(errorNode)})}})})});observer.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:['class']})} 18function observeBricksEvents(){document.addEventListener('bricks/form/submit/error',handleBricksFormError);document.addEventListener('bricks/form/error',handleBricksFormError);window.addEventListener('bricks/form/submit/error',handleBricksFormError);window.addEventListener('bricks/form/error',handleBricksFormError)} 19function handleBricksFormError(event){log('Bricks form error event received',event.type,event.detail);var detail=event.detail||{};var formEl=detail.form||detail.formElement||null;var message=detail.message||detail.error||detail.errorMessage||'';var errorType=detail.type||detail.errorType||'';if(!formEl&&event.target){formEl=event.target.closest?event.target.closest('form'):null} 20var ctx={formId:null,postId:0,referrer:window.location.href,formEl:formEl};if(detail.formId){ctx.formId=detail.formId}else if(formEl){var wrapper=formEl.closest('.brxe-form, [data-element-id]');if(wrapper&&wrapper.dataset&&wrapper.dataset.elementId){ctx.formId=wrapper.dataset.elementId} 21var idInput=formEl.querySelector('[name="formId"]');if(!ctx.formId&&idInput&&idInput.value){ctx.formId=idInput.value} 22var postInput=formEl.querySelector('[name="postId"]');if(postInput&&postInput.value){ctx.postId=parseInt(postInput.value,10)||0}} 23var classifiedType=classifyBricksError(errorType,message);if(ctx.formId){clearPendingClick(ctx.formId)} 24logToServer(ctx,{type:classifiedType,message:message||'Bricks form error (no message)',code:detail.code||0,source:'bricks_event',event_type:event.type,original_error_type:errorType})} 25function classifyBricksError(errorType,message){var lower=((errorType||'')+' '+(message||'')).toLowerCase();if(lower.indexOf('recaptcha')!==-1||lower.indexOf('captcha')!==-1){return'recaptcha_error'} 26if(lower.indexOf('required')!==-1||lower.indexOf('povinné')!==-1||lower.indexOf('povinný')!==-1){return'validation_error'} 27if(lower.indexOf('email')!==-1&&(lower.indexOf('invalid')!==-1||lower.indexOf('neplatný')!==-1||lower.indexOf('neplatná')!==-1)){return'validation_error'} 28if(errorType&&/^[a-z_]+$/.test(errorType)){return errorType} 29return'bricks_form_error'} 30function getErrorSelectors(){return'.recaptcha-error.show, .recaptcha-error.show .brxe-alert.danger, .message.error, .bricks-form-message.error, [data-message-type="error"]'} 31function isElementVisible(el){if(!el)return!1;var style=window.getComputedStyle(el);if(style.display==='none'||style.visibility==='hidden'){return!1} 32if(el.offsetParent===null&&style.position!=='fixed'&&style.position!=='sticky'){return!1} 33return!0} 34function isErrorMessageElement(el){if(!el||!el.classList){return!1} 35if(el.classList.contains('message')&&el.classList.contains('error')){return!0} 36if(el.classList.contains('bricks-form-message')&&el.classList.contains('error')){return!0} 37if(el.getAttribute&&el.getAttribute('data-message-type')==='error'){return!0} 38if(el.classList.contains('recaptcha-error')&&el.classList.contains('show')){return!0} 39if(el.classList.contains('brxe-alert')&&el.classList.contains('danger')){return!0} 40return!1} 41function handleErrorMessage(errorEl){if(!errorEl){return} 42if(observedErrorMessages.has(errorEl)){return} 43observedErrorMessages.add(errorEl);if(!isElementVisible(errorEl)){return} 44var errorText=(errorEl.textContent||errorEl.innerText||'').trim();if(!errorText){return} 45var formWrapper=errorEl.closest('.brxe-form, [data-element-id]');var formEl=errorEl.closest('form');var ctx={formId:null,postId:0,referrer:window.location.href,formEl:formEl};if(formWrapper&&formWrapper.dataset&&formWrapper.dataset.elementId){ctx.formId=formWrapper.dataset.elementId} 46if(!ctx.formId&&formEl){var idInput=formEl.querySelector('[name="formId"]');if(idInput&&idInput.value){ctx.formId=idInput.value} 47var postInput=formEl.querySelector('[name="postId"]');if(postInput&&postInput.value){ctx.postId=parseInt(postInput.value,10)||0}} 48var errorType=classifyDomError(errorText);if(ctx.formId){clearPendingClick(ctx.formId)} 49logToServer(ctx,{type:errorType,message:errorText,code:0,source:'dom_observer',error_element:describeElement(errorEl)})} 50function classifyDomError(errorText){var lower=errorText.toLowerCase();if(lower.indexOf('recaptcha')!==-1||lower.indexOf('captcha')!==-1){return'recaptcha_error'} 51if(lower.indexOf('required')!==-1||lower.indexOf('povinné')!==-1||lower.indexOf('povinný')!==-1){return'validation_error'} 52if(lower.indexOf('email')!==-1&&(lower.indexOf('invalid')!==-1||lower.indexOf('neplatný')!==-1||lower.indexOf('neplatná')!==-1)){return'validation_error'}
53return'client_validation_error'} 54function startClickWatch(ctx,hit,event){clearPendingClick(ctx.formId);pendingClickTimers[ctx.formId]=setTimeout(function(){if(inFlight[ctx.formId]){return} 55logToServer(ctx,{type:'click_not_submitted',message:'User clicked submit area but no admin-ajax request was detected within '+CONFIG.CLICK_NO_REQUEST_TIMEOUT_MS+'ms',code:0,click_timeout_ms:CONFIG.CLICK_NO_REQUEST_TIMEOUT_MS,click_coords:{x:event.clientX,y:event.clientY},button_rect:hit.buttonRect,top_element:hit.topElement,overlay_detected:hit.overlayDetected,overlay_element:hit.overlayElement})},CONFIG.CLICK_NO_REQUEST_TIMEOUT_MS)} 56function clearPendingClick(formId){if(pendingClickTimers[formId]){clearTimeout(pendingClickTimers[formId]);delete pendingClickTimers[formId]}} 57function interceptAjax(){var originalOpen=XMLHttpRequest.prototype.open;var originalSend=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(method,url){this._apadoreUrl=url;this._apadoreMethod=method;return originalOpen.apply(this,arguments)};XMLHttpRequest.prototype.send=function(body){var xhr=this;var url=xhr._apadoreUrl||'';if(isBricksSubmitRequest(url,body)){var req=extractIdsFromBody(body);startRequestWatch(req,'xhr');xhr.addEventListener('loadend',function(){finishXhrRequest(req,xhr)});xhr.addEventListener('error',function(){failRequest(req,'submit_request_failed','XHR network error')});xhr.addEventListener('abort',function(){failRequest(req,'submit_request_aborted','XHR request aborted')});xhr.addEventListener('timeout',function(){failRequest(req,'submit_request_timeout','XHR request timeout')})} 58return originalSend.apply(this,arguments)};if(window.fetch){var originalFetch=window.fetch;window.fetch=function(url,options){try{var urlStr=typeof url==='string'?url:(url&&url.url)?url.url:'';var body=options&&options.body;if(isBricksSubmitRequest(urlStr,body)){var req=extractIdsFromBody(body);startRequestWatch(req,'fetch');return originalFetch.apply(this,arguments).then(function(response){inspectFetchResponse(req,response);finishRequest(req);return response},function(err){failRequest(req,'submit_request_failed','Fetch failed: '+safeString(err));throw err})}}catch(e){} 59return originalFetch.apply(this,arguments)}}} 60function isBricksSubmitRequest(url,body){if(!url||url.indexOf('admin-ajax.php')===-1){return!1} 61if(!body){return!1} 62if(body instanceof FormData){return body.get('action')==='bricks_form_submit'} 63if(typeof body==='string'){return body.indexOf('bricks_form_submit')!==-1} 64return!1} 65function extractIdsFromBody(body){var formId=null;var postId=0;var referrer=window.location.href;try{if(body instanceof FormData){formId=body.get('formId')||null;postId=parseInt(body.get('postId'),10)||0;referrer=body.get('referrer')||referrer}else if(typeof body==='string'){formId=matchParam(body,'formId');postId=parseInt(matchParam(body,'postId'),10)||0;referrer=matchParam(body,'referrer')||referrer}}catch(e){} 66return{formId:formId,postId:postId,referrer:referrer}} 67function matchParam(bodyStr,key){var re=new RegExp(key+'=([^&]+)');var match=bodyStr.match(re);return match?decodeURIComponent(match[1]):null} 68function startRequestWatch(req,transport){if(!req||!req.formId){return} 69clearPendingClick(req.formId);if(inFlight[req.formId]){return} 70inFlight[req.formId]={startedAt:Date.now(),transport:transport,slowLogged:!1,slowTimerId:setTimeout(function(){if(!inFlight[req.formId]||inFlight[req.formId].slowLogged){return} 71inFlight[req.formId].slowLogged=!0;logToServer({formId:req.formId,postId:req.postId,referrer:req.referrer,formEl:null},{type:'submit_request_slow',message:'Form submission request is still running after '+CONFIG.SLOW_REQUEST_TIMEOUT_MS+'ms',code:0,elapsed_ms:Date.now()-inFlight[req.formId].startedAt,slow_threshold_ms:CONFIG.SLOW_REQUEST_TIMEOUT_MS,transport:transport})},CONFIG.SLOW_REQUEST_TIMEOUT_MS)}} 72function finishXhrRequest(req,xhr){if(!req||!req.formId){return} 73try{var status=xhr.status;var text='';try{text=xhr.responseText||''}catch(e){text=''} 74if(status>=400){failRequest(req,'submit_invalid_response','HTTP '+status+' from admin-ajax.php',{http_status:status,response_snippet:limitText(text)});return}
75if(text&&!looksLikeJson(text)){failRequest(req,'submit_invalid_response','Non-JSON response from admin-ajax.php',{http_status:status,response_snippet:limitText(text)});return}}finally{finishRequest(req)}} 76function inspectFetchResponse(req,response){if(!req||!req.formId||!response){return} 77try{if(!response.ok){failRequest(req,'submit_invalid_response','HTTP '+response.status+' from admin-ajax.php',{http_status:response.status});return} 78var contentType=response.headers&&response.headers.get?response.headers.get('content-type'):'';if(contentType&&contentType.indexOf('application/json')===-1){failRequest(req,'submit_invalid_response','Non-JSON response content-type from admin-ajax.php',{http_status:response.status,content_type:contentType})}}catch(e){}} 79function finishRequest(req){if(!req||!req.formId||!inFlight[req.formId]){return} 80var info=inFlight[req.formId];clearTimeout(info.slowTimerId);var elapsed=Date.now()-info.startedAt;if(elapsed>=CONFIG.SLOW_REQUEST_TIMEOUT_MS&&!info.slowLogged){logToServer({formId:req.formId,postId:req.postId,referrer:req.referrer,formEl:null},{type:'submit_request_slow',message:'Form submission request completed but took '+elapsed+'ms',code:0,elapsed_ms:elapsed,slow_threshold_ms:CONFIG.SLOW_REQUEST_TIMEOUT_MS,transport:info.transport,completed:!0})} 81delete inFlight[req.formId]} 82function failRequest(req,type,message,extra){if(!req||!req.formId){return} 83var payload={type:type,message:message,code:0};if(extra&&typeof extra==='object'){Object.keys(extra).forEach(function(k){payload[k]=extra[k]})} 84logToServer({formId:req.formId,postId:req.postId,referrer:req.referrer,formEl:null},payload);finishRequest(req)} 85function getFormContext(submitButton){var formEl=submitButton.closest('form');var wrapper=submitButton.closest('.brxe-form, [data-element-id]')||formEl;var formId=null;var postId=0;var referrer=window.location.href;try{if(wrapper&&wrapper.dataset&&wrapper.dataset.elementId){formId=wrapper.dataset.elementId} 86if(!formId&&formEl){var idInput=formEl.querySelector('[name="formId"]');if(idInput&&idInput.value){formId=idInput.value} 87var postInput=formEl.querySelector('[name="postId"]');if(postInput&&postInput.value){postId=parseInt(postInput.value,10)||0} 88var refInput=formEl.querySelector('[name="referrer"]');if(refInput&&refInput.value){referrer=refInput.value}}}catch(e){} 89return{formId:formId,postId:postId,referrer:referrer,formEl:formEl}} 90function findSubmitHit(event){var x=event.clientX;var y=event.clientY;var direct=closestSubmit(event.target);if(direct){return buildHit(direct,event.target)} 91var submits=document.querySelectorAll('button[type="submit"], input[type="submit"], .brxe-submit, [data-submit]');for(var i=0;i<submits.length;i++){var el=submits[i];if(!el||!el.getBoundingClientRect){continue} 92var rect=el.getBoundingClientRect();if(x>=rect.left&&x<=rect.right&&y>=rect.top&&y<=rect.bottom){return buildHit(el,event.target)}} 93return null} 94function closestSubmit(node){if(!node){return null} 95if(isSubmit(node)){return node} 96if(node.closest){var c=node.closest('button[type="submit"], input[type="submit"], .brxe-submit, [data-submit]');return c&&isSubmit(c)?c:null} 97return null} 98function isSubmit(el){if(!el||!el.tagName){return!1} 99var tag=el.tagName.toLowerCase();if(tag==='button'&&el.type==='submit'){return!0} 100if(tag==='input'&&el.type==='submit'){return!0} 101if(el.classList&&el.classList.contains('brxe-submit')){return!0} 102if(el.hasAttribute&&el.hasAttribute('data-submit')){return!0} 103return!1} 104function buildHit(button,topElement){var rect=button.getBoundingClientRect();var overlayDetected=!!(topElement&&topElement!==button&&!(button.contains&&button.contains(topElement)));return{button:button,buttonRect:{x:rect.left,y:rect.top,width:rect.width,height:rect.height},topElement:describeElement(topElement),overlayDetected:overlayDetected,overlayElement:overlayDetected?describeElement(topElement):null}} 105function describeElement(el){if(!el||!el.tagName){return null} 106var desc=el.tagName.toLowerCase();if(el.id){desc+='#'+el.id} 107if(el.className&&typeof el.className==='string'){var classes=el.className.split(' ').slice(0,3).join('.');if(classes){desc+='.'+classes}} 108try{var style=window.getComputedStyle(el);var z=style&&style.zIndex;if(z&&z!=='auto'){desc+=' (z-index: '+z+')'}}catch(e){} 109return desc} 110function looksLikeJson(text){var t=String(text||'').trim();if(!t){return!1} 111return t.charAt(0)==='{'||t.charAt(0)==='['} 112function limitText(text){var t=String(text||'');if(t.length<=500){return t} 113return t.substring(0,500)+'...'} 114function safeString(err){try{if(!err){return''} 115if(typeof err==='string'){return err} 116if(err&&err.message){return String(err.message)} 117return String(err)}catch(e){return''}} 118function shouldLogOnce(key){var now=Date.now();if(recentLogs[key]&&now-recentLogs[key]<CONFIG.DUPLICATE_LOG_TTL_MS){return!1} 119recentLogs[key]=now;return!0} 120function logToServer(ctx,errorData){var dedupeKey=(ctx.formId||'unknown')+'|'+(errorData&&errorData.type?errorData.type:'unknown');if(!shouldLogOnce(dedupeKey)){return} 121var formFields={};if(ctx.formEl){formFields=extractFormFields(ctx.formEl)} 122var payload={form_id:ctx.formId,post_id:ctx.postId||0,referrer:ctx.referrer||window.location.href,error_data:errorData||{type:'frontend_error',message:'Unknown frontend error',code:0},form_fields:formFields};fetch(apadoreBricks.restUrl,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(function(){}).catch(function(){})} 123function extractFormFields(formEl){var fields={};if(!formEl||!formEl.elements){return fields} 124var skipFields=['action','postId','formId','referrer','nonce','_wp_http_referer','_wpnonce','g-recaptcha-response','h-captcha-response','cf-turnstile-response'];try{var elements=formEl.elements;for(var i=0;i<elements.length;i++){var el=elements[i];var name=el.name;if(!name){continue} 125if(skipFields.indexOf(name)!==-1){continue} 126if(el.type==='password'){fields[name]='[REDACTED]';continue} 127if(el.type==='file'){var fileNames=[];if(el.files&&el.files.length){for(var f=0;f<el.files.length;f++){fileNames.push(el.files[f].name)}} 128fields[name]=fileNames.length?'[FILES: '+fileNames.join(', ')+']':'[NO FILE]';continue} 129if(el.type==='checkbox'){if(el.checked){if(fields[name]){if(!Array.isArray(fields[name])){fields[name]=[fields[name]]} 130fields[name].push(el.value||'on')}else{fields[name]=el.value||'on'}} 131continue} 132if(el.type==='radio'){if(el.checked){fields[name]=el.value} 133continue} 134if(el.tagName.toLowerCase()==='select'&&el.multiple){var selected=[];for(var j=0;j<el.options.length;j++){if(el.options[j].selected){selected.push(el.options[j].value)}} 135fields[name]=selected;continue} 136fields[name]=el.value||''}}catch(e){log('Failed to extract form fields',e)} 137return fields} 138function log(){if(CONFIG.DEBUG&&console&&console.log){var args=Array.prototype.slice.call(arguments);args.unshift('[Apadore Forms Monitor]');console.log.apply(console,args)}}})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.