1(function () 2{ 3 'use strict'; 4 let yandexLoader = null; 5 function escapeHtml(value){const node=document.createElement('span');node.textContent=String(value||'');return node.innerHTML;} 6 function loadYandex(apiKey) 7 { 8 if(window.ymaps){return Promise.resolve(window.ymaps);}if(yandexLoader){return yandexLoader;} 9 yandexLoader=new Promise((resolve,reject)=>{if(!apiKey){reject(new Error('YANDEX_MAPS_KEY_MISSING'));return;}const script=document.createElement('script');script.src='https://api-maps.yandex.ru/2.1/?apikey='+encodeURIComponent(apiKey)+'&lang=ru_RU';script.async=true;script.dataset.mbcYandexMaps='1';script.onload=()=>window.ymaps?window.ymaps.ready(()=>resolve(window.ymaps)):reject(new Error('YANDEX_MAPS_GLOBAL_MISSING'));script.onerror=()=>reject(new Error('YANDEX_MAPS_LOAD_FAILED'));document.head.appendChild(script);});return yandexLoader; 10 } 11 function parsePoints(root){const node=root.querySelector('.js-mbcCatalogMapData');if(!node){return [];}try{return JSON.parse(node.textContent||'[]');}catch(error){console.error('MBClub Partners Yandex map data is invalid',error);return [];}} 12 function balloonContent(point) 13 { 14 const company=escapeHtml(point.company_name||point.company||point.location_name||point.location||'ÐомпаниÑ'); 15 const location=escapeHtml(point.location_name||point.location||''); 16 const address=escapeHtml([point.city,point.address].filter(Boolean).join(', ')); 17 const logo=point.logo_url?'<img class="mbcCatalog-mapBalloonLogo" src="'+escapeHtml(point.logo_url)+'" alt="">':'<span class="mbcCatalog-mapBalloonLogo mbcCatalog-mapBalloonLogo--fallback" aria-hidden="true">'+escapeHtml(point.initial||company.charAt(0))+'</span>'; 18 const locationLine=location&&location!==company?'<div class="mbcCatalog-mapBalloonLocation">'+location+'</div>':''; 19 const partnerBadge=point.relationship_status==='partner'?'<span class="mbcCatalog-mapBalloonPartner">ÐаÑÑнÑÑ MBClub</span>':''; 20 const type=point.primary_type?'<span class="mbcCatalog-mapBalloonType">'+escapeHtml(point.primary_type)+'</span>':''; 21 const statusClass=point.open_state==='open'?' mbcCatalog-mapBalloonStatus--open':(point.open_state==='temporarily_closed'?' mbcCatalog-mapBalloonStatus--attention':''); 22 const status=point.open_status?'<div class="mbcCatalog-mapBalloonStatus'+statusClass+'">'+escapeHtml(point.open_status)+'</div>':''; 23 const today=point.today_hours?'<div class="mbcCatalog-mapBalloonHours"><strong>СегоднÑ:</strong> '+escapeHtml(point.today_hours)+'</div>':''; 24 const services=Array.isArray(point.services)&&point.services.length?'<div class="mbcCatalog-mapBalloonServices">'+point.services.map((service)=>'<span>'+escapeHtml(service)+'</span>').join('')+'</div>':''; 25 const phone=point.phone_uri&&point.phone_display?'<a class="mbcCatalog-mapBalloonPhone" href="'+escapeHtml(point.phone_uri)+'">'+escapeHtml(point.phone_display)+'</a>':''; 26 const companyLink=point.company_url?'<a class="mbcCatalog-mapBalloonLink" href="'+escapeHtml(point.company_url)+'">Ркомпании</a>':''; 27 const call=point.phone_uri?'<a class="mbcCatalog-mapBalloonAction mbcCatalog-mapBalloonAction--secondary" href="'+escapeHtml(point.phone_uri)+'">ÐозвониÑÑ</a>':''; 28 const route=Number.isFinite(Number(point.lat))&&Number.isFinite(Number(point.lng))?'<a class="mbcCatalog-mapBalloonAction mbcCatalog-mapBalloonAction--secondary" href="https://yandex.ru/maps/?rtext=~'+encodeURIComponent(point.lat+','+point.lng)+'&rtt=auto" target="_blank" rel="noopener noreferrer">ÐаÑÑÑÑÑ</a>':''; 29 return '<div class="mbcCatalog-mapBalloon"><div class="mbcCatalog-mapBalloonHead">'+logo+'<div class="mbcCatalog-mapBalloonIdentity"><strong class="mbcCatalog-mapBalloonTitle">'+company+'</strong><div class="mbcCatalog-mapBalloonBadges">'+partnerBadge+type+'</div></div></div>'+locationLine+'<div class="mbcCatalog-mapBalloonAddress">'+address+'</div>'+status+today+services+phone+'<div class="mbcCatalog-mapBalloonActions">'+companyLink+call+route+'</div></div>'; 30 } 31 function setQuery(values){const url=new URL(window.location.href);
31Object.entries(values).forEach(([key,value])=>{if(value===''||value===null){url.searchParams.delete(key);}else{url.searchParams.set(key,value);}});url.searchParams.delete('page');window.location.assign(url.toString());} 32 function configureClusters(ymaps,clusterer) 33 { 34 const neutralContentLayout=ymaps.templateLayoutFactory.createClass('<div style="font:600 13px Arial,sans-serif;color:#252a31;white-space:nowrap;">{{ properties.geoObjects.length }}</div>'); 35 const partnerContentLayout=ymaps.templateLayoutFactory.createClass('<div style="position:relative;display:inline-block;font:600 13px Arial,sans-serif;color:#252a31;white-space:nowrap;">{{ properties.geoObjects.length }}<span style="position:absolute;left:100%;top:-5px;color:#1686e7;font-size:9px;line-height:1;">â </span></div>'); 36 clusterer.createCluster=function(center,geoObjects) 37 { 38 const cluster=ymaps.Clusterer.prototype.createCluster.call(this,center,geoObjects); 39 const hasPartner=geoObjects.some((geoObject)=>geoObject.properties.get('mbcIsPartner')===true); 40 cluster.options.set({preset:hasPartner?'islands#blueClusterIcons':'islands#grayClusterIcons',iconContentLayout:hasPartner?partnerContentLayout:neutralContentLayout}); 41 cluster.properties.set('hintContent',hasPartner?'Ð ÑÑой гÑÑппе еÑÑÑ Ð¿Ð°ÑÑнÑÑ MBClub':'ÐÑÑппа ÑеÑвиÑов'); 42 return cluster; 43 }; 44 } 45 async function initMap(root) 46 { 47 const mapNode=root.querySelector('.js-mbcCatalogMap');if(!mapNode||mapNode.dataset.ready==='1'||mapNode.dataset.ready==='loading'){return;}const points=parsePoints(root);if(!points.length){return;}mapNode.dataset.ready='loading'; 48 try 49 { 50 const ymaps=await loadYandex(root.dataset.yandexMapsKey||''); 51 const map=new ymaps.Map(mapNode,{center:[55.751244,37.618423],zoom:9,controls:['zoomControl','fullscreenControl','searchControl','geolocationControl']},{searchControlProvider:'yandex#search',suppressMapOpenBlock:true});map.behaviors.disable('scrollZoom'); 52 const clusterer=new ymaps.Clusterer({preset:'islands#grayClusterIcons',groupByCoordinates:false,clusterDisableClickZoom:false,clusterOpenBalloonOnClick:true,gridSize:64});const markers=[];configureClusters(ymaps,clusterer); 53 points.forEach((point)=>{const isPartner=point.relationship_status==='partner';const preset=isPartner?'islands#blueAutoIcon':(point.verification_state==='verified'?'islands#blackAutoIcon':'islands#grayAutoIcon');const marker=new ymaps.Placemark([point.lat,point.lng],{hintContent:escapeHtml(point.company_name||point.company||point.location_name||point.location),balloonContent:balloonContent(point),mbcIsPartner:isPartner},{preset:preset,balloonMinWidth:300,balloonMaxWidth:380});marker.mbcPoint=point;marker.events.add('click',()=>{root.querySelectorAll('.mbcCatalog-card--mapActive').forEach((card)=>card.classList.remove('mbcCatalog-card--mapActive'));const card=root.querySelector('[data-organic-partner-id="'+point.partner_id+'"]');if(card){card.classList.add('mbcCatalog-card--mapActive');}});markers.push(marker);}); 54 clusterer.add(markers);map.geoObjects.add(clusterer);root.mbcMap=map;root.mbcMapMarkers=markers;root.mbcMapFocusReady=false; 55 const focusPending=()=>{root.mbcMapFocusReady=true;const partnerId=root.mbcPendingPartnerId;if(partnerId!==undefined){root.mbcPendingPartnerId=undefined;focusPartnerOnMap(root,partnerId);}}; 56 const bounds=clusterer.getBounds();if(bounds){const fit=map.setBounds(bounds,{checkZoomRange:true,zoomMargin:32});if(fit&&typeof fit.then==='function'){fit.then(focusPending,focusPending);}else{window.setTimeout(focusPending,0);}}else{focusPending();} 57 mapNode.dataset.ready='1'; 58 } 59 catch(error){mapNode.dataset.ready='error';mapNode.innerHTML='<p class="mbcCatalog-mapUnavailable">Ð¯Ð½Ð´ÐµÐºÑ ÐаÑÑа вÑеменно недоÑÑÑпна.</p>';console.error('MBClub Partners Yandex map initialization failed',error);} 60 } 61 function focusPartnerOnMap(root,partnerId,attempt=0) 62 { 63 root.mbcPendingPartnerId=Number(partnerId); 64 switchView(root,'map'); 65 if(!root.mbcMapFocusReady) 66 { 67 if(attempt<40){window.setTimeout(()=>focusPartnerOnMap(root,partnerId,attempt+1),75);}return; 68 } 69 const marker=root.mbcMapMarkers?.find((item)=>Number(item.mbcPoint.partner_id)===Number(partnerId)); 70 if(!marker) 71 { 72 if(attempt<40){window.setTimeout(()=>focusPartnerOnMap(root,partnerId,attempt+1),75);}return; 73 } 74 root.mbcMap.setCenter(marker.geometry.getCoordinates(),Math.max(root.mbcMap.getZoom(),14),{duration:250}); 75 marker.balloon.open(); 76 root.mbcPendingPartnerId=undefined; 77 } 78 function switchView(root,view){root.dataset.view=view;root.querySelectorAll('.js-mbcView').forEach((button)=>button.setAttribute('aria-pressed',button.dataset.view===view?'true':'false'));const url=new URL(window.location.href);if(view==='map'){url.searchParams.set('view','map');}else{url.searchParams.delete('view');}window.history.replaceState({},'',url.toString());if(view==='map'){initMap(root).then(()=>window.setTimeout(()=>root.mbcMap?.container.fitToViewport(),30));}} 79 function init(root) 80 { 81 root.querySelectorAll('.js-mbcView').forEach((button)=>button.addEventListener('click',()=>
81switchView(root,button.dataset.view)));root.querySelectorAll('.js-mbcShowOnMap').forEach((button)=>button.addEventListener('click',()=>focusPartnerOnMap(root,button.dataset.partnerId)));root.querySelector('.js-mbcCatalogSort')?.addEventListener('change',(event)=>setQuery({sort:event.target.value}));root.querySelector('.js-mbcCatalogSearch')?.addEventListener('submit',(event)=>{event.preventDefault();setQuery({q:new FormData(event.currentTarget).get('q')?.toString().trim()||''});});root.querySelector('.js-mbcCatalogNear')?.addEventListener('click',()=>{if(!navigator.geolocation){return;}navigator.geolocation.getCurrentPosition((position)=>setQuery({near:'1',lat:position.coords.latitude.toFixed(6),lng:position.coords.longitude.toFixed(6),radius:'30',sort:'distance'}),()=>window.alert('Ðе ÑдалоÑÑ Ð¾Ð¿ÑеделиÑÑ Ð¼ÐµÑÑоположение.'));});if(root.dataset.view==='map'){initMap(root);} 82 } 83 document.querySelectorAll('.mbcCatalog').forEach(init); 84})();
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.