1// ÐоÑÑ Ð¼ÐµÐ¶Ð´Ñ Dart-кодом ÑайÑа и ЯндекÑ.ÐеÑÑикой. 2// 3// ÐÐЧÐÐ ÐТÐÐÐЬÐЫРСÐÐ ÐÐТÐÐ. Ð¤Ð°Ð¹Ð»Ñ `lib/client/**` ÑобиÑаÑÑÑÑ Ð¸ в бÑаÑзеÑнÑй 4// JS, и в ÑеÑвеÑнÑÑ AOT-ÑбоÑкÑ, поÑÑÐ¾Ð¼Ñ Ð¾Ð±ÑÑвлÑÑÑ Ð² Ð½Ð¸Ñ Ð²Ð½ÐµÑние JS-ÑÑнкÑии 5// (`@JS ... external`) нелÑзÑ. Ð¢Ð¾Ñ Ð¶Ðµ пÑиÑм Ñже иÑполÑзÑеÑÑÑ ÐºÐ°ÑÑой магазинов: 6// Dart ÑлÑÑ DOM-ÑобÑÑие, ÑкÑÐ¸Ð¿Ñ ÐµÐ³Ð¾ ÑлÑÑаеÑ. 7// 8// ÐЧÐÐ ÐÐЬ ÐÐЯÐÐТÐÐЬÐÐ. СÑÑÑÑик иниÑиализиÑÑеÑÑÑ Ð°ÑÐ¸Ð½Ñ Ñонно, а ÑобÑÑÐ¸Ñ 9// наÑинаÑÑÑÑ Ñ Ð¿ÐµÑвого кадÑа ÑÑÑаниÑÑ. ÐÑÑмой вÑзов `ym(...)` на Ñ Ð¾Ð»Ð¾Ð´Ð½Ð¾Ð¹ 10// загÑÑзке Ð¿Ð°Ð´Ð°ÐµÑ â в мобилÑном вебе ÑÑо ловилоÑÑ ÐºÐ°Ðº `NoSuchMethodError` 11// (Ñм. `lib/di/yandex_web_metrika/js_ecom_web.dart`). Ðопим и Ñливаем. 12// 13// ÐÐÐСЬ ÐÐ ÐÐÐÐÐÐÐÐТСЯ СÐРСЧÐТЧÐÐ (`boot`). ÐÐ»Ð°Ð´ÐµÐ»ÐµÑ ÐеÑÑики в бÑаÑзеÑе 14// один â ÑÑÐ¾Ñ Ñайл: он и гÑÑÐ·Ð¸Ñ `tag.js`, и зовÑÑ `init`, и деÑÐ¶Ð¸Ñ Ð¾ÑеÑедÑ.
15// РазнеÑи ÑÑо по двÑм меÑÑам â и поÑÑдок «init ÑанÑÑе flush» пÑиÑлоÑÑ Ð±Ñ 16// поддеÑживаÑÑ Ð²ÑÑÑнÑÑ Ð¸Ð· ÑазмеÑки. 17// 18// ÐÐÐЪÐÐ ÐТÐÐÐÐÐ â как в мобилÑном вебе (`web/index.html`, Ñам ÑÑо 19// `flutter-first-frame` + 1000 мÑ). `tag.js` Ñ Ð²ÐµÐ±Ð²Ð¸Ð·Ð¾Ñом ÑÑÐ½ÐµÑ Ð·Ð°Ð¼ÐµÑнÑй 20// ÑÑоÑонний JS, а LCP ÑайÑа вÑлизан до 0.45 Ñ; в кÑиÑиÑеÑкий пÑÑÑ ÐµÐ³Ð¾ пÑÑкаÑÑ 21// нелÑзÑ. ТеÑÑÑÑ ÑобÑÑÐ¸Ñ Ð¾ÑÑÑоÑка не заÑÑавлÑÐµÑ â Ð¸Ñ Ð´ÐµÑÐ¶Ð¸Ñ Ð¾ÑеÑÐµÐ´Ñ Ð²ÑÑе, 22// а `hit` на ÑÑÑаниÑÑ Ð²Ñ Ð¾Ð´Ð° ÐеÑÑика заÑÑиÑÑÐ²Ð°ÐµÑ Ñама пÑи `init`. 23(function () { 24 var queue = []; 25 var counterId = 0; 26 var booted = false; 27 var scheduled = false; 28 var bootTimer = 0; 29 var disabled = document.cookie.split(';').some(function (part) { 30 return part.trim() === 'tvoe_cookie_consent=rejected'; 31 }); 32 33 // ÐодÑÑм ÑÑÑÑÑика: ÑÐ½Ð¸Ð¿Ð¿ÐµÑ Ð¯Ð½Ð´ÐµÐºÑа + `init`. ÐовÑÑÑÑ Ñовно один Ñаз. 34 // 35 // ÐаÑамеÑÑÑ `init` â Ñе же, ÑÑо в мобилÑном вебе (`web/index.html`): 36 // ÑазойдиÑÑ Ð¾Ð½Ð¸, и оÑÑÑÑÑ ÑайÑа Ñ Ð¿Ñиложением пеÑеÑÑанÑÑ ÑÑ Ð¾Ð´Ð¸ÑÑÑÑ. 37 // `referrer`/`url` ÑÑда ÐРпеÑедаÑÑÑÑ: `init` Ð¸Ñ Ð½Ðµ ÑиÑÐ°ÐµÑ (ÑÑо аÑгÑменÑÑ 38 // меÑода `hit`), а пÑоÑмоÑÑÑ ÑÐ°Ð¹Ñ ÑлÑÑ Ñам â `AnalyticsRouteObserver` 39 // (`lib/client/analytics/route_observer.dart`) Ñ ÑеÑÑнÑми url и referer. 40 function boot() { 41 if (disabled || booted || counterId <= 0) return; 42 booted = true; 43 (function (m, e, t, r, i, k, a) { 44 m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments) }; 45 m[i].l = 1 * new Date(); 46 for (var j = 0; j < document.scripts.length; j++) { if (document.scripts[j].src === r) { return; } } 47 k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a); 48 })(window, document, 'script', 'https://mc.yandex.ru/metrika/tag.js?id=' + counterId, 'ym'); 49 50 // `dataLayer` â ÐÐ `init`: ÐеÑÑика вÑÑиÑÑÐ²Ð°ÐµÑ Ñже накопленнÑй маÑÑив в 51 // Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¸Ð½Ð¸ÑиализаÑии, и ÑоваÑнÑе ÑобÑÑиÑ, оÑпÑавленнÑе до подÑÑма 52 // ÑÑÑÑÑика, не ÑеÑÑÑÑÑÑ. 53 window.dataLayer = window.dataLayer || []; 54 window.ym(counterId, 'init', { 55 ssr: true, 56 webvisor: true, 57 clickmap: true, 58 ecommerce: 'dataLayer', 59 accurateTrackBounce: true, 60 trackLinks: true 61 }); 62 63 // `ClientID` â Mindbox: он Ñ ÑÐ°Ð½Ð¸Ñ ÐµÐ³Ð¾ каÑÑом-полем клиенÑа 64 // (`website.EditYandexClientId`). ÐÑдаÑм DOM-ÑобÑÑием, ÑÑÐ¾Ð±Ñ ÑÑÐ¾Ñ Ñайл 65 // оÑÑалÑÑ ÐµÐ´Ð¸Ð½ÑÑвеннÑм владелÑÑем `window.ym`. 66 try { 67 window.ym(counterId, 'getClientID', function (clientId) { 68 if (!clientId) return; 69 document.dispatchEvent(new CustomEvent('tv-metrika-client-id', { detail: String(clientId) })); 70 }); 71 } catch (e) { 72 // ÐеÑÑика могла не поднÑÑÑÑÑ â Mindbox пÑоживÑÑ Ð±ÐµÐ· ÑÑого полÑ. 73 } 74 75 // Ð¡Ð½Ð¸Ð¿Ð¿ÐµÑ Ð²ÑÑе ÑоздаÑÑ `window.ym` ÑÐ¸Ð½Ñ Ñонно (заглÑÑка Ñ Ð¾ÑеÑедÑÑ `.a`), 76 // поÑÑÐ¾Ð¼Ñ Ð¾ÑеÑÐµÐ´Ñ Ð¼Ð¾Ð¶Ð½Ð¾ ÑливаÑÑ ÑÑÐ°Ð·Ñ â `tag.js` Ð´Ð¾ÐµÐ´ÐµÑ Ð¸ ÑазбеÑÑÑ ÐµÑ Ñам. 77 flush(); 78 } 79 80 // ÐланиÑовÑик подÑÑма. `load`, а не `DOMContentLoaded`: к моменÑÑ `load` 81 // каÑÑинки пеÑвого ÑкÑана Ñже наÑиÑованÑ, и ÑÑоÑонний JS ни Ñ Ñем не 82 // конкÑÑиÑÑеÑ. СекÑнда ÑвеÑÑ Ñ â ÑÐ¾Ñ Ð¶Ðµ зазоÑ, ÑÑо в мобилÑном вебе. 83 function schedule() { 84 if (disabled) return; 85 // ÐÐ¾Ð¼ÐµÑ Ð¿ÑÐ¸ÐµÐ·Ð¶Ð°ÐµÑ Ð´Ð²Ð°Ð¶Ð´Ñ (инлайн в ÑазмеÑке и ÑÑение `__tvCounterId` ÑÑим 86 // Ñайлом) â планиÑÑем Ñовно один Ñаз. Сам `boot` Ñоже заÑиÑÑн (`booted`), 87 // но копиÑÑ Ð¾ÑменÑннÑе ÑаймеÑÑ Ð½ÐµÐ·Ð°Ñем. 88 if (scheduled) return; 89 scheduled = true; 90 if (document.readyState === 'complete') { 91 bootTimer = setTimeout(boot, 1000); 92 return; 93 } 94 window.addEventListener('load', function () { 95 if (!disabled) bootTimer = setTimeout(boot, 1000); 96 }, { once: true }); 97 } 98 99 // ÐоднÑÑÑ ÑÑÑÑÑик ÐÐÐÐÐÐÐÐÐÐ, не дожидаÑÑÑ `load` + 1 Ñ. 100 // 101 // ÐÐЧÐÐ. ÐбÑÑÐ½Ð°Ñ Ð¾ÑÑÑоÑка (Ñм. `schedule`) пÑавилÑна Ð´Ð»Ñ Ð²Ð¸ÑÑÐ¸Ð½Ñ Ð¸ каÑалога: 102 // аналиÑика не должна конкÑÑиÑоваÑÑ Ñ Ð¿ÐµÑвÑм ÑкÑаном. Ðо на оÑоÑмлении 103 // заказа она ÑÑановиÑÑÑ ÑаÑÑÑÑ ÑÑенаÑиÑ: Ñеловек Ð½Ð°Ð¶Ð¸Ð¼Ð°ÐµÑ Â«ÐÑоÑмиÑÑ», и 104 // ÑÑÑаниÑа ÑÑÑ Ð¶Ðµ ÑÑ Ð¾Ð´Ð¸Ñ. ÐÑли к ÑÑÐ¾Ð¼Ñ Ð¼Ð¾Ð¼ÐµÐ½ÑÑ `tag.js` еÑÑ Ð½Ðµ поднÑлÑÑ, 105 // ÑÐµÐ»Ñ `purchase` оÑÑаÑÑÑÑ Ð² оÑеÑеди, подÑвеÑÐ¶Ð´ÐµÐ½Ð¸Ñ Ð½Ðµ бÑÐ´ÐµÑ Ð½Ð¸ÐºÐ¾Ð³Ð´Ð°, а 106 // ÑоваÑÐ½Ð°Ñ ÑаÑÑÑ ÑÐµÐ´ÐµÑ Ð¸Ð· `dataLayer` вмеÑÑе Ñ Ð´Ð¾Ðº
106ÑменÑом. 107 // 108 // СимпÑом заказÑика (04.09.2026): на одном ÐÐ `purchase` в дебаггеÑе не 109 // поÑвилÑÑ Ð²Ð¾Ð²Ñе. Ðа пÑоде замеÑено: `window.ym` не ÑÑÑеÑÑвÑÐµÑ Ð¸ ÑеÑез 110 // 7 ÑекÑнд поÑле наÑала загÑÑзки ÑÑÑаниÑÑ ÑоваÑа â `load` Ñам наÑÑÑÐ¿Ð°ÐµÑ 111 // поздно. 112 // 113 // ÐдемпоÑенÑна: `boot` заÑиÑÑн Ñлагом `booted`, повÑоÑнÑе вÑÐ·Ð¾Ð²Ñ Ð±ÐµÑплаÑнÑ. 114 window.tvAnalyticsBoot = function () { 115 if (disabled) return; 116 scheduled = true; 117 boot(); 118 }; 119 120 window.tvAnalyticsReject = function () { 121 disabled = true; 122 queue.length = 0; 123 if (bootTimer) clearTimeout(bootTimer); 124 try { 125 if (counterReady()) window.ym(counterId, 'destruct'); 126 } catch (e) { 127 // СÑÑÑÑик Ñже мог иÑÑезнÑÑÑ Ñам; оÑказ вÑÑ Ñавно ÑÑиÑаеÑÑÑ Ð¿ÑименÑннÑм. 128 } 129 }; 130 131 // То же Ñамое ÑобÑÑием â им полÑзÑеÑÑÑ Dart (`analytics.dart# 132 // bootAnalyticsCounter`), ÑÑÐ¾Ð±Ñ Ð½Ðµ ÑÑогаÑÑ `window` напÑÑмÑÑ. 133 document.addEventListener('tv-analytics-boot', function () { 134 window.tvAnalyticsBoot(); 135 }); 136 137 function counterReady() { 138 return counterId > 0 && typeof window.ym === 'function'; 139 } 140 141 function send(item) { 142 if (item.kind === 'ecommerce') { 143 window.dataLayer = window.dataLayer || []; 144 window.dataLayer.push({ ecommerce: item.ecommerce }); 145 return; 146 } 147 if (item.kind === 'hit') { 148 window.ym(counterId, 'hit', item.url, { referer: item.referer }); 149 return; 150 } 151 // `ackId` â ÑолÑко Ñ Ñели `purchase` оÑоÑÐ¼Ð»ÐµÐ½Ð¸Ñ Ð·Ð°ÐºÐ°Ð·Ð° 152 // (`yandex_metrika_sink.dart#reportPurchaseAwaitingAck`): ÑÐ°Ð¹Ñ ÑÐ²Ð¾Ð´Ð¸Ñ 153 // бÑаÑÐ·ÐµÑ Ñо ÑÑÑаниÑÑ Ð¶ÑÑÑким пеÑÐµÑ Ð¾Ð´Ð¾Ð¼ ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле оÑпÑавки, и без 154 // подÑвеÑÐ¶Ð´ÐµÐ½Ð¸Ñ `reachGoal`'а колбÑком запÑÐ¾Ñ Ðº `mc.yandex.ru` ÑиÑкÑÐµÑ 155 // обоÑваÑÑÑÑ Ð½Ð° ÑеÑедине, не дождавÑиÑÑ ÑеÑи. ÐолбÑк â ÑÑаÑнÑй ÑеÑвÑÑÑÑй 156 // аÑгÑÐ¼ÐµÐ½Ñ `reachGoal`, задокÑменÑиÑованнÑй Ñамой ÐеÑÑикой; оÑÑалÑнÑе 157 // Ñели его не пÑоÑÑÑ Ð¸ поÑÑлаÑÑÑÑ ÐºÐ°Ðº ÑанÑÑе, без колбÑка. 158 if (item.ackId) { 159 window.ym(counterId, 'reachGoal', item.name, item.params, function () { 160 document.dispatchEvent(new CustomEvent('tv-analytics-ack', { detail: item.ackId })); 161 }); 162 return; 163 } 164 window.ym(counterId, 'reachGoal', item.name, item.params); 165 } 166 167 function flush() { 168 if (!counterReady()) return; 169 while (queue.length) { 170 try { 171 send(queue.shift()); 172 } catch (e) { 173 // Ðдно Ñломанное ÑобÑÑие не Ð¸Ð¼ÐµÐµÑ Ð¿Ñава запеÑеÑÑ Ð¾ÑеÑедÑ. 174 } 175 } 176 } 177 178 // ÐÑиÑм номеÑа ÑÑÑÑÑика из ÑазмеÑки. ÐдемпоÑенÑна: ÑазмеÑка зовÑÑ ÐµÑ 179 // инлайном, а ÑÑÐ¾Ñ Ñайл â Ñам пÑи загÑÑзке (Ñм. низ), и повÑоÑнÑй вÑзов не 180 // должен ни задваиваÑÑ `tag.js`, ни пеÑепланиÑоваÑÑ Ð¿Ð¾Ð´ÑÑм (`booted`). 181 window.tvAnalyticsInit = function (id) { 182 if (disabled) return; 183 if (typeof id !== 'number' || id <= 0) return; 184 counterId = id; 185 // СÑÑÑÑика еÑÑ Ð½ÐµÑ â `flush` здеÑÑ Ð½Ð¸Ñего не ÑÐ´ÐµÐ»Ð°ÐµÑ (`counterReady` 186 // ÑÑебÑÐµÑ Ð¶Ð¸Ð²Ð¾Ð³Ð¾ `window.ym`). ÐÑеÑÐµÐ´Ñ ÑÐµÐ´ÐµÑ Ð¸Ð· `boot`. 187 schedule(); 188 }; 189 190 document.addEventListener('tv-analytics', function (event) { 191 if (disabled) return; 192 var item; 193 try { 194 item = JSON.parse(event.detail); 195 } catch (e) { 196 return; 197 } 198 // Ecommerce не ÑÑебÑÐµÑ Ð³Ð¾ÑовноÑÑи ÑÑÑÑÑика: `dataLayer` â обÑÑнÑй маÑÑив, 199 // ÐеÑÑика вÑÑиÑÑÐ²Ð°ÐµÑ ÐµÐ³Ð¾ пÑи иниÑиализаÑии. 200 if (item.kind === 'ecommerce') { 201 send(item); 202 return; 203 } 204 queue.push(item); 205 flush(); 206 }); 207 208 document.addEventListener('tv-cookie-consent-rejected', function () { 209 window.tvAnalyticsReject(); 210 }); 211 212 // ÐÐ¾Ð¼ÐµÑ Ð¼Ð¾Ð³ пÑÐ¸ÐµÑ Ð°ÑÑ ÑанÑÑе, Ñем загÑÑзилÑÑ ÑÑÐ¾Ñ Ñайл: ÑазмеÑка вÑÑÑавлÑÐµÑ 213 // `window.__tvCounterId` инлайном в `<head>`, а Ñам Ñайл идÑÑ Ñ `defer` и 214 // вÑполнÑеÑÑÑ Ð¿Ð¾Ñле ÑазбоÑа докÑменÑа. ÐÑо, а не инлайновÑй вÑзов, â 215 // ÐСÐÐÐÐÐРпÑÑÑ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð½Ð¾Ð¼ÐµÑа; вÑзов в ÑазмеÑке оÑÑавлен ÑÑÑÐ°Ñ Ð¾Ð²ÐºÐ¾Ð¹. 216 if (!disabled && typeof window.__tvCounterId === 'number') { 217 window.tvAnalyticsInit(window.__tvCounterId); 218 } 219})();
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.