1/* RSH İstek Hattı â React/player yaÅam döngüsünden tamamen baÄımsız modül. */ 2(() => { 3 'use strict'; 4 5 const ENDPOINT = '/api/v1/request-line.php'; 6 const DEFAULT_CLOSED = 'Åu anda yeni Åarkı isteÄi kabul edemiyoruz. İstek hattımız tekrar aktif olduÄunda bize buradan ulaÅabilirsiniz. Lütfen daha sonra yeniden deneyin.'; 7 let active = false; 8 let closedMessage = DEFAULT_CLOSED; 9 let lastFocus = null; 10 11 const ready = (callback) => document.readyState === 'loading' 12 ? document.addEventListener('DOMContentLoaded', callback, { once: true }) 13 : callback(); 14 15 ready(() => { 16 if (document.querySelector('[data-rsh-request-line]')) return; 17 18 const modal = document.createElement('div'); 19 modal.className = 'rshRequestModal'; 20 modal.dataset.rshRequestLine = 'modal'; 21 modal.hidden = true; 22 modal.innerHTML = ` 23 <button class="rshRequestModal__backdrop" type="button" data-request-close aria-label="Pencereyi kapat"></button> 24 <section class="rshRequestModal__dialog" role="dialog" aria-modal="true" aria-labelledby="rsh-request-title"> 25 <button class="rshRequestModal__close" type="button" data-request-close aria-label="Pencereyi kapat"><span aria-hidden="true">Ã</span></button> 26 <header class="rshRequestModal__header"> 27 <span class="rshRequestModal__icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 18V5l11-2v13M9 18a3 3 0 1 1-3-3c1.7 0 3 1.3 3 3Zm11-2a3 3 0 1 1-3-3c1.7 0 3 1.3 3 3Z"/></svg></span> 28 <div><small>CANLI YAYIN</small><h2 id="rsh-request-title">İstek Hattı</h2><p>Dinlemek istediÄiniz Åarkıyı stüdyomuza iletin.</p></div> 29 </header> 30 <div class="rshRequestState rshRequestState--closed" hidden> 31 <span class="rshRequestState__icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 13a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm-5.7 6.7a11 11 0 0 1 0-15.4m11.4 0a11 11 0 0 1 0 15.4M9.1 16.9a7 7 0 0 1 0-9.8m5.8 0a7 7 0 0 1 0 9.8M12 13v8"/></svg></span> 32 <small>ÅU ANDA ÃEVRİMDIÅI</small><h3>İstek Hattımız Åu Anda Kapalı</h3><p data-closed-copy></p> 33 </div> 34 <form class="rshRequestForm" novalidate> 35 <label><span>Ad Soyad</span><input name="name" type="text" minlength="2" maxlength="100" autocomplete="name" placeholder="Adınız ve soyadınız" required></label> 36 <label><span>İstek Åarkı</span><input name="song" type="text" minlength="2" maxlength="160" autocomplete="off" placeholder="Sanatçı â Åarkı adı" required></label> 37 <label><span>Mesaj <em>İsteÄe baÄlı</em></span><textarea name="message" rows="4" maxlength="1000" placeholder="Yayıncıya iletmek istediÄiniz kısa mesaj"></textarea><small data-message-count>0 / 1000</small></label> 38 <input class="rshRequestForm__trap" name="website" type="hidden" value="" aria-hidden="true"> 39 <label class="rshRequestForm__consent"><input name="consent" type="checkbox" value="1" required><span>GönderdiÄim bilgilerin istek talebimin deÄerlendirilmesi amacıyla kullanılmasını kabul ediyorum.</span></label> 40 <div class="rshRequestForm__notice" role="status" aria-live="polite"></div> 41 <button class="rshRequestForm__submit" type="submit"><span>İsteÄi Gönder</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg></button> 42 </form> 43 <div class="rshRequestState rshRequestState--success" hidden> 44 <span class="rshRequestState__icon"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></span> 45 <small>İSTEK ALINDI</small><h3>TeÅekkür ederiz.</h3><p>İsteÄiniz baÅarıyla alındı. TeÅekkür ederiz.</p> 46 <button type="button" data-request-close>Tamam</button> 47 </div> 48 </section>`; 49 document.body.appendChild(modal); 50 51 const form = modal.querySelector('.rshRequestForm'); 52 const closed = modal.querySelector('.rshRequestState--closed'); 53 const success = modal.querySelector('.rshRequestState--success'); 54 const notice = modal.querySelector('.rshRequestForm__notice'); 55 const submit = modal.querySelector('.rshRequestForm__submit'); 56 const textarea = form.elements.message; 57 const counter = modal.querySelector('[data-message-count]'); 58 59 const close = () => { 60 modal.classList.remove('is-open'); 61 document.documentElement.classList.remove('rshRequestModalOpen'); 62 window.setTimeout(() => { modal.hidden = true; lastFocus?.focus?.(); }, 220); 63 }; 64 const open = (trigger) => { 65 lastFocus = trigger; 66 modal.hidden = false;
67 form.hidden = !active; 68 closed.hidden = active; 69 success.hidden = true; 70 modal.querySelector('[data-closed-copy]').textContent = closedMessage; 71 notice.textContent = ''; 72 requestAnimationFrame(() => { 73 modal.classList.add('is-open'); 74 document.documentElement.classList.add('rshRequestModalOpen'); 75 }); 76 window.setTimeout(() => (active ? form.elements.name : modal.querySelector('[data-request-close]'))?.focus(), 90); 77 }; 78 79 modal.querySelectorAll('[data-request-close]').forEach((button) => button.addEventListener('click', close)); 80 document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && !modal.hidden) close(); }); 81 textarea.addEventListener('input', () => { counter.textContent = `${textarea.value.length} / 1000`; }); 82 83 form.addEventListener('submit', async (event) => { 84 event.preventDefault(); 85 notice.textContent = ''; 86 if (!form.reportValidity()) return; 87 submit.disabled = true; 88 submit.querySelector('span').textContent = 'Gönderiliyor'; 89 try { 90 const payload = Object.fromEntries(new FormData(form).entries()); 91 payload.consent = form.elements.consent.checked; 92 const response = await fetch(ENDPOINT, { 93 method: 'POST', cache: 'no-store', credentials: 'same-origin', 94 headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, 95 body: JSON.stringify(payload) 96 }); 97 const result = await response.json().catch(() => ({})); 98 if (!response.ok) throw new Error(result.error || 'İstek gönderilemedi. Lütfen yeniden deneyin.'); 99 form.reset(); counter.textContent = '0 / 1000'; form.hidden = true; success.hidden = false; 100 } catch (error) { 101 notice.textContent = error?.message || 'İstek gönderilemedi. Lütfen yeniden deneyin.'; 102 } finally { 103 submit.disabled = false; 104 submit.querySelector('span').textContent = 'İsteÄi Gönder'; 105 } 106 }); 107 108 const launcher = document.createElement('button'); 109 launcher.type = 'button'; 110 launcher.className = 'rshRequestLauncher'; 111 launcher.dataset.rshRequestLine = 'launcher'; 112 launcher.setAttribute('aria-haspopup', 'dialog'); 113 launcher.setAttribute('aria-label', 'İstek Gönder'); 114 // Durum API'den doÄrulanana kadar mobil butonu göstermeyerek kısa süreli 115 // görünme/kaybolma (flash) etkisini önler. WhatsApp bu durumdan baÄımsızdır. 116 launcher.hidden = true; 117 launcher.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 18V5l11-2v13M9 18a3 3 0 1 1-3-3c1.7 0 3 1.3 3 3Zm11-2a3 3 0 1 1-3-3c1.7 0 3 1.3 3 3Z"/></svg><span>İstek Gönder</span>'; 118 launcher.addEventListener('click', () => open(launcher)); 119 120 const playerLauncher = document.createElement('button'); 121 playerLauncher.type = 'button'; 122 playerLauncher.className = 'rshRequestPlayerButton'; 123 playerLauncher.dataset.rshRequestLine = 'player-launcher'; 124 playerLauncher.setAttribute('aria-haspopup', 'dialog'); 125 playerLauncher.setAttribute('aria-label', 'İstek Gönder'); 126 playerLauncher.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 18V5l11-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="17" cy="16" r="3"/></svg><span>İstek Hattı</span>'; 127 playerLauncher.addEventListener('click', () => open(playerLauncher)); 128 129 const fallback = document.createElement('div'); 130 fallback.className = 'rshRequestDock'; 131 fallback.appendChild(launcher); 132 document.body.appendChild(fallback); 133 134 /* React aÄacını izlemek yerine kısa süreli ve zararsız polling kullanılır. */ 135 let attempts = 0; 136 const attachNearWhatsApp = () => { 137 attempts += 1; 138 const whatsapp = document.querySelector('.waMessenger'); 139 const whatsappButton = whatsapp?.querySelector('.waLauncher'); 140 if (whatsapp && whatsappButton) { 141 const label = whatsappButton.querySelector('span'); 142 if (label && label.textContent !== 'WhatsApp') label.textContent = 'WhatsApp'; 143 if (launcher.parentElement !== whatsapp || launcher.nextElementSibling !== whatsappButton) { 144 whatsapp.insertBefore(launcher, whatsappButton); 145 } 146 fallback.remove(); 147 return true; 148 } 149 return false;
150 }; 151 if (!attachNearWhatsApp()) { 152 const timer = window.setInterval(() => { 153 if (attachNearWhatsApp() || attempts >= 40) window.clearInterval(timer); 154 }, 500); 155 } 156 157 let playerAttempts = 0; 158 const attachToPlayer = () => { 159 playerAttempts += 1; 160 const controls = document.querySelector('.radioDockV2__controls'); 161 const play = controls?.querySelector('.radioDockV2__play'); 162 if (!controls || !play) return false; 163 if (playerLauncher.parentElement !== controls || playerLauncher.nextElementSibling !== play) controls.insertBefore(playerLauncher, play); 164 return true; 165 }; 166 if (!attachToPlayer()) { 167 const playerTimer = window.setInterval(() => { 168 if (attachToPlayer() || playerAttempts >= 40) window.clearInterval(playerTimer); 169 }, 500); 170 } 171 172 fetch(ENDPOINT, { cache: 'no-store', credentials: 'same-origin', headers: { Accept: 'application/json' } }) 173 .then((response) => response.ok ? response.json() : Promise.reject()) 174 .then((payload) => { 175 active = payload?.data?.active === true; 176 closedMessage = payload?.data?.closed_message || DEFAULT_CLOSED; 177 // Bu launcher mobilde WhatsApp'ın yanında görünen İstek Hattı 178 // butonudur. Hat kapalıysa yalnızca bu buton gizlenir; WhatsApp'a 179 // hiçbir sınıf, stil veya görünürlük deÄiÅikliÄi uygulanmaz. 180 launcher.hidden = !active; 181 }) 182 .catch(() => { 183 active = false; 184 closedMessage = DEFAULT_CLOSED; 185 launcher.hidden = true; 186 }); 187 }); 188})();
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.