1/* A visual publication interlude. This module never sends or observes notifications. */ 2(function (window, document) { 3 'use strict'; 4 5 if (window.MatchPublishFlight) return; 6 7 const MINIMUM_DURATION_MS = 10000; 8 const SVG_NS = 'http://www.w3.org/2000/svg'; 9 const roles = [ 10 { key: 'rival', label: 'Takımlar', x: 14, y: 22, icon: 'team' }, 11 { key: 'player', label: 'Oyuncular', x: 86, y: 22, icon: 'player' }, 12 { key: 'referee', label: 'Hakemler', x: 50, y: 88, icon: 'whistle' }, 13 { key: 'coach', label: 'Antrenörler', x: 14, y: 74, icon: 'coach' }, 14 { key: 'audience', label: 'İzleyiciler', x: 86, y: 74, icon: 'audience' }, 15 { key: 'private', label: 'Sohbetler', x: 14, y: 22, icon: 'chat', channel: true }, 16 { key: 'community', label: 'Topluluklar', x: 86, y: 22, icon: 'community', channel: true } 17 ]; 18 const iconPaths = { 19 ball: '<circle cx="12" cy="12" r="9"/><path d="m12 7 4.8 3.5-1.8 5.6H9l-1.8-5.6L12 7Z M12 3v4 M3.5 9.2l3.7 1.3 M6.7 19.3 9 16.1 M17.3 19.3 15 16.1 M20.5 9.2l-3.7 1.3"/>', 20 team: '<circle cx="9" cy="8" r="3"/><path d="M3.5 20v-2a5.5 5.5 0 0 1 11 0v2 M16 5.3a3 3 0 0 1 0 5.5 M17 13a5 5 0 0 1 3.5 4.8V20"/>', 21 player: '<circle cx="12" cy="7" r="3"/><path d="M5 21v-2a7 7 0 0 1 14 0v2 M9 15l3 3 3-3"/>', 22 whistle: '<path d="M15 9h6v4h-5a6.5 6.5 0 1 1-6-7h2v5h3V9Z"/><circle cx="9.5" cy="12.5" r="2.5"/><path d="m15 4 1-2 M19 6l2-1"/>', 23 coach: '<path d="M8 5H5v16h14V5h-3 M9 3h6v4H9z M8 12h3 M8 16h3 M15 11v6 M13 14h4"/>', 24 audience: '<path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/>', 25 chat: '<path d="M21 11.5a8.5 8.5 0 0 1-8.5 8.5H4l1.5-4.5A8.5 8.5 0 1 1 21 11.5Z M8 10h8 M8 14h5"/>', 26 community: '<circle cx="12" cy="7" r="3"/><path d="M6 21v-2a6 6 0 0 1 12 0v2 M4 6a3 3 0 0 0 0 6 M2 19v-2a4 4 0 0 1 2.5-3.7 M20 6a3 3 0 0 1 0 6 M22 19v-2a4 4 0 0 0-2.5-3.7"/>', 27 signal: '<path d="M12 19h.01 M8.5 15.5a5 5 0 0 1 7 0 M5 12a10 10 0 0 1 14 0 M2 8.5a14 14 0 0 1 20 0"/>', 28 lock: '<rect x="5" y="10" width="14" height="11" rx="3"/><path d="M8 10V7a4 4 0 0 1 8 0v3 M12 14v3"/>', 29 check: '<path d="m5 12 4.5 4.5L19 7"/>', 30 warning: '<path d="m10.3 4.2-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-2.8l-8-14a2 2 0 0 0-3.4 0Z M12 9v4 M12 17h.01"/>' 31 }; 32 let activeController = null; 33 let sequence = 0; 34 35 function createElement(tag, className, content) { 36 const element = document.createElement(tag); 37 if (className) element.className = className; 38 if (content !== undefined) element.textContent = content; 39 return element; 40 } 41 42 function icon(name) { 43 const svg = document.createElementNS(SVG_NS, 'svg'); 44 svg.setAttribute('viewBox', '0 0 24 24'); 45 svg.setAttribute('fill', 'none'); 46 svg.setAttribute('stroke', 'currentColor'); 47 svg.setAttribute('stroke-width', '1.6'); 48 svg.setAttribute('stroke-linecap', 'round'); 49 svg.setAttribute('stroke-linejoin', 'round'); 50 svg.setAttribute('aria-hidden', 'true'); 51 svg.setAttribute('focusable', 'false'); 52 // These paths are constant, local artwork; user values only use textContent. 53 svg.innerHTML = iconPaths[name] || iconPaths.signal; 54 return svg; 55 } 56 57 function normalizeCategories(categories) { 58 if (categories === undefined || categories === null) return new Set(['rival', 'player', 'referee']); 59 const aliases = { team: 'rival', teams: 'rival', rivals: 'rival', players: 'player', referees: 'referee', coaches: 'coach', spectators: 'audience', chats: 'private', communities: 'community' }; 60 const supplied = Array.isArray(categories) 61 ? categories 62 : Object.keys(categories).filter(key => categories[key] === true); 63 return new Set(supplied.map(key => aliases[key] || key).filter(key => roles.some(role => role.key === key))); 64 } 65 66 function addConnection(svg, role, selected) { 67 const x = role.x * 6; 68 const y = role.y * 5; 69 const route = role.x === 50 70 ? `M300 225 C300 305 300 350 ${x} ${y}` 71 : `M300 225 C${x} 225 300 ${y} ${x} ${y}`; 72 const group = document.createElementNS(SVG_NS, 'g'); 73 group.setAttribute('class', `mpf-route mpf-role-${role.key}${selected ? '' : ' is-muted'}`); 74 ['mpf-route-track', 'mpf-route-light', 'mpf-route-packet'].forEach(className => { 75 const path = document.createElementNS(SVG_NS, 'path'); 76 path.setAttribute('d', route); 77 path.setAttribute('pathLength', '100'); 78 path.setAttribute('class', className); 79 path.setAttribute('vector-effect', 'non-scaling-stroke'); 80 group.appendChild(path); 81 }); 82 svg.appendChild(group); 83 } 84 85 function createNetwork(categories, facility) { 86 const network = createElement('div', 'mpf-network'); 87 // Decorative network: announcements come from the real request status below. 88 network.setAttribute('aria-hidden', 'true'); 89 network.appendChild(createElement('div', 'mpf-pitch')); 90 network.appendChild(createElement('div', 'mpf-orbit mpf-orbit-outer')); 91 network.appendChild(createElement('div', 'mpf-orbit mpf-orbit-inner')); 92 93 const paths = document.createElementNS(SVG_NS, 'svg'); 94 paths.setAttribute('class', 'mpf-paths'); 95 paths.setAttribute('viewBox', '0 0 600 500'); 96 paths.setAttribute('preserveAspectRatio', 'none'); 97 paths.setAttribute('focusable', 'false'); 98 network.appendChild(paths); 99 100 const hasNearbyRole = roles.some(role => !role.channel && categories.has(role.key)); 101 const sharingOnly = !hasNearbyRole && (categories.has('private') || categories.has('community'));
102 // Without nearby recipients, show only the selected sharing channels, never unrelated roles. 103 // Nearby mode keeps the familiar three roles and adds at most two optional recipient roles. 104 const visibleRoles = sharingOnly 105 ? roles.filter(role => role.channel && categories.has(role.key)) 106 : roles.filter((role, index) => !role.channel && (index < 3 || categories.has(role.key))); 107 visibleRoles.forEach(definition => { 108 const role = sharingOnly && visibleRoles.length === 1 ? { ...definition, x: 50, y: 88 } : definition; 109 const selected = categories.has(role.key); 110 addConnection(paths, role, selected); 111 const node = createElement('div', `mpf-role mpf-role-${role.key}${selected ? '' : ' is-muted'}`); 112 node.style.setProperty('--mpf-x', `${role.x}%`); 113 node.style.setProperty('--mpf-y', `${role.y}%`); 114 const nodeIcon = createElement('span', 'mpf-role-icon'); 115 nodeIcon.appendChild(icon(role.icon)); 116 node.appendChild(nodeIcon); 117 node.appendChild(createElement('span', 'mpf-role-label', role.label)); 118 node.appendChild(createElement('span', 'mpf-role-receipt', selected ? (role.channel ? 'Seçili kanal' : 'Seçili grup') : 'Seçili deÄil')); 119 network.appendChild(node); 120 }); 121 122 const source = createElement('div', 'mpf-source'); 123 const sourceIcon = createElement('span', 'mpf-source-icon'); 124 sourceIcon.appendChild(icon('ball')); 125 source.appendChild(sourceIcon); 126 source.appendChild(createElement('span', 'mpf-source-kicker', 'OYUN BURADA BAÅLAR')); 127 source.appendChild(createElement('strong', 'mpf-source-title', 'Maç ilanın')); 128 const venue = createElement('span', 'mpf-source-venue', facility || 'Sahada buluÅalım'); 129 venue.title = facility || 'Sahada buluÅalım'; 130 source.appendChild(venue); 131 const sourceSignal = createElement('span', 'mpf-source-signal'); 132 sourceSignal.appendChild(icon('signal')); 133 source.appendChild(sourceSignal); 134 network.appendChild(source); 135 136 if (!categories.size) network.classList.add('is-notifications-off'); 137 return network; 138 } 139 140 function start(options) { 141 if (activeController) return activeController; 142 const settings = options || {}; 143 const categories = normalizeCategories(settings.categories); 144 const facility = typeof settings.facility === 'string' ? settings.facility.trim().slice(0, 180) : ''; 145 const id = `match-publish-flight-${++sequence}`; 146 const previouslyFocused = document.activeElement; 147 const overlay = createElement('dialog', 'match-publish-flight'); 148 overlay.id = id; 149 overlay.setAttribute('role', 'dialog'); 150 overlay.setAttribute('aria-modal', 'true'); 151 overlay.setAttribute('aria-labelledby', `${id}-title`); 152 overlay.setAttribute('aria-describedby', `${id}-description ${id}-status ${id}-note`); 153 overlay.setAttribute('aria-busy', 'true'); 154 overlay.tabIndex = -1; 155 156 const panel = createElement('div', 'mpf-panel'); 157 const header = createElement('header', 'mpf-header'); 158 const eyebrow = createElement('span', 'mpf-eyebrow'); 159 eyebrow.appendChild(createElement('span', 'mpf-brand-mark')); 160 eyebrow.appendChild(createElement('span', '', 'SAHASENİN')); 161 eyebrow.appendChild(createElement('span', 'mpf-eyebrow-separator', '/')); 162 eyebrow.appendChild(createElement('span', '', 'BİLDİRİM AKIÅI')); 163 header.appendChild(eyebrow); 164 const title = createElement('h2', 'mpf-title', categories.size ? 'Bildirimler hedefine ulaÅıyor.' : 'Maç ilanın sahaya çıkıyor.'); 165 title.id = `${id}-title`; 166 header.appendChild(title); 167 const description = createElement('p', 'mpf-description', categories.size 168 ? 'Bir maç ilanı. Aynı anda kurulan yeni baÄlantılar.' 169 : 'Bildirimler kapalı. İlanın yayın ayarlarıyla hazırlanıyor.'); 170 description.id = `${id}-description`; 171 header.appendChild(description); 172 panel.appendChild(header); 173 174 panel.appendChild(createNetwork(categories, facility)); 175 176 const footer = createElement('footer', 'mpf-footer'); 177 const status = createElement('div', 'mpf-status'); 178 status.id = `${id}-status`; 179 status.setAttribute('role', 'status'); 180 status.setAttribute('aria-live', 'polite'); 181 status.setAttribute('aria-atomic', 'true'); 182 const statusIcon = createElement('span', 'mpf-status-icon'); 183 statusIcon.setAttribute('aria-hidden', 'true'); 184 statusIcon.appendChild(createElement('span', 'mpf-status-spinner')); 185 const statusCopy = createElement('div', 'mpf-status-copy'); 186 const statusTitle = createElement('strong', 'mpf-status-title', 'İlanın y
186ayınlanıyor'); 187 const statusDescription = createElement('span', 'mpf-status-description', 'İÅlem tamamlandıÄında otomatik devam edeceÄiz.'); 188 statusCopy.appendChild(statusTitle); 189 statusCopy.appendChild(statusDescription); 190 status.appendChild(statusIcon); 191 status.appendChild(statusCopy); 192 footer.appendChild(status); 193 194 const note = createElement('p', 'mpf-note'); 195 note.id = `${id}-note`; 196 note.appendChild(icon('lock')); 197 note.appendChild(createElement('span', '', 'Bu görsel bildirim akıÅını temsil eder; teslimat teyidi deÄildir.')); 198 footer.appendChild(note); 199 panel.appendChild(footer); 200 overlay.appendChild(panel); 201 202 let outcome = null; 203 let ready = false; 204 let closed = false; 205 let completionTimer = null; 206 let waitingTimer = null; 207 let resolveFinished; 208 const finished = new Promise(resolve => { resolveFinished = resolve; }); 209 const clock = () => window.performance && typeof window.performance.now === 'function' ? window.performance.now() : Date.now(); 210 let startedAt; 211 const fallbackInert = []; 212 213 function focusOverlay() { 214 if (closed || document.activeElement === overlay) return; 215 try { overlay.focus({ preventScroll: true }); } 216 catch (_) { overlay.focus(); } 217 } 218 219 function handleKeydown(event) { 220 if (closed) return; 221 if (event.key === 'Escape' || event.key === 'Tab') { 222 event.preventDefault(); 223 event.stopImmediatePropagation(); 224 focusOverlay(); 225 } 226 } 227 228 function handleFocus(event) { 229 if (!closed && !overlay.contains(event.target)) focusOverlay(); 230 } 231 232 function handleCancel(event) { 233 event.preventDefault(); 234 event.stopPropagation(); 235 } 236 237 function setOutcomeState(result) { 238 overlay.dataset.outcome = result; 239 overlay.setAttribute('aria-busy', 'false'); 240 statusIcon.replaceChildren(icon(result === 'success' ? 'check' : 'warning')); 241 statusTitle.textContent = result === 'success' ? 'Maç ilanın yayınlandı' : 'İlan henüz yayınlanamadı'; 242 statusDescription.textContent = result === 'success' 243 ? 'Yayın tamamlandı. AkıŠgörseli tamamlanıyor.' 244 : 'İlan bilgilerine geri döndüÄünde yeniden deneyebilirsin.'; 245 if (result === 'error') { 246 title.textContent = 'İlan henüz yayınlanamadı.'; 247 description.textContent = 'Bir sorun oluÅtu. Birazdan ilan bilgilerine geri döneceksin.'; 248 } 249 } 250 251 function finish(result) { 252 if (result !== 'success' && result !== 'error') throw new TypeError('MatchPublishFlight.finish expects success or error.'); 253 if (outcome || closed) return finished; 254 // Only the caller's actual publication result may settle the visual interlude. 255 outcome = result; 256 window.clearTimeout(waitingTimer); 257 setOutcomeState(result); 258 function completeWhenReady() { 259 if (closed) return; 260 // Recheck the monotonic clock: browser timer rounding must not shorten 10s. 261 const remaining = MINIMUM_DURATION_MS - (clock() - startedAt); 262 if (remaining > 0) { 263 completionTimer = window.setTimeout(completeWhenReady, Math.ceil(remaining)); 264 return; 265 } 266 ready = true; 267 overlay.dataset.ready = 'true'; 268 resolveFinished(result); 269 } 270 const remaining = Math.max(0, Math.ceil(MINIMUM_DURATION_MS - (clock() - startedAt))); 271 completionTimer = window.setTimeout(completeWhenReady, remaining); 272 return finished; 273 } 274 275 function close() { 276 // There is intentionally no forced-close option, cancel button, or timeout settlement. 277 if (!ready || closed) return false;
278 closed = true; 279 window.clearTimeout(completionTimer); 280 window.clearTimeout(waitingTimer); 281 document.removeEventListener('keydown', handleKeydown, true); 282 document.removeEventListener('focusin', handleFocus, true); 283 overlay.removeEventListener('cancel', handleCancel); 284 if (typeof overlay.close === 'function' && overlay.open) overlay.close(); 285 overlay.remove(); 286 fallbackInert.forEach(item => { 287 if (!item.wasInert && item.element.isConnected) item.element.removeAttribute('inert'); 288 }); 289 document.body.classList.remove('match-publish-flight-open'); 290 activeController = null; 291 if (previouslyFocused && previouslyFocused.isConnected && typeof previouslyFocused.focus === 'function') { 292 try { previouslyFocused.focus({ preventScroll: true }); } 293 catch (_) { previouslyFocused.focus(); } 294 } 295 return true; 296 } 297 298 const controller = Object.freeze({ finish, close, finished }); 299 activeController = controller; 300 document.body.appendChild(overlay); 301 document.body.classList.add('match-publish-flight-open'); 302 overlay.addEventListener('cancel', handleCancel); 303 document.addEventListener('keydown', handleKeydown, true); 304 document.addEventListener('focusin', handleFocus, true); 305 try { 306 if (typeof overlay.showModal !== 'function') throw new Error('Native dialog unavailable'); 307 // Top-layer isolation is limited to this non-interactive publication interlude. 308 overlay.showModal(); 309 } catch (_) { 310 overlay.setAttribute('open', ''); 311 Array.from(document.body.children).filter(child => child !== overlay).forEach(element => { 312 fallbackInert.push({ element, wasInert: element.hasAttribute('inert') }); 313 element.setAttribute('inert', ''); 314 }); 315 } 316 focusOverlay(); 317 startedAt = clock(); 318 waitingTimer = window.setTimeout(function () { 319 if (!outcome && !closed) statusDescription.textContent = 'İÅlem devam ediyor. Lütfen bu ekranı açık tut.'; 320 }, 16000); 321 return controller; 322 } 323 324 window.MatchPublishFlight = Object.freeze({ start, minimumDurationMs: MINIMUM_DURATION_MS }); 325})(window, document);
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.