1/** 2 * Frontend Logic for Sardina Smart Redirect Form - V3.0.0 3 * Target translator forced, UI enhancements, specific elementor popup optimizations. 4 * AJAX tracking added for different redirect types (WhatsApp, Bale, Rubika, Call). 5 */ 6jQuery(document).ready(function ($) { 7 'use strict'; 8 9 // Helper: Fisher-Yates Shuffle algorithm for true randomization 10 function sar_shuffle_array(array) { 11 var currentIndex = array.length, temporaryValue, randomIndex; 12 while (0 !== currentIndex) { 13 randomIndex = Math.floor(Math.random() * currentIndex); 14 currentIndex -= 1; 15 temporaryValue = array[currentIndex]; 16 array[currentIndex] = array[randomIndex]; 17 array[randomIndex] = temporaryValue; 18 } 19 return array; 20 } 21 22 // Helper Function: Extract data specifically from the local container 23 function sar_get_local_data($container) { 24 try { 25 var rawCombos = $container.find('.sar-data-combinations').html(); 26 var rawLangs = $container.find('.sar-data-languages').html(); 27 28 if (!rawCombos || !rawLangs) return null; 29 30 var combinations = JSON.parse($.trim(rawCombos)); 31 var languagesList = JSON.parse($.trim(rawLangs)); 32 var languagesMap = {}; 33 34 $.each(languagesList, function(i, lang) { 35 languagesMap[lang.id.toString()] = lang; 36 }); 37 38 return { combos: combinations, langs: languagesMap }; 39 } catch (e) { 40 console.error("SAR Redirect Form - JSON Parse Error:", e); 41 return null; 42 } 43 } 44 45 // Main Initialization Function Logic 46 function sar_init_redirect_forms() { 47 $('.sar-smart-form-container').each(function() { 48 var $container = $(this); 49 if ($container.hasClass('sar-js-ready')) return; // Prevent double init 50 51 var data = sar_get_local_data($container); 52 if (!data) return; 53 54 var sourceSelect = $container.find('.sar-source-select'); 55 var targetSelect = $container.find('.sar-target-select'); 56 57 // Find valid source IDs that have at least one combination 58 var validSources = []; 59 $.each(data.combos, function(i, combo) { 60 if (validSources.indexOf(combo.source_lang_id.toString()) === -1) { 61 validSources.push(combo.source_lang_id.toString()); 62 } 63 }); 64 65 // Clean dropdown from languages without combinations 66 sourceSelect.find('option').each(function() { 67 var val = $(this).val(); 68 if (val !== "" && validSources.indexOf(val) === -1) { 69 $(this).remove(); 70 } 71 }); 72 73 sourceSelect.val(''); 74 targetSelect.empty().append('<option value="">Ø§ÙØªØ®Ø§Ø¨ Ú©ÙÛØ¯</option>').prop('disabled', true); 75 $container.find('.sar-action-buttons').hide(); 76 77 $container.addClass('sar-js-ready'); 78 }); 79 } 80 81 // Run on Load 82 sar_init_redirect_forms(); 83 84 // Robust Elementor Popup Compatibility 85 $(document).on('elementor/popup/show', function() { 86 $('.sar-smart-form-container').removeClass('sar-js-ready'); 87 setTimeout(sar_init_redirect_forms, 150); 88 }); 89 90 // Select Event Handlers 91 $(document).on('change', '.sar-source-select', function() { 92 var $this = $(this); 93 var $container = $this.closest('.sar-smart-form-container'); 94 var targetSelect = $container.find('.sar-target-select'); 95 var data = sar_get_local_data($container); 96 97 $container.find('.sar-action-buttons').hide(); 98 targetSelect.empty(); 99 100 var srcId = $this.val(); 101 if (!srcId || !data) { 102 targetSelect.append('<option value="">Ø§ÙØªØ®Ø§Ø¨ Ú©ÙÛØ¯</option>').prop('disabled', true); 103 return; 104 } 105 106 var targets = []; 107 $.each(data.combos, function(i, combo) { 108 if (combo.source_lang_id.toString() === srcId) targets.push(combo.target_lang_id.toString()); 109 }); 110 111 if (targets.length > 0) { 112 targetSelect.prop('disabled', false).append('<option value="">-- Ø§ÙØªØ®Ø§Ø¨ Ú©ÙÛØ¯ --</option>'); 113 $.each(data.langs, function(id, lang) { 114 if (targets.indexOf(id) !== -1) targetSelect.append('<option value="' + id + '">' + lang.name + '</option>'); 115 }); 116 } 117 });
118 119 $(document).on('change', '.sar-target-select', function() { 120 var $container = $(this).closest('.sar-smart-form-container'); 121 if ($(this).val()) $container.find('.sar-action-buttons').slideDown(250); 122 else $container.find('.sar-action-buttons').hide(); 123 }); 124 125 // Helper: Get Current Selection Details (Always use Target Translator) 126 function sar_get_active_info($container) { 127 var data = sar_get_local_data($container); 128 var srcId = $container.find('.sar-source-select').val(); 129 var tgtId = $container.find('.sar-target-select').val(); 130 131 var match = null; 132 $.each(data.combos, function(i, combo) { 133 if (combo.source_lang_id.toString() === srcId && combo.target_lang_id.toString() === tgtId) { 134 match = combo; return false; 135 } 136 }); 137 138 if (!match) return null; 139 140 var target = data.langs[tgtId]; 141 var activeTranslator = target; 142 var msg = match.message_template || ''; 143 144 return { combination: match, translator: activeTranslator, message: msg }; 145 } 146 147 // Handle Call Button 148 $(document).on('click', '.sar-btn-call', function() { 149 var $container = $(this).closest('.sar-smart-form-container'); 150 var info = sar_get_active_info($container); 151 if (!info) return; 152 153 $container.find('.sar-call-text').html(info.message.replace(/\n/g, '<br>')); 154 155 var btnList = $container.find('.sar-call-buttons-list'); 156 btnList.empty(); 157 158 var phones = info.translator.phones || []; 159 if (phones.length === 0) { 160 btnList.append('<p style="color:#d32f2f; text-align:center;">Ø´Ù Ø§Ø±Ù ØªÙ Ø§Ø³Û Ø«Ø¨Øª ÙØ´Ø¯Ù است.</p>'); 161 } else { 162 var shuffledPhones = sar_shuffle_array(phones.slice()); 163 var btnTextBase = 'ت٠اس با ٠ترج٠'; 164 var phoneIconSvg = '<svg width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>'; 165 166 var targetId = info.combination.target_lang_id; 167 168 $.each(shuffledPhones, function(i, phone) { 169 var finalBtnText = shuffledPhones.length > 1 ? btnTextBase + ' ' + (i + 1) : btnTextBase; 170 171 // Add class "sar-track-redirect" and data attributes for AJAX logging 172 btnList.append('<a href="tel:+' + phone + '" class="sar-call-btn-dynamic sar-track-redirect" data-target-id="' + targetId + '" data-redirect-type="call">' + phoneIconSvg + ' ' + finalBtnText + '</a>'); 173 }); 174 } 175 176 $container.find('.sar-modal-call').fadeIn(200); 177 }); 178 179 // Handle Online Chat Button 180 $(document).on('click', '.sar-btn-chat', function() { 181 var $container = $(this).closest('.sar-smart-form-container'); 182 var info = sar_get_active_info($container); 183 if (!info) return; 184 185 var targetId = info.combination.target_lang_id; 186 187 var btnWa = $container.find('.sar-btn-whatsapp'); 188 var btnBale = $container.find('.sar-btn-bale'); 189 var btnRubika = $container.find('.sar-btn-rubika'); 190 191 if (info.translator.phones && info.translator.phones.length > 0) { 192 btnWa.attr('href', 'https://api.whatsapp.com/send?phone=' + info.translator.phones[0]) 193 .attr('data-target-id', targetId) 194 .attr('data-redirect-type', 'whatsapp') 195 .addClass('sar-track-redirect') 196 .show(); 197 } else { 198 btnWa.hide(); 199 } 200 201 if (info.translator.bale) { 202 btnBale.attr('href', 'https://ble.ir/' + info.translator.bale) 203 .attr('data-target-id', targetId) 204 .attr('data-redirect-type', 'bale') 205 .addClass('sar-track-redirect') 206 .show(); 207 } else { 208 btnBale.hide(); 209 } 210 211 if (info.translator.rubika) { 212 btnRubika.attr('href', 'https://rubika.ir/' + info.translator.rubika) 213 .attr('data-target-id', targetId) 214 .attr('data-redirect-type', 'rubika') 215 .addClass('sar-track-redirect') 216 .show(); 217 } else { 218 btnRubika.hide(); 219 } 220 221 $container.find('.sar-modal-chat').fadeIn(200); 222 });
223 224 // Modal Closing logic 225 $(document).on('click', '.sar-modal-close', function() { 226 $(this).closest('.sar-modal-overlay').fadeOut(150); 227 }); 228 229 // ======================================================================== 230 // AJAX Tracking Logic (Triggered before redirection) 231 // ======================================================================== 232 $(document).on('click', '.sar-track-redirect', function() { 233 var targetId = $(this).attr('data-target-id'); 234 var redirectType = $(this).attr('data-redirect-type'); 235 236 if (targetId && redirectType && typeof sar_redirect_data !== 'undefined') { 237 $.ajax({ 238 url: sar_redirect_data.ajax_url, 239 type: 'POST', 240 data: { 241 action: 'sar_log_redirect', 242 nonce: sar_redirect_data.log_nonce, 243 target_lang_id: targetId, 244 redirect_type: redirectType 245 } 246 // We don't need to wait for success. The browser will open the native tel: 247 // or target="_blank" links naturally while this background request is sent to the server. 248 }); 249 } 250 }); 251 252});
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.