1(function ($, utils, BannersManager, CountersManager) { 2 $(function () { 3 var loadMorePostIds = Array.isArray(window.loadMorePostIds) ? window.loadMorePostIds : []; 4 5 // If there are no posts to load, then it's pointless to continue 6 if (!loadMorePostIds.length) { 7 return; 8 } 9 10 var nextPostOffset = 0; 11 12 var nextPostDataRequest = null; 13 14 var hasMorePosts = true; 15 16 var $currentPost = null; 17 18 var prevPostData = null; 19 20 var currentPostData = null; 21 22 var $window = $(window); 23 24 var lastScrollTop = $window.scrollTop(); 25 26 var isScrollingUp = false; 27 28 var bannersReloadScrollStates = {}; 29 30 var ymPreloadArticleId = null; 31 32 // Prevent automatic browser scroll on refresh 33 $window.on('unload', function () { 34 $window.scrollTop(0); 35 }); 36 37 $window.on('scroll', utils.debounce(onScroll, 100)); 38 39 function onScroll() { 40 var currentScrollTop = window.scrollY; 41 42 var scrollDelta = currentScrollTop - lastScrollTop; 43 44 isScrollingUp = currentScrollTop <= lastScrollTop; 45 46 lastScrollTop = currentScrollTop; 47 48 var viewportHeight = window.innerHeight, 49 viewportTop = window.scrollY, 50 viewportBottom = viewportTop + viewportHeight; 51 52 var $posts = $('.b-post-view'); 53 54 $posts.each(function (index) { 55 var $post = $(this); 56 57 var postData = $post.data('postData'); 58 59 if (!postData) { 60 return; 61 } 62 63 var postContainer = $post.get(0).closest('.b-site-body'); 64 65 var postContainerRect = postContainer.getBoundingClientRect(), 66 postContainerHeight = postContainerRect.height, 67 postContainerTop = postContainerRect.top + window.scrollY, 68 postContainerMiddle = postContainerTop + postContainerHeight / 2, 69 postContainerBottom = postContainerTop + postContainerHeight; 70 71 var intersectionLine = viewportTop + 300; 72 73 var isIntersecting = intersectionLine >= postContainerTop && intersectionLine <= postContainerBottom; 74 75 if (index === 0) { 76 isIntersecting = isIntersecting || viewportTop <= postContainerTop; 77 } else if (index === $posts.length - 1) { 78 isIntersecting = isIntersecting || viewportBottom >= postContainerBottom; 79 } 80 81 if (isIntersecting) { 82 var shouldChangeCurrentPost = currentPostData?.id !== postData.id && viewportTop <= postContainerBottom - Math.min(postContainerHeight * 0.5, viewportHeight * 0.5); 83 84 var bannersReloadScrollState = bannersReloadScrollStates[postData.id]; 85 86 if (!bannersReloadScrollState) { 87 bannersReloadScrollState = bannersReloadScrollStates[postData.id] = { 88 heightAcquired: 0, 89 heightRequired: 2400, 90 }; 91 } 92 93 if (shouldChangeCurrentPost) { 94 changeCurrentPost($post); 95 96 bannersReloadScrollState.heightAcquired = 0; 97 } else { 98 if (bannersReloadScrollState.heightAcquired >= bannersReloadScrollState.heightRequired) { 99 bannersReloadScrollState.heightAcquired = 0; 100 101 // Ð ÑÐ°Ð¼ÐºÐ°Ñ Ð·Ð°Ð´Ð°Ñи SOB-77: Ñак как Ñ Ð½Ð°Ñ Ð½ÐµÑ Ð±Ð°Ð½Ð½ÐµÑов в лонгÑÐ¸Ð´Ð°Ñ , Ñо Ð¼Ñ Ð¿ÐµÑезагÑÑжаем ÑÑеÑÑики баннеÑов оÑделÑно 102 if (postData.isLongread) { 103 updateBannerCounters(); 104 } else { 105 updateBanners($post); 106 } 107 } else { 108 bannersReloadScrollState.heightAcquired += Math.abs(scrollDelta); 109 } 110 } 111 } 112 113 var shouldLoadNextPost = !hasNextPostLoaded(index) && !isScrollingUp && viewportBottom >= postContainerMiddle; 114 115 if (shouldLoadNextPost) { 116 loadNextPost($post); 117 } 118 }); 119 } 120 121 function changeCurrentPost($post) { 122 $currentPost = $post; 123 124 prevPostData = currentPostData; 125 126 currentPostData = $currentPost.data('postData'); 127 128 if (prevPostData && currentPostData && prevPostData.id !== currentPostData.id) { 129 updatePageUrl(); 130 updatePageMetaData(); 131 updateAdriverDefaults(); 132 updateSiteZone(); 133 updateCity(); 134 updateIsCommercialPage(); 135 updateRubricTags(); 136 updatePageViewCounters(); 137 // Ð ÑÐ°Ð¼ÐºÐ°Ñ Ð·Ð°Ð´Ð°Ñи SOB-77: Ñак как Ñ Ð½Ð°Ñ Ð½ÐµÑ Ð±Ð°Ð½Ð½ÐµÑов в лонгÑÐ¸Ð´Ð°Ñ , Ñо Ð¼Ñ Ð¿ÐµÑезагÑÑжаем ÑÑеÑÑики баннеÑов оÑделÑно 138 if (currentPostData.isLongread) { 139 updateBannerCounters(); 140 } else { 141 updateBanners(); 142 } 143 updateInstagramWidgets(); 144 sendYmOnloadArticleEvent(currentPostData.id); 145 } 146 } 147 148 function hasNextPostLoaded(postIndex) { 149 return nextPostOffset > postIndex; 150 } 151 152 function loadNextPost($post) { 153 if (!hasMorePosts || nextPostDataRequest) { 154 return; 155 } 156 157 var nextPostId = loadMorePostIds[nextPostOffset] ? loadMorePostIds[nextPostOffset] : null; 158 159 if (!nextPostId) { 160 hasMorePosts = false;
161 162 return; 163 } 164 165 nextPostDataRequest = $.ajax({ 166 url: $post.data('nextPostFetchUrl'), 167 method: 'GET', 168 data: { 169 id: nextPostId, 170 }, 171 success: function (data) { 172 if (!data) { 173 hasMorePosts = false; 174 175 return; 176 } 177 178 var siteBody = document.querySelector('.b-site__body'); 179 180 utils.insertHtml(data.template, siteBody); 181 182 nextPostOffset++; 183 184 if (!ymPreloadArticleId) { 185 ymReachGoal('preload_article', { 186 article_id: String(nextPostId), 187 }); 188 ymPreloadArticleId = nextPostId; 189 } 190 }, 191 error: function () { 192 hasMorePosts = false; 193 }, 194 complete: function () { 195 nextPostDataRequest = null; 196 }, 197 }); 198 } 199 200 function updatePageUrl() { 201 if (!(currentPostData && currentPostData.url)) { 202 return; 203 } 204 205 window.history.replaceState({}, '', currentPostData.url); 206 } 207 208 function updatePageMetaData() { 209 if (!(currentPostData && currentPostData.metaData)) { 210 return; 211 } 212 213 var metaData = currentPostData.metaData; 214 215 if (metaData.title) { 216 document.title = metaData.title; 217 } 218 219 if (metaData.ogTitle) { 220 $('head').find('meta[property="og:title"]').attr('content', metaData.ogTitle); 221 } 222 223 if (metaData.url) { 224 $('head').find('meta[property="og:url"]').attr('content', metaData.url); 225 226 // A workaround for IOS 15.2+: IOS browsers use canonical URL for sharing via the native share buttons 227 $('head').find('link[rel="canonical"]').attr('href', metaData.url); 228 } 229 230 if (metaData.image) { 231 $('head').find('meta[property="og:image"]').attr('content', metaData.image); 232 } 233 234 if (metaData.ogDescription) { 235 $('head').find('meta[property="og:description"]').attr('content', metaData.ogDescription); 236 } 237 238 if (metaData.description) { 239 $('head').find('meta[name="description"]').attr('content', metaData.description); 240 } 241 242 if (metaData.keywords) { 243 $('head').find('meta[name="keywords"]').attr('content', metaData.keywords); 244 } 245 246 if (metaData.canonical) { 247 $('head').find('link[rel="canonical"]').attr('href', metaData.canonical); 248 } 249 } 250 251 function updateInstagramWidgets() { 252 if ($currentPost.find('.instagram-media').length === 0) { 253 return; 254 } 255 256 if (window.instgrm && window.instgrm.Embeds && typeof window.instgrm.Embeds.process === 'function') { 257 window.instgrm.Embeds.process(); 258 } 259 } 260 261 function ymReachGoal(targetName, goalParams) { 262 if (typeof window.ym === 'function') { 263 var cityAlias = utils.getCityFromCookie() || utils.getCityFromUrl() || 'spb'; 264 var targetNamePostfix = '_' + cityAlias; 265 if (cityAlias === 'spb') { 266 targetNamePostfix = ''; 267 } 268 window.ym(19015538, 'reachGoal', targetName + targetNamePostfix, goalParams || {}); 269 //$.notify('REACH GOAL: ' + targetName + targetNamePostfix); 270 } 271 } 272 273 function sendYmOnloadArticleEvent(postId) { 274 if (ymPreloadArticleId === postId) { 275 // article_id mirrors preload_article: the goal reaches Metrika before 276 // the async hit of the new URL, so URL-based goal attribution points to 277 // the source post â the param carries the actually loaded post id. 278 ymReachGoal('onload_article', { 279 article_id: String(postId), 280 }); 281 } 282 } 283 284 function updatePageViewCounters() { 285 if (!(currentPostData && currentPostData.url)) { 286 return; 287 } 288 289 var url = new URL(currentPostData.url, window.location.origin); 290 url.searchParams.set('scroll', 'true'); 291 292 CountersManager.hitCounters({ 293 url: url.href, 294 trackTags: ['pageViews'], 295 }); 296 } 297 298 function updateBannerCounters() { 299 CountersManager.hitCounters({ 300 trackTags: ['bannerViews'], 301 }); 302 } 303 304 function updateBanners($post) { 305 var container = ($post || $currentPost).closest('.b-site-body').get(0); 306 307 BannersManager.reloadBanners({ rootContainer: container }); 308 } 309 310 function updateAdriverDefaults() { 311 if (!currentPostData || !currentPostData.adriverParams) { 312 return; 313 } 314 315 utils.setAdriverDefaults(currentPostData.adriverParams); 316 } 317 318 function updateSiteZone() { 319 if (!currentPostData || !currentPostData.siteZone) { 320 return; 321 } 322 323 utils.setSiteZone(currentPostData.siteZone); 324 } 325 326 function updateCity() { 327 var city = currentPostData && currentPostData.city ? currentPostData.city : null; 328 window.sobaka = window.sobaka || {}; 329 window.sobaka.city = city; 330 } 331 332 function updateIsCommercialPage() { 333 var value = currentPostData && currentPostData.isCommercialPage ? currentPostData.isCommercialPage : false;
334 window.sobaka = window.sobaka || {}; 335 window.sobaka.isCommercialPage = value; 336 } 337 338 function updateRubricTags() { 339 var tags = currentPostData && Array.isArray(currentPostData.rubricTags) ? currentPostData.rubricTags : []; 340 window.sobaka = window.sobaka || {}; 341 window.sobaka.rubricTags = tags; 342 } 343 }); 344})(window.jQuery, window.siteUtils, window.BannersManager, window.CountersManager);
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.