diff --git a/css/cleantalk-admin.min.css b/css/cleantalk-admin.min.css index 98506bac7..ec6d60958 100644 --- a/css/cleantalk-admin.min.css +++ b/css/cleantalk-admin.min.css @@ -1 +1 @@ -:disabled{cursor:not-allowed!important}.apbct_color--gray{color:gray}.apbct_display--none{display:none}.apbct_bottom_links--left{margin-right:2pc}.apbct_bottom_links--other{margin-right:2pc;margin-left:2pc}.ct_translate_links{color:#969614}.ct_support_links{color:#961414}.ct_faq_links{color:#149614}.ct_setting_links{color:#141496}.ct_translate_links:hover{color:#d2d214!important}.ct_support_links:hover{color:#fa1414!important}.ct_faq_links:hover{color:#14fa14!important}.ct_setting_links:hover{color:#1414fa!important}.ct_link_new_tab img{float:none!important;margin:0 2px;border:0}#negative_reports_table tr td{padding:7px 5px!important}#wp-admin-bar-cleantalk_admin_bar__parent_node{margin-right:5px}#wp-admin-bar-cleantalk_admin_bar__parent_node span{display:inline-block}#wp-admin-bar-cleantalk_admin_bar__parent_node .apbct-icon-attention-alt{background:#d63638;color:#fff;border-radius:50%;font-size:12px}#wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__spbc_icon{width:14px;height:17px;margin-top:7px}#wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__apbct_icon{width:18px;height:18px;margin-top:7px}#wp-admin-bar-cleantalk_admin_bar__parent_node div.cleantalk_admin_bar__sum_counter{color:#999;display:inline;padding:2px 5px!important}.cleantalk_admin_bar__blocked div{cursor:not-allowed!important}.cleantalk_admin_bar__blocked div a{color:#777!important}.cleantalk_admin_bar__title{vertical-align:top}.cleantalk_admin_bar__separator{height:0!important}.cleantalk-admin_bar--list_wrapper .ab-sub-wrapper ul:last-child{margin-bottom:5px!important}.apbct-plugin-errors{margin-left:0;margin-bottom:20px}#cleantalk_notice_review .caption{margin:0 0 15px;color:gray}#cleantalk_notice_review .button{margin-bottom:20px}.apbct-restore-spam-order-button{cursor:pointer}.ct-modal-buttons{display:flex;align-items:center;padding:20px 0;justify-content:space-between}.ct-modal-message{font-weight:700;font-size:16px;line-height:2rem}.apbct-popup-fade:before{content:'';background:#000;position:fixed;left:0;top:0;width:100%;height:100%;opacity:.7;z-index:9999}.apbct-popup{position:fixed;top:20%;left:50%;padding:20px;width:360px;margin-left:-200px;background:#fff;border:1px solid;border-radius:4px;z-index:99999;opacity:1}.apbct-table-actions-wrapper{background:#FСFСFС;border-radius:2px;padding:5px!important;border:1px solid #d3d3d3;margin:0 5px 5px 0!important}@media screen and (max-width:1120px){.apbct-tablenav{display:flex;flex-direction:column;flex-wrap:nowrap;height:100%;max-width:50%}} \ No newline at end of file +:disabled{cursor:not-allowed!important}.apbct_color--gray{color:gray}.apbct_display--none{display:none}.apbct_bottom_links--left{margin-right:2pc}.apbct_bottom_links--other{margin-right:2pc;margin-left:2pc}.ct_translate_links{color:#969614}.ct_support_links{color:#961414}.ct_faq_links{color:#149614}.ct_setting_links{color:#141496}.ct_translate_links:hover{color:#d2d214!important}.ct_support_links:hover{color:#fa1414!important}.ct_faq_links:hover{color:#14fa14!important}.ct_setting_links:hover{color:#1414fa!important}.ct_link_new_tab img{float:none!important;margin:0 2px;border:0}#negative_reports_table tr td{padding:7px 5px!important}#wp-admin-bar-cleantalk_admin_bar__parent_node{margin-right:5px}#wp-admin-bar-cleantalk_admin_bar__parent_node span{display:inline-block}#wp-admin-bar-cleantalk_admin_bar__parent_node .apbct-icon-attention-alt{background:#d63638;color:#fff;border-radius:50%;font-size:12px}#wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__spbc_icon{width:14px;height:17px;margin-top:7px}#wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__apbct_icon{width:18px;height:18px;margin-top:7px}#wp-admin-bar-cleantalk_admin_bar__parent_node div.cleantalk_admin_bar__sum_counter{color:#999;display:inline;padding:2px 5px!important}.cleantalk_admin_bar__blocked div{cursor:not-allowed!important}.cleantalk_admin_bar__blocked div a{color:#777!important}.cleantalk_admin_bar__title{vertical-align:top}.cleantalk_admin_bar__separator{height:0!important}.cleantalk-admin_bar--list_wrapper .ab-sub-wrapper ul:last-child{margin-bottom:5px!important}.apbct-plugin-errors{margin-left:0;margin-bottom:20px}#cleantalk_notice_review .caption{margin:0 0 15px;color:gray}#cleantalk_notice_review .button{margin-bottom:20px}.apbct-details-spam-order-button,.apbct-restore-spam-order-button{cursor:pointer}.apbct-details-spam-order-button{color:gray}.ct-modal-buttons{display:flex;align-items:center;padding:20px 0;justify-content:space-between}.ct-modal-message{font-weight:700;font-size:16px;line-height:2rem}.apbct-popup-fade:before{content:'';background:#000;position:fixed;left:0;top:0;width:100%;height:100%;opacity:.7;z-index:9999}.apbct-popup{position:fixed;top:20%;left:50%;padding:20px;width:360px;margin-left:-200px;background:#fff;border:1px solid;border-radius:4px;z-index:99999;opacity:1}.apbct-table-actions-wrapper{background:#fcfcfc;border-radius:2px;padding:5px!important;border:1px solid #d3d3d3;margin:0 5px 5px 0!important}.apbct_wc_details__table-container_header{text-align:center}.apbct_wc_details__wrapper{display:flex;flex-direction:column;scroll-behavior:smooth;overflow-y:auto;max-height:400px;min-width:50pc;position:relative}.apbct_wc_details__table-wrapper-inner{margin-bottom:25px;background:#f9f9f9;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.08);position:relative;padding:0 15px}.apbct_wc_details__table-wrapper-inner h4{margin:0 0 12px 0;color:#333;font-size:16px;font-weight:600;padding:10px 0 8px 0;border-bottom:2px solid #e0e0e0;position:sticky;top:0;background:#f9f9f9;z-index:10}.apbct_wc_details__table{width:100%;border-collapse:collapse;background:#fff;border-radius:6px;overflow:hidden}.apbct_wc_details__table-key-cell{border:1px solid #e8e8e8;padding:10px 12px;font-weight:600;background:#f5f7fa;color:#2c3e50;width:35%;font-size:13px}.apbct_wc_details__table-value-cell{border:1px solid #e8e8e8;padding:10px 12px;color:#34495e;font-size:13px;word-break:break-word}.apbct_wc_details__table tbody tr:hover{background:#fafbfc}.apbct_wc_details__table tbody tr:last-child td{border-bottom:none}.apbct_wc_details__table-value-cell--json{font-family:monospace;font-size:12px;white-space:pre-wrap}@supports (position:sticky){.apbct_wc_details__table th,.apbct_wc_details__table-wrapper-inner h4{position:sticky}}@media screen and (max-width:1120px){.apbct-tablenav{display:flex;flex-direction:column;flex-wrap:nowrap;height:100%;max-width:50%}} \ No newline at end of file diff --git a/css/src/cleantalk-admin.css b/css/src/cleantalk-admin.css index 57dbaad32..006357f86 100644 --- a/css/src/cleantalk-admin.css +++ b/css/src/cleantalk-admin.css @@ -98,9 +98,13 @@ #cleantalk_notice_review .button { margin-bottom: 20px; } -.apbct-restore-spam-order-button { +.apbct-restore-spam-order-button, .apbct-details-spam-order-button { cursor: pointer; } + +.apbct-details-spam-order-button { + color: gray; +} .ct-modal-buttons { display: flex; align-items: center; @@ -140,13 +144,98 @@ } .apbct-table-actions-wrapper { - background: #FСFСFС; + background: #fcfcfc; border-radius: 2px; padding: 5px !important; border: 1px solid lightgray; margin: 0 5px 5px 0 !important; } +.apbct_wc_details__table-container_header { + text-align: center; +} + +.apbct_wc_details__wrapper { + display: flex; + flex-direction: column; + scroll-behavior: smooth; + overflow-y: auto; + max-height: 400px; + min-width: 50pc; + position: relative; +} + +.apbct_wc_details__table-wrapper-inner { + margin-bottom: 25px; + background: #f9f9f9; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.08); + position: relative; + padding: 0 15px; +} + +.apbct_wc_details__table-wrapper-inner h4 { + margin: 0 0 12px 0; + color: #333; + font-size: 16px; + font-weight: 600; + padding: 10px 0 8px 0; + border-bottom: 2px solid #e0e0e0; + position: sticky; + top: 0; + background: #f9f9f9; + z-index: 10; +} + +.apbct_wc_details__table { + width: 100%; + border-collapse: collapse; + background: white; + border-radius: 6px; + overflow: hidden; +} + +.apbct_wc_details__table-key-cell { + border: 1px solid #e8e8e8; + padding: 10px 12px; + font-weight: 600; + background: #f5f7fa; + color: #2c3e50; + width: 35%; + font-size: 13px; +} + +.apbct_wc_details__table-value-cell { + border: 1px solid #e8e8e8; + padding: 10px 12px; + color: #34495e; + font-size: 13px; + word-break: break-word; +} + +.apbct_wc_details__table tbody tr:hover { + background: #fafbfc; +} + +.apbct_wc_details__table tbody tr:last-child td { + border-bottom: none; +} + +.apbct_wc_details__table-value-cell--json { + font-family: monospace; + font-size: 12px; + white-space: pre-wrap; +} + +/* Safari and older browsers support */ +@supports (position: sticky) { + .apbct_wc_details__table-wrapper-inner h4, + .apbct_wc_details__table th { + position: sticky; + } +} + + @media screen and (max-width: 1120px) { .apbct-tablenav { display: flex; diff --git a/js/cleantalk-admin.min.js b/js/cleantalk-admin.min.js index e914aef60..e5384117f 100644 --- a/js/cleantalk-admin.min.js +++ b/js/cleantalk-admin.min.js @@ -1,2 +1,2 @@ -function apbct_admin_sendAJAX(t,n,c){let o=n.callback||null,i=n.callback_context||null,a=n.callback_params||null;var e=n.async||!0;let d=n.notJson||null;var l=n.timeout||15e3,c=c||null;let r=n.button||null,s=n.spinner||null,u=n.progressbar||null;"string"==typeof t?t=t+"&_ajax_nonce="+ctAdminCommon._ajax_nonce+"&no_cache="+Math.random():(t._ajax_nonce=ctAdminCommon._ajax_nonce,t.no_cache=Math.random()),r&&(r.setAttribute("disabled","disabled"),r.style.cursor="not-allowed"),s&&jQuery(s).css("display","inline"),jQuery.ajax({type:"POST",url:ctAdminCommon._ajax_url,data:t,async:e,success:function(e){r&&(r.removeAttribute("disabled"),r.style.cursor="pointer"),s&&jQuery(s).css("display","none"),(e=d?e:JSON.parse(e)).error?(setTimeout(function(){u&&u.fadeOut("slow")},1e3),"undefined"!=typeof cleantalkModal?(cleantalkModal.loaded="Error:
"+e.error.toString(),cleantalkModal.open()):alert("Error happens: "+(e.error||"Unkown"))):o&&(a?o.apply(i,a.concat(e,t,n,c)):o(e,t,n,c))},error:function(e,t,n){r&&(r.removeAttribute("disabled"),r.style.cursor="pointer"),s&&jQuery(s).css("display","none"),console.log("APBCT_AJAX_ERROR"),console.log(e),console.log(t),console.log(n)},timeout:l})}function apbctSetEmailDecoderPopupAnimation(){var t=["apbct_dog_one","apbct_dog_two","apbct_dog_three"],n=document.createElement("div");n.classList="apbct-ee-animation-wrapper";for(let e=0;e{e.encoded_email===a.dataset.originalString&&(t=e)}),e=t.decoded_email.split(/[&?]/)[0]}else e=o.data[0].decoded_email;var n=t.querySelector("#apbct_email_ecoder__popup_text_node_first"),c=document.createElement("b"),c=(c.setAttribute("class","apbct-email-encoder-select-whole-email"),c.innerText=e,"undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_click_to_select?c.title=ctPublicFunctions.text__ee_click_to_select:c.title=ctAdminCommon.text__ee_click_to_select,n&&("undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_original_email?n.innerHTML=ctPublicFunctions.text__ee_original_email+" "+c.outerHTML:n.innerHTML=ctAdminCommon.text__ee_original_email+" "+c.outerHTML,n.setAttribute("style","flex-direction: row;")),t.querySelector(".apbct-ee-animation-wrapper")),n=(c&&c.remove(),t.querySelector("#apbct_email_ecoder__popup_text_node_second")),c=(n&&n.remove(),document.createElement("span"));c.classList="apbct-email-encoder-elements_center top-margin-long",document.querySelector(".apbct-email-encoder-got-it-button")||(n=document.createElement("button"),"undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_got_it?n.innerText=ctPublicFunctions.text__ee_got_it:n.innerText=ctAdminCommon.text__ee_got_it,n.classList="apbct-email-encoder-got-it-button",n.addEventListener("click",function(){document.body.classList.remove("apbct-popup-fade"),t.setAttribute("style","display:none"),fillDecodedNodes(i,o),"undefined"!=typeof ctPublic&&ctPublic.encodedEmailNodesIsMixed&&a&&a.click()}),c.append(n),t.append(c))}},3e3);else if(a){let e="unknown_error";o.hasOwnProperty("data")&&0{e.encoded_email===c[n].dataset.originalString&&(t=e)}),!1===t.is_allowed)return;if(void 0===c[n].href||0!==c[n].href.indexOf("mailto:")&&0!==c[n].href.indexOf("tel:"))c[n].classList.add("no-blur"),setTimeout(()=>{ctProcessDecodedDataResult(t,c[n])},2e3);else{let e;if(0===c[n].href.indexOf("mailto:"))e="mailto:";else{if(0!==c[n].href.indexOf("tel:"))continue;e="tel:"}var i=c[n].href.replace(e,""),a=c[n].innerHTML;c[n].innerHTML=a.replace(i,t.decoded_email),c[n].href=e+t.decoded_email,c[n].querySelectorAll("span.apbct-email-encoder").forEach(t=>{let n="";o.data.forEach(e=>{e.encoded_email===t.dataset.originalString&&(n=e.decoded_email)}),t.innerHTML=n})}c[n].removeEventListener("click",ctFillDecodedEmailHandler)}else{let e=o.data[0];c.classList.add("no-blur"),setTimeout(()=>{ctProcessDecodedDataResult(e,c)},2e3),c.removeEventListener("click",ctFillDecodedEmailHandler)}}function ctProcessDecodedDataResult(e,t){t.setAttribute("title",""),t.removeAttribute("style"),ctFillDecodedEmail(t,e.decoded_email)}function ctFillDecodedEmail(e,t){e.innerHTML=e.innerHTML.replace(/.+?(
)/,t+"$1")}jQuery(document).ready(function(t){jQuery(".apbct_update_notice").on("click","button",function(){var e=new Date((new Date).getTime()+2592e6),t="https:"===location.protocol?"; secure":"";document.cookie="apbct_update_banner_closed=1; path=/; expires="+e.toUTCString()+"; samesite=lax"+t}),jQuery('li a[href="options-general.php?page=cleantalk"]').css("white-space","nowrap").css("display","inline-block"),jQuery("body").on("click",".apbct-notice .notice-dismiss-link",function(e){jQuery(e.target).parent().parent(".notice").after('

'+ctAdminCommon.apbctNoticeDismissSuccess+"

"),setTimeout(function(){jQuery("#apbct-notice-dismiss-success").fadeOut()},2e3),jQuery(e.target).parent().siblings(".apbct-notice .notice-dismiss").click()}),jQuery("body").on("click",".apbct-notice .notice-dismiss",function(e){e=jQuery(e.target).parent().attr("id");e&&apbct_admin_sendAJAX({action:"cleantalk_dismiss_notice",notice_id:e},{callback:null,notJson:!0})}),jQuery(".ct_username .row-actions .delete a").on("click",function(e){e.preventDefault(),confirm(ctAdminCommon.notice_when_deleting_user_text)&&(window.location=this.href)});let n=document.querySelector("#apbct_setting_forms__force_protection__On");var e;n&&n.addEventListener("click",function(e){n.checked&&!confirm(ctAdminCommon.apbctNoticeForceProtectionOn)&&e.preventDefault()}),t(".apbct-restore-spam-order-button").click(function(){var e=t(this).data("spam-order-id"),e={action:"apbct_restore_spam_order",_ajax_nonce:ctAdminCommon._ajax_nonce,order_id:e};t.ajax({type:"POST",url:ctAdminCommon._ajax_url,data:e,success:function(e){e.success?window.location.reload():alert(e.data.message)}})}),window.location.href.includes("options-general.php?page=cleantalk")&&(e=document.querySelector("[data-original-string]"))&&((ctAdminCommon.encodedEmailNode=e).style.cursor="pointer",e.addEventListener("click",ctFillDecodedEmailHandler))}),document.addEventListener("DOMContentLoaded",function(){var t=document.querySelectorAll("[data-original-string]");if("undefined"!=typeof ctPublic&&(ctPublic.encodedEmailNodes=t),t.length)for(let e=0;e{e.encoded_email===i.dataset.originalString&&(t=e)}),e=t.decoded_email.split(/[&?]/)[0]}else e=o.data[0].decoded_email;var n=t.querySelector("#apbct_email_ecoder__popup_text_node_first"),c=document.createElement("b"),c=(c.setAttribute("class","apbct-email-encoder-select-whole-email"),c.innerText=e,"undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_click_to_select?c.title=ctPublicFunctions.text__ee_click_to_select:c.title=ctAdminCommon.text__ee_click_to_select,n&&("undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_original_email?n.innerHTML=ctPublicFunctions.text__ee_original_email+" "+c.outerHTML:n.innerHTML=ctAdminCommon.text__ee_original_email+" "+c.outerHTML,n.setAttribute("style","flex-direction: row;")),t.querySelector(".apbct-ee-animation-wrapper")),n=(c&&c.remove(),t.querySelector("#apbct_email_ecoder__popup_text_node_second")),c=(n&&n.remove(),document.createElement("span"));c.classList="apbct-email-encoder-elements_center top-margin-long",document.querySelector(".apbct-email-encoder-got-it-button")||(n=document.createElement("button"),"undefined"!=typeof ctPublicFunctions&&ctPublicFunctions.text__ee_got_it?n.innerText=ctPublicFunctions.text__ee_got_it:n.innerText=ctAdminCommon.text__ee_got_it,n.classList="apbct-email-encoder-got-it-button",n.addEventListener("click",function(){document.body.classList.remove("apbct-popup-fade"),t.setAttribute("style","display:none"),fillDecodedNodes(a,o),"undefined"!=typeof ctPublic&&ctPublic.encodedEmailNodesIsMixed&&i&&i.click()}),c.append(n),t.append(c))}},3e3);else if(i){let e="unknown_error";o.hasOwnProperty("data")&&0{e.encoded_email===c[n].dataset.originalString&&(t=e)}),!1===t.is_allowed)return;if(void 0===c[n].href||0!==c[n].href.indexOf("mailto:")&&0!==c[n].href.indexOf("tel:"))c[n].classList.add("no-blur"),setTimeout(()=>{ctProcessDecodedDataResult(t,c[n])},2e3);else{let e;if(0===c[n].href.indexOf("mailto:"))e="mailto:";else{if(0!==c[n].href.indexOf("tel:"))continue;e="tel:"}var a=c[n].href.replace(e,""),i=c[n].innerHTML;c[n].innerHTML=i.replace(a,t.decoded_email),c[n].href=e+t.decoded_email,c[n].querySelectorAll("span.apbct-email-encoder").forEach(t=>{let n="";o.data.forEach(e=>{e.encoded_email===t.dataset.originalString&&(n=e.decoded_email)}),t.innerHTML=n})}c[n].removeEventListener("click",ctFillDecodedEmailHandler)}else{let e=o.data[0];c.classList.add("no-blur"),setTimeout(()=>{ctProcessDecodedDataResult(e,c)},2e3),c.removeEventListener("click",ctFillDecodedEmailHandler)}}function ctProcessDecodedDataResult(e,t){t.setAttribute("title",""),t.removeAttribute("style"),ctFillDecodedEmail(t,e.decoded_email)}function ctFillDecodedEmail(e,t){e.innerHTML=e.innerHTML.replace(/.+?(
)/,t+"$1")}jQuery(document).ready(function(o){jQuery(".apbct_update_notice").on("click","button",function(){var e=new Date((new Date).getTime()+2592e6),t="https:"===location.protocol?"; secure":"";document.cookie="apbct_update_banner_closed=1; path=/; expires="+e.toUTCString()+"; samesite=lax"+t}),jQuery('li a[href="options-general.php?page=cleantalk"]').css("white-space","nowrap").css("display","inline-block"),jQuery("body").on("click",".apbct-notice .notice-dismiss-link",function(e){jQuery(e.target).parent().parent(".notice").after('

'+ctAdminCommon.apbctNoticeDismissSuccess+"

"),setTimeout(function(){jQuery("#apbct-notice-dismiss-success").fadeOut()},2e3),jQuery(e.target).parent().siblings(".apbct-notice .notice-dismiss").click()}),jQuery("body").on("click",".apbct-notice .notice-dismiss",function(e){e=jQuery(e.target).parent().attr("id");e&&apbct_admin_sendAJAX({action:"cleantalk_dismiss_notice",notice_id:e},{callback:null,notJson:!0})}),jQuery(".ct_username .row-actions .delete a").on("click",function(e){e.preventDefault(),confirm(ctAdminCommon.notice_when_deleting_user_text)&&(window.location=this.href)});let t=document.querySelector("#apbct_setting_forms__force_protection__On");var e;t&&t.addEventListener("click",function(e){t.checked&&!confirm(ctAdminCommon.apbctNoticeForceProtectionOn)&&e.preventDefault()}),o(".apbct-restore-spam-order-button").click(function(){var e=o(this).data("spam-order-id"),e={action:"apbct_restore_spam_order",_ajax_nonce:ctAdminCommon._ajax_nonce,order_id:e};o.ajax({type:"POST",url:ctAdminCommon._ajax_url,data:e,success:function(e){e.success?window.location.reload():alert(e.data.message)}})}),o(".apbct-details-spam-order-button").click(function(){var e=o(this).data("spam-order-id"),e={action:"apbct_details_spam_order",_ajax_nonce:ctAdminCommon._ajax_nonce,order_id:e};"undefined"!=typeof cleantalkModal?(cleantalkModal.loaded=!1,cleantalkModal.open(!1),o.ajax({type:"POST",url:ctAdminCommon._ajax_url,data:e,success:function(e){var t,n,c=o("#cleantalk-modal-content");c.empty(),e.success&&e.data?(t=apbctGetWCOrderDetailsModalContainer(e.data),(n=document.createElement("h3")).className="apbct_wc_details__table-container_header",n.textContent="WooCommerce spam order details",c.append(n),c.append(t)):(n=e.data.error||"Unknown error occurred",c.text(n)),cleantalkModal.loaded=!0},error:function(e,t,n){console.error("AJAX Error:",n),alert("An error occurred while processing your request, see console for details.")}})):alert("Can not initialize CleanTalk modal window.")}),window.location.href.includes("options-general.php?page=cleantalk")&&(e=document.querySelector("[data-original-string]"))&&((ctAdminCommon.encodedEmailNode=e).style.cursor="pointer",e.addEventListener("click",ctFillDecodedEmailHandler))}),document.addEventListener("DOMContentLoaded",function(){var t=document.querySelectorAll("[data-original-string]");if("undefined"!=typeof ctPublic&&(ctPublic.encodedEmailNodes=t),t.length)for(let e=0;e

' +\n ctAdminCommon.apbctNoticeDismissSuccess +\n '

');\n setTimeout(function() {\n jQuery('#apbct-notice-dismiss-success').fadeOut();\n }, 2000);\n jQuery(e.target).parent().siblings('.apbct-notice .notice-dismiss').click();\n });\n jQuery('body').on('click', '.apbct-notice .notice-dismiss', function(e) {\n let apbctNoticeName = jQuery(e.target).parent().attr('id');\n if ( apbctNoticeName ) {\n apbct_admin_sendAJAX(\n {\n 'action': 'cleantalk_dismiss_notice',\n 'notice_id': apbctNoticeName,\n },\n {\n 'callback': null,\n 'notJson': true,\n },\n );\n }\n });\n\n // Notice when deleting user\n jQuery('.ct_username .row-actions .delete a').on('click', function(e) {\n e.preventDefault();\n\n let result = confirm(ctAdminCommon.notice_when_deleting_user_text);\n\n if (result) {\n window.location = this.href;\n }\n });\n\n let btnForceProtectionOn = document.querySelector('#apbct_setting_forms__force_protection__On');\n if (btnForceProtectionOn) {\n btnForceProtectionOn.addEventListener('click', function(e) {\n if (btnForceProtectionOn.checked) {\n let result = confirm(ctAdminCommon.apbctNoticeForceProtectionOn);\n\n if (!result) {\n e.preventDefault();\n }\n }\n });\n }\n // Restore spam order\n $('.apbct-restore-spam-order-button').click(function() {\n const spmOrderId = $(this).data('spam-order-id');\n let data = {\n action: 'apbct_restore_spam_order',\n _ajax_nonce: ctAdminCommon._ajax_nonce,\n order_id: spmOrderId,\n };\n $.ajax({\n type: 'POST',\n url: ctAdminCommon._ajax_url,\n data: data,\n success: function(result) {\n if (result.success) {\n window.location.reload();\n } else {\n alert(result.data.message);\n }\n },\n });\n });\n\n // Email decoder example\n if (window.location.href.includes('options-general.php?page=cleantalk')) {\n let encodedEmailNode = document.querySelector('[data-original-string]');\n if (encodedEmailNode) {\n ctAdminCommon.encodedEmailNode = encodedEmailNode;\n encodedEmailNode.style.cursor = 'pointer';\n encodedEmailNode.addEventListener('click', ctFillDecodedEmailHandler);\n }\n }\n});\n// eslint-disable-next-line camelcase,require-jsdoc,no-unused-vars\nfunction apbct_admin_sendAJAX(data, params, obj) {\n // Default params\n let callback = params.callback || null;\n let callbackContext = params.callback_context || null;\n let callbackParams = params.callback_params || null;\n let async = params.async || true;\n let notJson = params.notJson || null;\n let timeout = params.timeout || 15000;\n var obj = obj || null; // eslint-disable-line no-var\n let button = params.button || null;\n let spinner = params.spinner || null;\n let progressbar = params.progressbar || null;\n\n if (typeof (data) === 'string') {\n data = data + '&_ajax_nonce=' + ctAdminCommon._ajax_nonce + '&no_cache=' + Math.random();\n } else {\n data._ajax_nonce = ctAdminCommon._ajax_nonce;\n data.no_cache = Math.random();\n }\n // Button and spinner\n if (button) {\n button.setAttribute('disabled', 'disabled'); button.style.cursor = 'not-allowed';\n }\n if (spinner) jQuery(spinner).css('display', 'inline');\n\n jQuery.ajax({\n type: 'POST',\n url: ctAdminCommon._ajax_url,\n data: data,\n async: async,\n success: function(result) {\n if (button) {\n button.removeAttribute('disabled'); button.style.cursor = 'pointer';\n }\n if (spinner) jQuery(spinner).css('display', 'none');\n if (!notJson) result = JSON.parse(result);\n if (result.error) {\n setTimeout(function() {\n if (progressbar) progressbar.fadeOut('slow');\n }, 1000);\n if ( typeof cleantalkModal !== 'undefined' ) {\n // Show the result by modal\n cleantalkModal.loaded = 'Error:
' + result.error.toString();\n cleantalkModal.open();\n } else {\n alert('Error happens: ' + (result.error || 'Unkown'));\n }\n } else {\n if (callback) {\n if (callbackParams) {\n callback.apply( callbackContext, callbackParams.concat( result, data, params, obj ) );\n } else {\n callback(result, data, params, obj);\n }\n }\n }\n },\n error: function(jqXHR, textStatus, errorThrown) {\n if (button) {\n button.removeAttribute('disabled'); button.style.cursor = 'pointer';\n }\n if (spinner) jQuery(spinner).css('display', 'none');\n console.log('APBCT_AJAX_ERROR');\n console.log(jqXHR);\n console.log(textStatus);\n console.log(errorThrown);\n },\n timeout: timeout,\n });\n}\n","/**\n * @return {HTMLElement} event\n */\nfunction apbctSetEmailDecoderPopupAnimation() {\n const animationElements = ['apbct_dog_one', 'apbct_dog_two', 'apbct_dog_three'];\n const animationWrapper = document.createElement('div');\n animationWrapper.classList = 'apbct-ee-animation-wrapper';\n for (let i = 0; i < animationElements.length; i++) {\n const apbctEEAnimationDogOne = document.createElement('span');\n apbctEEAnimationDogOne.classList = 'apbct_dog ' + animationElements[i];\n apbctEEAnimationDogOne.innerText = '@';\n animationWrapper.append(apbctEEAnimationDogOne);\n }\n return animationWrapper;\n}\n\n/**\n * @param {mixed} event\n */\nfunction ctFillDecodedEmailHandler(event = false) {\n let clickSource = false;\n let ctWlBrandname = '';\n let encodedEmail = '';\n if (typeof ctPublic !== 'undefined') {\n this.removeEventListener('click', ctFillDecodedEmailHandler);\n // remember clickSource\n clickSource = this;\n // globally remember if emails is mixed with mailto\n ctPublic.encodedEmailNodesIsMixed = false;\n ctWlBrandname = ctPublic.wl_brandname;\n encodedEmail = ctPublic.encodedEmailNodes;\n } else if (typeof ctAdminCommon !== 'undefined') {\n ctWlBrandname = ctAdminCommon.plugin_name;\n encodedEmail = ctAdminCommon.encodedEmailNode;\n }\n\n // get fade\n document.body.classList.add('apbct-popup-fade');\n // popup show\n let encoderPopup = document.getElementById('apbct_popup');\n if (!encoderPopup) {\n // construct popup\n let waitingPopup = document.createElement('div');\n waitingPopup.setAttribute('class', 'apbct-popup apbct-email-encoder-popup');\n waitingPopup.setAttribute('id', 'apbct_popup');\n\n // construct text header\n let popupHeaderWrapper = document.createElement('span');\n popupHeaderWrapper.classList = 'apbct-email-encoder-elements_center';\n let popupHeader = document.createElement('p');\n popupHeader.innerText = ctWlBrandname;\n popupHeader.setAttribute('class', 'apbct-email-encoder--popup-header');\n popupHeaderWrapper.append(popupHeader);\n\n // construct text wrapper\n let popupTextWrapper = document.createElement('div');\n popupTextWrapper.setAttribute('id', 'apbct_popup_text');\n popupTextWrapper.setAttribute('class', 'apbct-email-encoder-elements_center');\n popupTextWrapper.style.color = 'black';\n\n // construct text first node\n // todo make translatable\n let popupTextWaiting = document.createElement('p');\n popupTextWaiting.id = 'apbct_email_ecoder__popup_text_node_first';\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_wait_for_decoding) {\n popupTextWaiting.innerText = ctPublicFunctions.text__ee_wait_for_decoding;\n } else {\n popupTextWaiting.innerText = ctAdminCommon.text__ee_wait_for_decoding;\n }\n popupTextWaiting.setAttribute('class', 'apbct-email-encoder-elements_center');\n\n // construct text second node\n // todo make translatable\n let popupTextDecoding = document.createElement('p');\n popupTextDecoding.id = 'apbct_email_ecoder__popup_text_node_second';\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_decoding_process) {\n popupTextDecoding.innerText = ctPublicFunctions.text__ee_decoding_process;\n } else {\n popupTextDecoding.innerText = ctAdminCommon.text__ee_decoding_process;\n }\n\n // appending\n popupTextWrapper.append(popupTextWaiting);\n popupTextWrapper.append(popupTextDecoding);\n waitingPopup.append(popupHeaderWrapper);\n waitingPopup.append(popupTextWrapper);\n waitingPopup.append(apbctSetEmailDecoderPopupAnimation());\n document.body.append(waitingPopup);\n } else {\n encoderPopup.setAttribute('style', 'display: inherit');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_wait_for_decoding) {\n document.getElementById('apbct_popup_text').innerHTML = ctPublicFunctions.text__ee_wait_for_decoding;\n } else {\n document.getElementById('apbct_popup_text').innerHTML = ctAdminCommon.text__ee_wait_for_decoding;\n }\n }\n\n apbctAjaxEmailDecodeBulk(event, encodedEmail, clickSource);\n}\n\n/**\n * @param {mixed} event\n * @param {mixed} encodedEmailNodes\n * @param {mixed} clickSource\n */\nfunction apbctAjaxEmailDecodeBulk(event, encodedEmailNodes, clickSource) {\n if (event && clickSource) {\n // collect data\n let data = {\n post_url: document.location.href,\n referrer: document.referrer,\n encodedEmails: '',\n };\n if (+ctPublic.bot_detector_enabled) {\n data.event_token = apbctLocalStorage.get('bot_detector_event_token');\n } else {\n data.event_javascript_data = getJavascriptClientData();\n }\n\n let encodedEmailsCollection = {};\n for (let i = 0; i < encodedEmailNodes.length; i++) {\n // disable click for mailto\n if (\n typeof encodedEmailNodes[i].href !== 'undefined' &&\n encodedEmailNodes[i].href.indexOf('mailto:') === 0\n ) {\n event.preventDefault();\n ctPublic.encodedEmailNodesIsMixed = true;\n }\n\n // Adding a tooltip\n let apbctTooltip = document.createElement('div');\n apbctTooltip.setAttribute('class', 'apbct-tooltip');\n apbct(encodedEmailNodes[i]).append(apbctTooltip);\n\n // collect encoded email strings\n encodedEmailsCollection[i] = encodedEmailNodes[i].dataset.originalString;\n }\n\n // JSONify encoded email strings\n data.encodedEmails = JSON.stringify(encodedEmailsCollection);\n\n // Using REST API handler\n if ( ctPublicFunctions.data__ajax_type === 'rest' ) {\n apbct_public_sendREST(\n 'apbct_decode_email',\n {\n data: data,\n method: 'POST',\n callback: function(result) {\n // set alternative cookie to skip next pages encoding\n ctSetCookie('apbct_email_encoder_passed', ctPublic.emailEncoderPassKey, '');\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource);\n },\n onErrorCallback: function(res) {\n resetEncodedNodes();\n ctShowDecodeComment(res);\n },\n },\n );\n\n // Using AJAX request and handler\n } else {\n data.action = 'apbct_decode_email';\n apbct_public_sendAJAX(\n data,\n {\n notJson: false,\n callback: function(result) {\n // set alternative cookie to skip next pages encoding\n ctSetCookie('apbct_email_encoder_passed', ctPublic.emailEncoderPassKey, '');\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource);\n },\n onErrorCallback: function(res) {\n resetEncodedNodes();\n ctShowDecodeComment(res);\n },\n },\n );\n }\n } else {\n const encodedEmail = encodedEmailNodes.dataset.originalString;\n let data = {\n encodedEmails: JSON.stringify({0: encodedEmail}),\n };\n\n // Adding a tooltip\n let apbctTooltip = document.createElement('div');\n apbctTooltip.setAttribute('class', 'apbct-tooltip');\n encodedEmailNodes.appendChild(apbctTooltip);\n\n apbct_admin_sendAJAX(\n {\n 'action': 'apbct_decode_email',\n 'encodedEmails': data.encodedEmails,\n },\n {\n 'callback': function(result) {\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, false);\n },\n 'notJson': true,\n },\n );\n }\n}\n\n/**\n * @param {mixed} result\n * @param {mixed} encodedEmailNodes\n * @param {mixed} clickSource\n */\nfunction apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource = false) {\n if (result.success && result.data[0].is_allowed === true) {\n // start process of visual decoding\n setTimeout(function() {\n // popup remove\n let popup = document.getElementById('apbct_popup');\n if (popup !== null) {\n let email = '';\n if (clickSource) {\n let currentResultData;\n result.data.forEach((row) => {\n if (row.encoded_email === clickSource.dataset.originalString) {\n currentResultData = row;\n }\n });\n\n email = currentResultData.decoded_email.split(/[&?]/)[0];\n } else {\n email = result.data[0].decoded_email;\n }\n // handle first node\n let firstNode = popup.querySelector('#apbct_email_ecoder__popup_text_node_first');\n // get email selectable by click\n let selectableEmail = document.createElement('b');\n selectableEmail.setAttribute('class', 'apbct-email-encoder-select-whole-email');\n selectableEmail.innerText = email;\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_click_to_select) {\n selectableEmail.title = ctPublicFunctions.text__ee_click_to_select;\n } else {\n selectableEmail.title = ctAdminCommon.text__ee_click_to_select;\n }\n // add email to the first node\n if (firstNode) {\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_original_email) {\n firstNode.innerHTML = ctPublicFunctions.text__ee_original_email +\n ' ' + selectableEmail.outerHTML;\n } else {\n firstNode.innerHTML = ctAdminCommon.text__ee_original_email +\n ' ' + selectableEmail.outerHTML;\n }\n\n firstNode.setAttribute('style', 'flex-direction: row;');\n }\n // remove animation\n let wrapper = popup.querySelector('.apbct-ee-animation-wrapper');\n if (wrapper) {\n wrapper.remove();\n }\n // remove second node\n let secondNode = popup.querySelector('#apbct_email_ecoder__popup_text_node_second');\n if (secondNode) {\n secondNode.remove();\n }\n // add button\n let buttonWrapper = document.createElement('span');\n buttonWrapper.classList = 'apbct-email-encoder-elements_center top-margin-long';\n if (!document.querySelector('.apbct-email-encoder-got-it-button')) {\n let button = document.createElement('button');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_got_it) {\n button.innerText = ctPublicFunctions.text__ee_got_it;\n } else {\n button.innerText = ctAdminCommon.text__ee_got_it;\n }\n button.classList = 'apbct-email-encoder-got-it-button';\n button.addEventListener('click', function() {\n document.body.classList.remove('apbct-popup-fade');\n popup.setAttribute('style', 'display:none');\n fillDecodedNodes(encodedEmailNodes, result);\n // click on mailto if so\n if (typeof ctPublic !== 'undefined' && ctPublic.encodedEmailNodesIsMixed && clickSource) {\n clickSource.click();\n }\n });\n buttonWrapper.append(button);\n popup.append(buttonWrapper);\n }\n }\n }, 3000);\n } else {\n if (clickSource) {\n let comment = 'unknown_error';\n if (\n result.hasOwnProperty('data') &&\n result.data.length > 0 &&\n typeof result.data[0] === 'object' &&\n typeof result.data[0].comment === 'string'\n ) {\n comment = result.data[0].comment;\n }\n if (result.success) {\n resetEncodedNodes();\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_blocked) {\n ctShowDecodeComment(ctPublicFunctions.text__ee_blocked + ': ' + comment);\n } else {\n ctShowDecodeComment(ctAdminCommon.text__ee_blocked + ': ' + comment);\n }\n } else {\n resetEncodedNodes();\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_cannot_connect) {\n ctShowDecodeComment(ctPublicFunctions.text__ee_cannot_connect + ': ' + comment);\n } else {\n ctShowDecodeComment(ctAdminCommon.text__ee_cannot_connect + ': ' + comment);\n }\n }\n } else {\n console.log('result', result);\n }\n }\n}\n\n/**\n * Reset click event for encoded email\n */\nfunction resetEncodedNodes() {\n if (typeof ctPublic.encodedEmailNodes !== 'undefined') {\n ctPublic.encodedEmailNodes.forEach(function(element) {\n element.addEventListener('click', ctFillDecodedEmailHandler);\n });\n }\n}\n\n/**\n * Show Decode Comment\n * @param {string} comment\n */\nfunction ctShowDecodeComment(comment) {\n if ( ! comment ) {\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_cannot_decode) {\n comment = ctPublicFunctions.text__ee_cannot_decode;\n } else {\n comment = ctAdminCommon.text__ee_cannot_decode;\n }\n }\n\n let popup = document.getElementById('apbct_popup');\n let popupText = document.getElementById('apbct_popup_text');\n if (popup !== null) {\n document.body.classList.remove('apbct-popup-fade');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_email_decoder) {\n popupText.innerText = ctPublicFunctions.text__ee_email_decoder + ': ' + comment;\n } else {\n popupText.innerText = ctAdminCommon.text__ee_email_decoder + ': ' + comment;\n }\n setTimeout(function() {\n popup.setAttribute('style', 'display:none');\n }, 3000);\n }\n}\n\n/**\n * Run filling for every node with decoding result.\n * @param {mixed} encodedNodes\n * @param {mixed} decodingResult\n */\nfunction fillDecodedNodes(encodedNodes, decodingResult) {\n if (encodedNodes.length > 0) {\n for (let i = 0; i < encodedNodes.length; i++) {\n // chek what is what\n let currentResultData;\n decodingResult.data.forEach((row) => {\n if (row.encoded_email === encodedNodes[i].dataset.originalString) {\n currentResultData = row;\n }\n });\n // quit case on cloud block\n if (currentResultData.is_allowed === false) {\n return;\n }\n // handler for mailto\n if (\n typeof encodedNodes[i].href !== 'undefined' &&\n (\n encodedNodes[i].href.indexOf('mailto:') === 0 ||\n encodedNodes[i].href.indexOf('tel:') === 0\n )\n ) {\n let linkTypePrefix;\n if (encodedNodes[i].href.indexOf('mailto:') === 0) {\n linkTypePrefix = 'mailto:';\n } else if (encodedNodes[i].href.indexOf('tel:') === 0) {\n linkTypePrefix = 'tel:';\n } else {\n continue;\n }\n let encodedEmail = encodedNodes[i].href.replace(linkTypePrefix, '');\n let baseElementContent = encodedNodes[i].innerHTML;\n encodedNodes[i].innerHTML = baseElementContent.replace(\n encodedEmail,\n currentResultData.decoded_email,\n );\n encodedNodes[i].href = linkTypePrefix + currentResultData.decoded_email;\n\n encodedNodes[i].querySelectorAll('span.apbct-email-encoder').forEach((el) => {\n let encodedEmailTextInsideMailto = '';\n decodingResult.data.forEach((row) => {\n if (row.encoded_email === el.dataset.originalString) {\n encodedEmailTextInsideMailto = row.decoded_email;\n }\n });\n el.innerHTML = encodedEmailTextInsideMailto;\n });\n } else {\n encodedNodes[i].classList.add('no-blur');\n // fill the nodes\n setTimeout(() => {\n ctProcessDecodedDataResult(currentResultData, encodedNodes[i]);\n }, 2000);\n }\n // remove listeners\n encodedNodes[i].removeEventListener('click', ctFillDecodedEmailHandler);\n }\n } else {\n let currentResultData = decodingResult.data[0];\n encodedNodes.classList.add('no-blur');\n // fill the nodes\n setTimeout(() => {\n ctProcessDecodedDataResult(currentResultData, encodedNodes);\n }, 2000);\n encodedNodes.removeEventListener('click', ctFillDecodedEmailHandler);\n }\n}\n\n/**\n * @param {mixed} response\n * @param {mixed} targetElement\n */\nfunction ctProcessDecodedDataResult(response, targetElement) {\n targetElement.setAttribute('title', '');\n targetElement.removeAttribute('style');\n ctFillDecodedEmail(targetElement, response.decoded_email);\n}\n\n/**\n * @param {mixed} target\n * @param {string} email\n */\nfunction ctFillDecodedEmail(target, email) {\n target.innerHTML = target.innerHTML.replace(/.+?(
)/, email + '$1');\n}\n\n// Listen clicks on encoded emails\ndocument.addEventListener('DOMContentLoaded', function() {\n let encodedEmailNodes = document.querySelectorAll('[data-original-string]');\n if (typeof ctPublic !== 'undefined') {\n ctPublic.encodedEmailNodes = encodedEmailNodes;\n }\n if (encodedEmailNodes.length) {\n for (let i = 0; i < encodedEmailNodes.length; ++i) {\n const node = encodedEmailNodes[i];\n if (\n node.parentNode &&\n node.parentNode.tagName === 'A' &&\n node.parentNode.getAttribute('href')?.includes('mailto:') &&\n node.parentNode.hasAttribute('data-original-string')\n ) {\n // This node was skipped from listeners\n continue;\n }\n node.addEventListener('click', ctFillDecodedEmailHandler);\n }\n }\n});\n"]} \ No newline at end of file +{"version":3,"sources":["cleantalk-admin.js","common-decoder.js"],"names":["apbctGetWCOrderDetailsModalContainer","wcOrderData","container","document","createElement","createTableFromObject","obj","title","key","value","tableWrapperInner","header","className","table","textContent","appendChild","tbody","Object","entries","row","keyCell","valueCell","JSON","stringify","classList","add","order_details","orderDetails","productId","customer_details","apbct_admin_sendAJAX","data","params","let","callback","callbackContext","callback_context","callbackParams","callback_params","async","notJson","timeout","button","spinner","progressbar","ctAdminCommon","_ajax_nonce","Math","random","no_cache","setAttribute","style","cursor","jQuery","css","ajax","type","url","_ajax_url","success","result","removeAttribute","parse","error","setTimeout","fadeOut","cleantalkModal","loaded","toString","open","alert","apply","concat","jqXHR","textStatus","errorThrown","console","log","apbctSetEmailDecoderPopupAnimation","animationElements","animationWrapper","i","length","apbctEEAnimationDogOne","innerText","append","ctFillDecodedEmailHandler","event","clickSource","ctWlBrandname","encodedEmail","ctPublic","this","removeEventListener","encodedEmailNodesIsMixed","wl_brandname","encodedEmailNodes","plugin_name","encodedEmailNode","body","popupHeaderWrapper","popupTextWrapper","popupTextWaiting","popupTextDecoding","encoderPopup","getElementById","ctPublicFunctions","text__ee_wait_for_decoding","innerHTML","waitingPopup","popupHeader","color","id","text__ee_decoding_process","apbctAjaxEmailDecodeBulk","post_url","location","href","referrer","encodedEmails","encodedEmailsCollection","bot_detector_enabled","event_token","apbctLocalStorage","get","event_javascript_data","getJavascriptClientData","indexOf","preventDefault","apbctTooltip","apbct","dataset","originalString","data__ajax_type","apbct_public_sendREST","method","ctSetCookie","emailEncoderPassKey","apbctEmailEncoderCallbackBulk","onErrorCallback","res","resetEncodedNodes","ctShowDecodeComment","action","apbct_public_sendAJAX","0","is_allowed","popup","email","currentResultData","forEach","encoded_email","decoded_email","split","firstNode","querySelector","selectableEmail","wrapper","text__ee_click_to_select","text__ee_original_email","outerHTML","secondNode","remove","buttonWrapper","text__ee_got_it","addEventListener","fillDecodedNodes","click","comment","hasOwnProperty","text__ee_blocked","text__ee_cannot_connect","element","text__ee_cannot_decode","popupText","text__ee_email_decoder","encodedNodes","decodingResult","ctProcessDecodedDataResult","linkTypePrefix","replace","baseElementContent","querySelectorAll","encodedEmailTextInsideMailto","el","response","targetElement","ctFillDecodedEmail","target","ready","$","on","ctDate","Date","getTime","ctSecure","protocol","cookie","toUTCString","e","parent","after","apbctNoticeDismissSuccess","siblings","apbctNoticeName","attr","notice_id","confirm","notice_when_deleting_user_text","window","btnForceProtectionOn","checked","apbctNoticeForceProtectionOn","spmOrderId","order_id","reload","message","modalContent","empty","containerHeader","text","xhr","status","includes","node","parentNode","tagName","getAttribute","hasAttribute"],"mappings":"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","file":"cleantalk-admin.min.js","sourcesContent":["jQuery(document).ready(function($) {\n // Auto update banner close handler\n jQuery('.apbct_update_notice').on('click', 'button', function() {\n let ctDate = new Date(new Date().getTime() + 1000 * 86400 * 30 );\n let ctSecure = location.protocol === 'https:' ? '; secure' : '';\n document.cookie = 'apbct_update_banner_closed=1; path=/; expires=' +\n ctDate.toUTCString() + '; samesite=lax' + ctSecure;\n });\n\n jQuery('li a[href=\"options-general.php?page=cleantalk\"]').css('white-space', 'nowrap')\n .css('display', 'inline-block');\n\n jQuery('body').on('click', '.apbct-notice .notice-dismiss-link', function(e) {\n jQuery(e.target).parent()\n .parent('.notice')\n .after('

' +\n ctAdminCommon.apbctNoticeDismissSuccess +\n '

');\n setTimeout(function() {\n jQuery('#apbct-notice-dismiss-success').fadeOut();\n }, 2000);\n jQuery(e.target).parent().siblings('.apbct-notice .notice-dismiss').click();\n });\n jQuery('body').on('click', '.apbct-notice .notice-dismiss', function(e) {\n let apbctNoticeName = jQuery(e.target).parent().attr('id');\n if ( apbctNoticeName ) {\n apbct_admin_sendAJAX(\n {\n 'action': 'cleantalk_dismiss_notice',\n 'notice_id': apbctNoticeName,\n },\n {\n 'callback': null,\n 'notJson': true,\n },\n );\n }\n });\n\n // Notice when deleting user\n jQuery('.ct_username .row-actions .delete a').on('click', function(e) {\n e.preventDefault();\n\n let result = confirm(ctAdminCommon.notice_when_deleting_user_text);\n\n if (result) {\n window.location = this.href;\n }\n });\n\n let btnForceProtectionOn = document.querySelector('#apbct_setting_forms__force_protection__On');\n if (btnForceProtectionOn) {\n btnForceProtectionOn.addEventListener('click', function(e) {\n if (btnForceProtectionOn.checked) {\n let result = confirm(ctAdminCommon.apbctNoticeForceProtectionOn);\n\n if (!result) {\n e.preventDefault();\n }\n }\n });\n }\n // Restore spam order\n $('.apbct-restore-spam-order-button').click(function() {\n const spmOrderId = $(this).data('spam-order-id');\n let data = {\n action: 'apbct_restore_spam_order',\n _ajax_nonce: ctAdminCommon._ajax_nonce,\n order_id: spmOrderId,\n };\n $.ajax({\n type: 'POST',\n url: ctAdminCommon._ajax_url,\n data: data,\n success: function(result) {\n if (result.success) {\n window.location.reload();\n } else {\n alert(result.data.message);\n }\n },\n });\n });\n\n // Extended spam order details show via modal\n $('.apbct-details-spam-order-button').click(function() {\n const spmOrderId = $(this).data('spam-order-id');\n let data = {\n action: 'apbct_details_spam_order',\n _ajax_nonce: ctAdminCommon._ajax_nonce,\n order_id: spmOrderId,\n };\n if (typeof cleantalkModal !== 'undefined') {\n cleantalkModal.loaded = false;\n cleantalkModal.open(false);\n $.ajax({\n type: 'POST',\n url: ctAdminCommon._ajax_url,\n data: data,\n success: function(result) {\n const modalContent = $('#cleantalk-modal-content');\n modalContent.empty();\n if (result.success && result.data) {\n const container = apbctGetWCOrderDetailsModalContainer(result.data);\n const containerHeader = document.createElement('h3');\n containerHeader.className = 'apbct_wc_details__table-container_header';\n containerHeader.textContent = 'WooCommerce spam order details';\n modalContent.append(containerHeader);\n modalContent.append(container);\n } else {\n const error = result.data.error || 'Unknown error occurred';\n modalContent.text(error);\n }\n cleantalkModal.loaded = true;\n },\n error: function(xhr, status, error) {\n console.error('AJAX Error:', error);\n alert('An error occurred while processing your request, see console for details.');\n },\n });\n } else {\n alert('Can not initialize CleanTalk modal window.');\n }\n });\n\n // Email decoder example\n if (window.location.href.includes('options-general.php?page=cleantalk')) {\n let encodedEmailNode = document.querySelector('[data-original-string]');\n if (encodedEmailNode) {\n ctAdminCommon.encodedEmailNode = encodedEmailNode;\n encodedEmailNode.style.cursor = 'pointer';\n encodedEmailNode.addEventListener('click', ctFillDecodedEmailHandler);\n }\n }\n});\n\n/**\n * apbctGetWCOrderDetailsModalContainer\n * @param {object} wcOrderData\n * @return {HTMLDivElement}\n */\nfunction apbctGetWCOrderDetailsModalContainer(wcOrderData) {\n const container = document.createElement('div');\n container.className = 'apbct_wc_details__wrapper';\n\n /**\n * createTableFromObject\n * @param {object} obj\n * @param {string} title\n * @return {HTMLDivElement}\n */\n function createTableFromObject(obj, title) {\n const tableWrapperInner = document.createElement('div');\n tableWrapperInner.className = 'apbct_wc_details__table-wrapper-inner';\n\n const header = document.createElement('h4');\n header.textContent = title;\n tableWrapperInner.appendChild(header);\n\n const table = document.createElement('table');\n table.className = 'apbct_wc_details__table';\n\n const tbody = document.createElement('tbody');\n\n for (const [key, value] of Object.entries(obj)) {\n const row = document.createElement('tr');\n\n const keyCell = document.createElement('td');\n keyCell.className = 'apbct_wc_details__table-key-cell';\n keyCell.textContent = key;\n\n const valueCell = document.createElement('td');\n valueCell.className = 'apbct_wc_details__table-value-cell';\n\n if (typeof value === 'object' && value !== null) {\n valueCell.textContent = JSON.stringify(value, null, 2);\n valueCell.classList.add('apbct_wc_details__table-value-cell--json');\n } else {\n valueCell.textContent = value !== null && value !== undefined ? value : '—';\n }\n\n row.appendChild(keyCell);\n row.appendChild(valueCell);\n tbody.appendChild(row);\n }\n\n table.appendChild(tbody);\n tableWrapperInner.appendChild(table);\n return tableWrapperInner;\n }\n\n if (wcOrderData.order_details) {\n const orderDetails = wcOrderData.order_details;\n for (const [key, value] of Object.entries(orderDetails)) {\n const productId = orderDetails[key] && typeof orderDetails[key]['product_id'] === 'number' ?\n orderDetails[key]['product_id'] :\n 'Unknown';\n container.appendChild(createTableFromObject(value, `Order Details for product ID ${productId}`));\n }\n }\n\n if (wcOrderData.customer_details) {\n container.appendChild(\n createTableFromObject(wcOrderData.customer_details, 'Customer Details'),\n );\n }\n\n return container;\n}\n// eslint-disable-next-line camelcase,require-jsdoc,no-unused-vars\nfunction apbct_admin_sendAJAX(data, params, obj) {\n // Default params\n let callback = params.callback || null;\n let callbackContext = params.callback_context || null;\n let callbackParams = params.callback_params || null;\n let async = params.async || true;\n let notJson = params.notJson || null;\n let timeout = params.timeout || 15000;\n var obj = obj || null; // eslint-disable-line no-var\n let button = params.button || null;\n let spinner = params.spinner || null;\n let progressbar = params.progressbar || null;\n\n if (typeof (data) === 'string') {\n data = data + '&_ajax_nonce=' + ctAdminCommon._ajax_nonce + '&no_cache=' + Math.random();\n } else {\n data._ajax_nonce = ctAdminCommon._ajax_nonce;\n data.no_cache = Math.random();\n }\n // Button and spinner\n if (button) {\n button.setAttribute('disabled', 'disabled'); button.style.cursor = 'not-allowed';\n }\n if (spinner) jQuery(spinner).css('display', 'inline');\n\n jQuery.ajax({\n type: 'POST',\n url: ctAdminCommon._ajax_url,\n data: data,\n async: async,\n success: function(result) {\n if (button) {\n button.removeAttribute('disabled'); button.style.cursor = 'pointer';\n }\n if (spinner) jQuery(spinner).css('display', 'none');\n if (!notJson) result = JSON.parse(result);\n if (result.error) {\n setTimeout(function() {\n if (progressbar) progressbar.fadeOut('slow');\n }, 1000);\n if ( typeof cleantalkModal !== 'undefined' ) {\n // Show the result by modal\n cleantalkModal.loaded = 'Error:
' + result.error.toString();\n cleantalkModal.open();\n } else {\n alert('Error happens: ' + (result.error || 'Unkown'));\n }\n } else {\n if (callback) {\n if (callbackParams) {\n callback.apply( callbackContext, callbackParams.concat( result, data, params, obj ) );\n } else {\n callback(result, data, params, obj);\n }\n }\n }\n },\n error: function(jqXHR, textStatus, errorThrown) {\n if (button) {\n button.removeAttribute('disabled'); button.style.cursor = 'pointer';\n }\n if (spinner) jQuery(spinner).css('display', 'none');\n console.log('APBCT_AJAX_ERROR');\n console.log(jqXHR);\n console.log(textStatus);\n console.log(errorThrown);\n },\n timeout: timeout,\n });\n}\n","/**\n * @return {HTMLElement} event\n */\nfunction apbctSetEmailDecoderPopupAnimation() {\n const animationElements = ['apbct_dog_one', 'apbct_dog_two', 'apbct_dog_three'];\n const animationWrapper = document.createElement('div');\n animationWrapper.classList = 'apbct-ee-animation-wrapper';\n for (let i = 0; i < animationElements.length; i++) {\n const apbctEEAnimationDogOne = document.createElement('span');\n apbctEEAnimationDogOne.classList = 'apbct_dog ' + animationElements[i];\n apbctEEAnimationDogOne.innerText = '@';\n animationWrapper.append(apbctEEAnimationDogOne);\n }\n return animationWrapper;\n}\n\n/**\n * @param {mixed} event\n */\nfunction ctFillDecodedEmailHandler(event = false) {\n let clickSource = false;\n let ctWlBrandname = '';\n let encodedEmail = '';\n if (typeof ctPublic !== 'undefined') {\n this.removeEventListener('click', ctFillDecodedEmailHandler);\n // remember clickSource\n clickSource = this;\n // globally remember if emails is mixed with mailto\n ctPublic.encodedEmailNodesIsMixed = false;\n ctWlBrandname = ctPublic.wl_brandname;\n encodedEmail = ctPublic.encodedEmailNodes;\n } else if (typeof ctAdminCommon !== 'undefined') {\n ctWlBrandname = ctAdminCommon.plugin_name;\n encodedEmail = ctAdminCommon.encodedEmailNode;\n }\n\n // get fade\n document.body.classList.add('apbct-popup-fade');\n // popup show\n let encoderPopup = document.getElementById('apbct_popup');\n if (!encoderPopup) {\n // construct popup\n let waitingPopup = document.createElement('div');\n waitingPopup.setAttribute('class', 'apbct-popup apbct-email-encoder-popup');\n waitingPopup.setAttribute('id', 'apbct_popup');\n\n // construct text header\n let popupHeaderWrapper = document.createElement('span');\n popupHeaderWrapper.classList = 'apbct-email-encoder-elements_center';\n let popupHeader = document.createElement('p');\n popupHeader.innerText = ctWlBrandname;\n popupHeader.setAttribute('class', 'apbct-email-encoder--popup-header');\n popupHeaderWrapper.append(popupHeader);\n\n // construct text wrapper\n let popupTextWrapper = document.createElement('div');\n popupTextWrapper.setAttribute('id', 'apbct_popup_text');\n popupTextWrapper.setAttribute('class', 'apbct-email-encoder-elements_center');\n popupTextWrapper.style.color = 'black';\n\n // construct text first node\n // todo make translatable\n let popupTextWaiting = document.createElement('p');\n popupTextWaiting.id = 'apbct_email_ecoder__popup_text_node_first';\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_wait_for_decoding) {\n popupTextWaiting.innerText = ctPublicFunctions.text__ee_wait_for_decoding;\n } else {\n popupTextWaiting.innerText = ctAdminCommon.text__ee_wait_for_decoding;\n }\n popupTextWaiting.setAttribute('class', 'apbct-email-encoder-elements_center');\n\n // construct text second node\n // todo make translatable\n let popupTextDecoding = document.createElement('p');\n popupTextDecoding.id = 'apbct_email_ecoder__popup_text_node_second';\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_decoding_process) {\n popupTextDecoding.innerText = ctPublicFunctions.text__ee_decoding_process;\n } else {\n popupTextDecoding.innerText = ctAdminCommon.text__ee_decoding_process;\n }\n\n // appending\n popupTextWrapper.append(popupTextWaiting);\n popupTextWrapper.append(popupTextDecoding);\n waitingPopup.append(popupHeaderWrapper);\n waitingPopup.append(popupTextWrapper);\n waitingPopup.append(apbctSetEmailDecoderPopupAnimation());\n document.body.append(waitingPopup);\n } else {\n encoderPopup.setAttribute('style', 'display: inherit');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_wait_for_decoding) {\n document.getElementById('apbct_popup_text').innerHTML = ctPublicFunctions.text__ee_wait_for_decoding;\n } else {\n document.getElementById('apbct_popup_text').innerHTML = ctAdminCommon.text__ee_wait_for_decoding;\n }\n }\n\n apbctAjaxEmailDecodeBulk(event, encodedEmail, clickSource);\n}\n\n/**\n * @param {mixed} event\n * @param {mixed} encodedEmailNodes\n * @param {mixed} clickSource\n */\nfunction apbctAjaxEmailDecodeBulk(event, encodedEmailNodes, clickSource) {\n if (event && clickSource) {\n // collect data\n let data = {\n post_url: document.location.href,\n referrer: document.referrer,\n encodedEmails: '',\n };\n if (+ctPublic.bot_detector_enabled) {\n data.event_token = apbctLocalStorage.get('bot_detector_event_token');\n } else {\n data.event_javascript_data = getJavascriptClientData();\n }\n\n let encodedEmailsCollection = {};\n for (let i = 0; i < encodedEmailNodes.length; i++) {\n // disable click for mailto\n if (\n typeof encodedEmailNodes[i].href !== 'undefined' &&\n encodedEmailNodes[i].href.indexOf('mailto:') === 0\n ) {\n event.preventDefault();\n ctPublic.encodedEmailNodesIsMixed = true;\n }\n\n // Adding a tooltip\n let apbctTooltip = document.createElement('div');\n apbctTooltip.setAttribute('class', 'apbct-tooltip');\n apbct(encodedEmailNodes[i]).append(apbctTooltip);\n\n // collect encoded email strings\n encodedEmailsCollection[i] = encodedEmailNodes[i].dataset.originalString;\n }\n\n // JSONify encoded email strings\n data.encodedEmails = JSON.stringify(encodedEmailsCollection);\n\n // Using REST API handler\n if ( ctPublicFunctions.data__ajax_type === 'rest' ) {\n apbct_public_sendREST(\n 'apbct_decode_email',\n {\n data: data,\n method: 'POST',\n callback: function(result) {\n // set alternative cookie to skip next pages encoding\n ctSetCookie('apbct_email_encoder_passed', ctPublic.emailEncoderPassKey, '');\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource);\n },\n onErrorCallback: function(res) {\n resetEncodedNodes();\n ctShowDecodeComment(res);\n },\n },\n );\n\n // Using AJAX request and handler\n } else {\n data.action = 'apbct_decode_email';\n apbct_public_sendAJAX(\n data,\n {\n notJson: false,\n callback: function(result) {\n // set alternative cookie to skip next pages encoding\n ctSetCookie('apbct_email_encoder_passed', ctPublic.emailEncoderPassKey, '');\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource);\n },\n onErrorCallback: function(res) {\n resetEncodedNodes();\n ctShowDecodeComment(res);\n },\n },\n );\n }\n } else {\n const encodedEmail = encodedEmailNodes.dataset.originalString;\n let data = {\n encodedEmails: JSON.stringify({0: encodedEmail}),\n };\n\n // Adding a tooltip\n let apbctTooltip = document.createElement('div');\n apbctTooltip.setAttribute('class', 'apbct-tooltip');\n encodedEmailNodes.appendChild(apbctTooltip);\n\n apbct_admin_sendAJAX(\n {\n 'action': 'apbct_decode_email',\n 'encodedEmails': data.encodedEmails,\n },\n {\n 'callback': function(result) {\n apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, false);\n },\n 'notJson': true,\n },\n );\n }\n}\n\n/**\n * @param {mixed} result\n * @param {mixed} encodedEmailNodes\n * @param {mixed} clickSource\n */\nfunction apbctEmailEncoderCallbackBulk(result, encodedEmailNodes, clickSource = false) {\n if (result.success && result.data[0].is_allowed === true) {\n // start process of visual decoding\n setTimeout(function() {\n // popup remove\n let popup = document.getElementById('apbct_popup');\n if (popup !== null) {\n let email = '';\n if (clickSource) {\n let currentResultData;\n result.data.forEach((row) => {\n if (row.encoded_email === clickSource.dataset.originalString) {\n currentResultData = row;\n }\n });\n\n email = currentResultData.decoded_email.split(/[&?]/)[0];\n } else {\n email = result.data[0].decoded_email;\n }\n // handle first node\n let firstNode = popup.querySelector('#apbct_email_ecoder__popup_text_node_first');\n // get email selectable by click\n let selectableEmail = document.createElement('b');\n selectableEmail.setAttribute('class', 'apbct-email-encoder-select-whole-email');\n selectableEmail.innerText = email;\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_click_to_select) {\n selectableEmail.title = ctPublicFunctions.text__ee_click_to_select;\n } else {\n selectableEmail.title = ctAdminCommon.text__ee_click_to_select;\n }\n // add email to the first node\n if (firstNode) {\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_original_email) {\n firstNode.innerHTML = ctPublicFunctions.text__ee_original_email +\n ' ' + selectableEmail.outerHTML;\n } else {\n firstNode.innerHTML = ctAdminCommon.text__ee_original_email +\n ' ' + selectableEmail.outerHTML;\n }\n\n firstNode.setAttribute('style', 'flex-direction: row;');\n }\n // remove animation\n let wrapper = popup.querySelector('.apbct-ee-animation-wrapper');\n if (wrapper) {\n wrapper.remove();\n }\n // remove second node\n let secondNode = popup.querySelector('#apbct_email_ecoder__popup_text_node_second');\n if (secondNode) {\n secondNode.remove();\n }\n // add button\n let buttonWrapper = document.createElement('span');\n buttonWrapper.classList = 'apbct-email-encoder-elements_center top-margin-long';\n if (!document.querySelector('.apbct-email-encoder-got-it-button')) {\n let button = document.createElement('button');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_got_it) {\n button.innerText = ctPublicFunctions.text__ee_got_it;\n } else {\n button.innerText = ctAdminCommon.text__ee_got_it;\n }\n button.classList = 'apbct-email-encoder-got-it-button';\n button.addEventListener('click', function() {\n document.body.classList.remove('apbct-popup-fade');\n popup.setAttribute('style', 'display:none');\n fillDecodedNodes(encodedEmailNodes, result);\n // click on mailto if so\n if (typeof ctPublic !== 'undefined' && ctPublic.encodedEmailNodesIsMixed && clickSource) {\n clickSource.click();\n }\n });\n buttonWrapper.append(button);\n popup.append(buttonWrapper);\n }\n }\n }, 3000);\n } else {\n if (clickSource) {\n let comment = 'unknown_error';\n if (\n result.hasOwnProperty('data') &&\n result.data.length > 0 &&\n typeof result.data[0] === 'object' &&\n typeof result.data[0].comment === 'string'\n ) {\n comment = result.data[0].comment;\n }\n if (result.success) {\n resetEncodedNodes();\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_blocked) {\n ctShowDecodeComment(ctPublicFunctions.text__ee_blocked + ': ' + comment);\n } else {\n ctShowDecodeComment(ctAdminCommon.text__ee_blocked + ': ' + comment);\n }\n } else {\n resetEncodedNodes();\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_cannot_connect) {\n ctShowDecodeComment(ctPublicFunctions.text__ee_cannot_connect + ': ' + comment);\n } else {\n ctShowDecodeComment(ctAdminCommon.text__ee_cannot_connect + ': ' + comment);\n }\n }\n } else {\n console.log('result', result);\n }\n }\n}\n\n/**\n * Reset click event for encoded email\n */\nfunction resetEncodedNodes() {\n if (typeof ctPublic.encodedEmailNodes !== 'undefined') {\n ctPublic.encodedEmailNodes.forEach(function(element) {\n element.addEventListener('click', ctFillDecodedEmailHandler);\n });\n }\n}\n\n/**\n * Show Decode Comment\n * @param {string} comment\n */\nfunction ctShowDecodeComment(comment) {\n if ( ! comment ) {\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_cannot_decode) {\n comment = ctPublicFunctions.text__ee_cannot_decode;\n } else {\n comment = ctAdminCommon.text__ee_cannot_decode;\n }\n }\n\n let popup = document.getElementById('apbct_popup');\n let popupText = document.getElementById('apbct_popup_text');\n if (popup !== null) {\n document.body.classList.remove('apbct-popup-fade');\n if (typeof ctPublicFunctions !== 'undefined' && ctPublicFunctions.text__ee_email_decoder) {\n popupText.innerText = ctPublicFunctions.text__ee_email_decoder + ': ' + comment;\n } else {\n popupText.innerText = ctAdminCommon.text__ee_email_decoder + ': ' + comment;\n }\n setTimeout(function() {\n popup.setAttribute('style', 'display:none');\n }, 3000);\n }\n}\n\n/**\n * Run filling for every node with decoding result.\n * @param {mixed} encodedNodes\n * @param {mixed} decodingResult\n */\nfunction fillDecodedNodes(encodedNodes, decodingResult) {\n if (encodedNodes.length > 0) {\n for (let i = 0; i < encodedNodes.length; i++) {\n // chek what is what\n let currentResultData;\n decodingResult.data.forEach((row) => {\n if (row.encoded_email === encodedNodes[i].dataset.originalString) {\n currentResultData = row;\n }\n });\n // quit case on cloud block\n if (currentResultData.is_allowed === false) {\n return;\n }\n // handler for mailto\n if (\n typeof encodedNodes[i].href !== 'undefined' &&\n (\n encodedNodes[i].href.indexOf('mailto:') === 0 ||\n encodedNodes[i].href.indexOf('tel:') === 0\n )\n ) {\n let linkTypePrefix;\n if (encodedNodes[i].href.indexOf('mailto:') === 0) {\n linkTypePrefix = 'mailto:';\n } else if (encodedNodes[i].href.indexOf('tel:') === 0) {\n linkTypePrefix = 'tel:';\n } else {\n continue;\n }\n let encodedEmail = encodedNodes[i].href.replace(linkTypePrefix, '');\n let baseElementContent = encodedNodes[i].innerHTML;\n encodedNodes[i].innerHTML = baseElementContent.replace(\n encodedEmail,\n currentResultData.decoded_email,\n );\n encodedNodes[i].href = linkTypePrefix + currentResultData.decoded_email;\n\n encodedNodes[i].querySelectorAll('span.apbct-email-encoder').forEach((el) => {\n let encodedEmailTextInsideMailto = '';\n decodingResult.data.forEach((row) => {\n if (row.encoded_email === el.dataset.originalString) {\n encodedEmailTextInsideMailto = row.decoded_email;\n }\n });\n el.innerHTML = encodedEmailTextInsideMailto;\n });\n } else {\n encodedNodes[i].classList.add('no-blur');\n // fill the nodes\n setTimeout(() => {\n ctProcessDecodedDataResult(currentResultData, encodedNodes[i]);\n }, 2000);\n }\n // remove listeners\n encodedNodes[i].removeEventListener('click', ctFillDecodedEmailHandler);\n }\n } else {\n let currentResultData = decodingResult.data[0];\n encodedNodes.classList.add('no-blur');\n // fill the nodes\n setTimeout(() => {\n ctProcessDecodedDataResult(currentResultData, encodedNodes);\n }, 2000);\n encodedNodes.removeEventListener('click', ctFillDecodedEmailHandler);\n }\n}\n\n/**\n * @param {mixed} response\n * @param {mixed} targetElement\n */\nfunction ctProcessDecodedDataResult(response, targetElement) {\n targetElement.setAttribute('title', '');\n targetElement.removeAttribute('style');\n ctFillDecodedEmail(targetElement, response.decoded_email);\n}\n\n/**\n * @param {mixed} target\n * @param {string} email\n */\nfunction ctFillDecodedEmail(target, email) {\n target.innerHTML = target.innerHTML.replace(/.+?(
)/, email + '$1');\n}\n\n// Listen clicks on encoded emails\ndocument.addEventListener('DOMContentLoaded', function() {\n let encodedEmailNodes = document.querySelectorAll('[data-original-string]');\n if (typeof ctPublic !== 'undefined') {\n ctPublic.encodedEmailNodes = encodedEmailNodes;\n }\n if (encodedEmailNodes.length) {\n for (let i = 0; i < encodedEmailNodes.length; ++i) {\n const node = encodedEmailNodes[i];\n if (\n node.parentNode &&\n node.parentNode.tagName === 'A' &&\n node.parentNode.getAttribute('href')?.includes('mailto:') &&\n node.parentNode.hasAttribute('data-original-string')\n ) {\n // This node was skipped from listeners\n continue;\n }\n node.addEventListener('click', ctFillDecodedEmailHandler);\n }\n }\n});\n"]} \ No newline at end of file diff --git a/js/prebuild/apbct-public-bundle.js b/js/prebuild/apbct-public-bundle.js index 4ff505cbb..98bfc5275 100644 --- a/js/prebuild/apbct-public-bundle.js +++ b/js/prebuild/apbct-public-bundle.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_ext-protection.js b/js/prebuild/apbct-public-bundle_ext-protection.js index 505b71eac..d19793fcf 100644 --- a/js/prebuild/apbct-public-bundle_ext-protection.js +++ b/js/prebuild/apbct-public-bundle_ext-protection.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_ext-protection_gathering.js b/js/prebuild/apbct-public-bundle_ext-protection_gathering.js index 01a5e6bc0..a9b8e2c80 100644 --- a/js/prebuild/apbct-public-bundle_ext-protection_gathering.js +++ b/js/prebuild/apbct-public-bundle_ext-protection_gathering.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_full-protection.js b/js/prebuild/apbct-public-bundle_full-protection.js index c299a0986..5716f065c 100644 --- a/js/prebuild/apbct-public-bundle_full-protection.js +++ b/js/prebuild/apbct-public-bundle_full-protection.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_full-protection_gathering.js b/js/prebuild/apbct-public-bundle_full-protection_gathering.js index 33b517f29..a80b4e2ea 100644 --- a/js/prebuild/apbct-public-bundle_full-protection_gathering.js +++ b/js/prebuild/apbct-public-bundle_full-protection_gathering.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_gathering.js b/js/prebuild/apbct-public-bundle_gathering.js index a2715c625..bb10081f0 100644 --- a/js/prebuild/apbct-public-bundle_gathering.js +++ b/js/prebuild/apbct-public-bundle_gathering.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_int-protection.js b/js/prebuild/apbct-public-bundle_int-protection.js index 513c97b3e..f9e4e7a91 100644 --- a/js/prebuild/apbct-public-bundle_int-protection.js +++ b/js/prebuild/apbct-public-bundle_int-protection.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/prebuild/apbct-public-bundle_int-protection_gathering.js b/js/prebuild/apbct-public-bundle_int-protection_gathering.js index 46dbc5e48..a703c6dd3 100644 --- a/js/prebuild/apbct-public-bundle_int-protection_gathering.js +++ b/js/prebuild/apbct-public-bundle_int-protection_gathering.js @@ -3081,7 +3081,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/js/src/cleantalk-admin.js b/js/src/cleantalk-admin.js index 8455922bb..e1ce79dfe 100644 --- a/js/src/cleantalk-admin.js +++ b/js/src/cleantalk-admin.js @@ -82,6 +82,47 @@ jQuery(document).ready(function($) { }); }); + // Extended spam order details show via modal + $('.apbct-details-spam-order-button').click(function() { + const spmOrderId = $(this).data('spam-order-id'); + let data = { + action: 'apbct_details_spam_order', + _ajax_nonce: ctAdminCommon._ajax_nonce, + order_id: spmOrderId, + }; + if (typeof cleantalkModal !== 'undefined') { + cleantalkModal.loaded = false; + cleantalkModal.open(false); + $.ajax({ + type: 'POST', + url: ctAdminCommon._ajax_url, + data: data, + success: function(result) { + const modalContent = $('#cleantalk-modal-content'); + modalContent.empty(); + if (result.success && result.data) { + const container = apbctGetWCOrderDetailsModalContainer(result.data); + const containerHeader = document.createElement('h3'); + containerHeader.className = 'apbct_wc_details__table-container_header'; + containerHeader.textContent = 'WooCommerce spam order details'; + modalContent.append(containerHeader); + modalContent.append(container); + } else { + const error = result.data.error || 'Unknown error occurred'; + modalContent.text(error); + } + cleantalkModal.loaded = true; + }, + error: function(xhr, status, error) { + console.error('AJAX Error:', error); + alert('An error occurred while processing your request, see console for details.'); + }, + }); + } else { + alert('Can not initialize CleanTalk modal window.'); + } + }); + // Email decoder example if (window.location.href.includes('options-general.php?page=cleantalk')) { let encodedEmailNode = document.querySelector('[data-original-string]'); @@ -92,6 +133,80 @@ jQuery(document).ready(function($) { } } }); + +/** + * apbctGetWCOrderDetailsModalContainer + * @param {object} wcOrderData + * @return {HTMLDivElement} + */ +function apbctGetWCOrderDetailsModalContainer(wcOrderData) { + const container = document.createElement('div'); + container.className = 'apbct_wc_details__wrapper'; + + /** + * createTableFromObject + * @param {object} obj + * @param {string} title + * @return {HTMLDivElement} + */ + function createTableFromObject(obj, title) { + const tableWrapperInner = document.createElement('div'); + tableWrapperInner.className = 'apbct_wc_details__table-wrapper-inner'; + + const header = document.createElement('h4'); + header.textContent = title; + tableWrapperInner.appendChild(header); + + const table = document.createElement('table'); + table.className = 'apbct_wc_details__table'; + + const tbody = document.createElement('tbody'); + + for (const [key, value] of Object.entries(obj)) { + const row = document.createElement('tr'); + + const keyCell = document.createElement('td'); + keyCell.className = 'apbct_wc_details__table-key-cell'; + keyCell.textContent = key; + + const valueCell = document.createElement('td'); + valueCell.className = 'apbct_wc_details__table-value-cell'; + + if (typeof value === 'object' && value !== null) { + valueCell.textContent = JSON.stringify(value, null, 2); + valueCell.classList.add('apbct_wc_details__table-value-cell--json'); + } else { + valueCell.textContent = value !== null && value !== undefined ? value : '—'; + } + + row.appendChild(keyCell); + row.appendChild(valueCell); + tbody.appendChild(row); + } + + table.appendChild(tbody); + tableWrapperInner.appendChild(table); + return tableWrapperInner; + } + + if (wcOrderData.order_details) { + const orderDetails = wcOrderData.order_details; + for (const [key, value] of Object.entries(orderDetails)) { + const productId = orderDetails[key] && typeof orderDetails[key]['product_id'] === 'number' ? + orderDetails[key]['product_id'] : + 'Unknown'; + container.appendChild(createTableFromObject(value, `Order Details for product ID ${productId}`)); + } + } + + if (wcOrderData.customer_details) { + container.appendChild( + createTableFromObject(wcOrderData.customer_details, 'Customer Details'), + ); + } + + return container; +} // eslint-disable-next-line camelcase,require-jsdoc,no-unused-vars function apbct_admin_sendAJAX(data, params, obj) { // Default params diff --git a/js/src/public-1-main.js b/js/src/public-1-main.js index b94084eff..029296edd 100644 --- a/js/src/public-1-main.js +++ b/js/src/public-1-main.js @@ -494,7 +494,7 @@ class ApbctHandler { ctPublic.force_alt_cookies = jetpackCommentsForm; /** - * NOT ADD ANY NEW INTEGRATION IN THIS FLOW + * DO NOT ADD ANY NEW INTEGRATION IN THIS FLOW */ setTimeout(function() { diff --git a/lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php b/lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php index 59deea4b9..d46112ffc 100644 --- a/lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php +++ b/lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php @@ -85,6 +85,9 @@ public function doAjaxWork() // Restore Spam Order add_action('wp_ajax_apbct_restore_spam_order', array(WcSpamOrdersFunctions::class, 'restoreOrderAction')); + // Details + add_action('wp_ajax_apbct_details_spam_order', array(WcSpamOrdersFunctions::class, 'detailsOrderAction')); + // Uni CPO integration, remove service fields from order items add_action('woocommerce_checkout_create_order_line_item', [$this, 'removeServiceFieldsFromOrderItems'], 100, 4); } diff --git a/lib/Cleantalk/ApbctWP/WcSpamOrdersFunctions.php b/lib/Cleantalk/ApbctWP/WcSpamOrdersFunctions.php index 4c198bf04..59f3a3a69 100644 --- a/lib/Cleantalk/ApbctWP/WcSpamOrdersFunctions.php +++ b/lib/Cleantalk/ApbctWP/WcSpamOrdersFunctions.php @@ -20,7 +20,7 @@ public static function restoreOrderAction() $order_data = self::getOrderDataById($order_id); if (is_null($order_data)) { - wp_send_json_error(esc_html__('Error: Order is not founded.', 'cleantalk-spam-protect')); + wp_send_json_error(esc_html__('Error: Order is not found.', 'cleantalk-spam-protect')); } try { @@ -37,6 +37,79 @@ public static function restoreOrderAction() wp_send_json_success(); } + /** + * Handler for 'wp_ajax_apbct_details_spam_order' ajax call. + * @return void wp_send_json + */ + public static function detailsOrderAction() + { + AJAXService::checkNonceRestrictingNonAdmins(); + + $order_id = Post::getInt('order_id'); + + $response_data = self::prepareDetailsOrderResponse( + $order_id, + ['class' => self::class, 'method' => 'getOrderDataById'] + ); + + if (empty($response_data['error'])) { + wp_send_json_success($response_data); + } else { + wp_send_json_error($response_data); + } + } + + public static function prepareDetailsOrderResponse($order_id = null, $search_method = ['class' => null, 'method' => null]) + { + $response_data = array( + 'order_details' => null, + 'customer_details' => null, + 'error' => null, + ); + + try { + if (!is_numeric($order_id) || (int)$order_id <= 0) { + throw new \Exception(esc_html__('Order ID is not valid.', 'cleantalk-spam-protect')); + } + $order_id = (int)$order_id; + + if ( + empty($search_method['class']) || + empty($search_method['method']) || + !is_string($search_method['class']) || + !is_string($search_method['method']) || + !class_exists($search_method['class']) || + !is_callable([$search_method['class'], $search_method['method']]) + ) { + throw new \Exception(esc_html__('Search method undefined.', 'cleantalk-spam-protect')); + } + + // Get order data from table with spam orders + $order_data = $search_method['class']::{$search_method['method']}($order_id); + + if (is_null($order_data)) { + throw new \Exception(esc_html__('Order is not found.', 'cleantalk-spam-protect')); + } + + $response_data['order_details'] = json_decode($order_data->order_details); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \Exception(esc_html__('Order details JSON is invalid.', 'cleantalk-spam-protect')); + } + + $response_data['customer_details'] = json_decode($order_data->customer_details); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \Exception(esc_html__('Customer details JSON is invalid.', 'cleantalk-spam-protect')); + } + } catch (\Exception $e) { + $response_data['error'] = sprintf( + esc_html__('Error: %s', 'cleantalk-spam-protect'), + $e->getMessage() + ); + } + + return $response_data; + } + private static function getOrderDataById($order_id) { global $wpdb; diff --git a/lib/Cleantalk/ApbctWP/WcSpamOrdersListTable.php b/lib/Cleantalk/ApbctWP/WcSpamOrdersListTable.php index c50e65e1f..1e8bc5415 100644 --- a/lib/Cleantalk/ApbctWP/WcSpamOrdersListTable.php +++ b/lib/Cleantalk/ApbctWP/WcSpamOrdersListTable.php @@ -90,6 +90,7 @@ public function prepare_items() // phpcs:ignore PSR1.Methods.CamelCapsMethodNam $actions = array( 'restore' => '' . esc_html__('Restore', 'cleantalk-spam-protect') . '', 'delete' => 'Delete', + 'details' => '' . esc_html__('See details', 'cleantalk-spam-protect') . '', /*'approve' => sprintf( 'Approve', htmlspecialchars(addslashes(Get::get('page'))), diff --git a/tests/ApbctWP/TestWcSpamOrdersFunctions.php b/tests/ApbctWP/TestWcSpamOrdersFunctions.php new file mode 100644 index 000000000..12389ff17 --- /dev/null +++ b/tests/ApbctWP/TestWcSpamOrdersFunctions.php @@ -0,0 +1,261 @@ + OrderDataStub::class, + 'method' => 'getOrderDataById', + ]; + } + + private function makeOrderRow(array $orderDetails = [], array $customerDetails = []): \stdClass + { + $row = new \stdClass(); + $row->order_details = json_encode($orderDetails); + $row->customer_details = json_encode($customerDetails); + return $row; + } + + // ------------------------------------------------------------------ + // Tests: invalid / missing order_id + // ------------------------------------------------------------------ + + /** + * @test + * @dataProvider invalidOrderIdProvider + */ + public function prepareDetailsOrderResponse_returnsError_whenOrderIdIsInvalid($invalidId): void + { + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse( + $invalidId, + $this->makeSearchMethod(function ($id) { return null; }) + ); + + $this->assertNull($result['order_details']); + $this->assertNull($result['customer_details']); + $this->assertNotNull($result['error']); + $this->assertStringContainsString('not valid', $result['error']); + } + + public function invalidOrderIdProvider(): array + { + return [ + 'null id' => [null], + 'zero int' => [0], + 'empty string' => [''], + 'false' => [false], + ]; + } + + // ------------------------------------------------------------------ + // Tests: invalid search_method + // ------------------------------------------------------------------ + + /** @test */ + public function prepareDetailsOrderResponse_returnsError_whenSearchMethodIsEmptyArray(): void + { + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(42, []); + + $this->assertNotNull($result['error']); + $this->assertStringContainsString('undefined', strtolower($result['error'])); + } + + /** @test */ + public function prepareDetailsOrderResponse_returnsError_whenClassDoesNotExist(): void + { + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(42, [ + 'class' => 'NonExistentClass_XYZ', + 'method' => 'someMethod', + ]); + + $this->assertNotNull($result['error']); + $this->assertStringContainsString('undefined', strtolower($result['error'])); + } + + /** @test */ + public function prepareDetailsOrderResponse_returnsError_whenMethodDoesNotExist(): void + { + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(42, [ + 'class' => OrderDataStub::class, + 'method' => 'nonExistentMethod', + ]); + + $this->assertNotNull($result['error']); + $this->assertStringContainsString('undefined', strtolower($result['error'])); + } + + /** @test */ + public function prepareDetailsOrderResponse_returnsError_whenMethodKeyMissing(): void + { + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(42, [ + 'class' => OrderDataStub::class, + // 'method' intentionally omitted + ]); + + $this->assertNotNull($result['error']); + } + + // ------------------------------------------------------------------ + // Tests: order not found + // ------------------------------------------------------------------ + + /** @test */ + public function prepareDetailsOrderResponse_returnsError_whenOrderNotFound(): void + { + $searchMethod = $this->makeSearchMethod(function ($id) { return null; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(99, $searchMethod); + + $this->assertNull($result['order_details']); + $this->assertNull($result['customer_details']); + $this->assertNotNull($result['error']); + $this->assertStringContainsString('not found', strtolower($result['error'])); + } + + // ------------------------------------------------------------------ + // Tests: happy path + // ------------------------------------------------------------------ + + /** @test */ + public function prepareDetailsOrderResponse_returnsDecodedData_whenOrderExists(): void + { + $orderDetails = [['product_id' => 5, 'quantity' => 2]]; + $customerDetails = ['billing_email' => 'test@example.com']; + + $row = $this->makeOrderRow($orderDetails, $customerDetails); + $searchMethod = $this->makeSearchMethod(function ($id) use ($row) { return $row; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(1, $searchMethod); + + $this->assertNull($result['error']); + $this->assertNotNull($result['order_details']); + $this->assertNotNull($result['customer_details']); + $this->assertEquals('test@example.com', $result['customer_details']->billing_email); + $this->assertEquals(5, $result['order_details'][0]->product_id); + } + + /** @test */ + public function prepareDetailsOrderResponse_passesOrderIdToSearchMethod(): void + { + $capturedId = null; + $self = $this; + $searchMethod = $this->makeSearchMethod(function ($id) use (&$capturedId, $self) { + $capturedId = $id; + return $self->makeOrderRowPublic(); + }); + + WcSpamOrdersFunctions::prepareDetailsOrderResponse(777, $searchMethod); + + $this->assertSame(777, $capturedId); + } + + // makeOrderRow must be public to use it inside the closure above + public function makeOrderRowPublic(array $orderDetails = [], array $customerDetails = []): \stdClass + { + return $this->makeOrderRow($orderDetails, $customerDetails); + } + + // ------------------------------------------------------------------ + // Tests: response structure + // ------------------------------------------------------------------ + + /** @test */ + public function prepareDetailsOrderResponse_alwaysReturnsAllThreeKeys(): void + { + $searchMethod = $this->makeSearchMethod(function ($id) { return null; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(null, $searchMethod); + + $this->assertArrayHasKey('order_details', $result); + $this->assertArrayHasKey('customer_details', $result); + $this->assertArrayHasKey('error', $result); + } + + /** @test */ + public function prepareDetailsOrderResponse_nullifiesDetails_onError(): void + { + $searchMethod = $this->makeSearchMethod(function ($id) { return null; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(10, $searchMethod); + + $this->assertNull($result['order_details']); + $this->assertNull($result['customer_details']); + } + + // ------------------------------------------------------------------ + // Tests: edge cases with JSON data + // ------------------------------------------------------------------ + + /** @test */ + public function prepareDetailsOrderResponse_handlesEmptyJsonArrays(): void + { + $row = $this->makeOrderRow([], []); + $searchMethod = $this->makeSearchMethod(function ($id) use ($row) { return $row; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(1, $searchMethod); + + $this->assertNull($result['error']); + $this->assertIsArray($result['order_details']); + $this->assertEmpty($result['order_details']); + } + + /** @test */ + public function prepareDetailsOrderResponse_handlesMultipleProducts(): void + { + $orderDetails = [ + ['product_id' => 1, 'quantity' => 3], + ['product_id' => 2, 'quantity' => 1], + ]; + $row = $this->makeOrderRow($orderDetails, []); + $searchMethod = $this->makeSearchMethod(function ($id) use ($row) { return $row; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(1, $searchMethod); + + $this->assertNull($result['error']); + $this->assertCount(2, $result['order_details']); + } + + /** @test */ + public function prepareDetailsOrderResponse_errorIsString_onAnyError(): void + { + $searchMethod = $this->makeSearchMethod(function ($id) { return null; }); + + $result = WcSpamOrdersFunctions::prepareDetailsOrderResponse(5, $searchMethod); + + $this->assertIsString($result['error']); + $this->assertGreaterThan(0, strlen($result['error'])); + } +} + +// --------------------------------------------------------------------------- +// Named stub — declared at file scope so class_exists() / method_exists() +// can see it during checks inside prepareDetailsOrderResponse(). +// --------------------------------------------------------------------------- + +class OrderDataStub +{ + /** @var callable|null */ + public static $impl = null; + + public static function getOrderDataById(int $id) + { + return (self::$impl)($id); + } +}