(function () { function pageContext(node) { var root = (node && node.closest && node.closest('[data-page-id]')) || document.body; return { page_id: root.dataset.pageId || '', template_family: root.dataset.templateFamily || '', intent_cluster: root.dataset.intentCluster || '', action_context: (node && node.dataset && (node.dataset.actionContext || node.dataset.widget)) || root.dataset.pageKind || '' }; } function emitMetric(name, node, extra) { var params = Object.assign({}, pageContext(node || document.body), extra || {}); if (typeof window.ym === 'function') { try { window.ym(Number(document.body.dataset.counterId || '0'), 'reachGoal', name, params); } catch (e) { // noop } } } function formatNumber(value) { if (!isFinite(value)) return ''; var rounded = Math.round(value * 10000) / 10000; return String(rounded) .replace(/\.0+$/, '') .replace(/(\.\d*?)0+$/, '$1') .replace(/\.$/, ''); } function setCopyFeedback(button, message) { var feedback = button.parentElement.querySelector('.copy-feedback'); if (!feedback) return; feedback.textContent = message; window.clearTimeout(button._copyTimeout); button._copyTimeout = window.setTimeout(function () { feedback.textContent = ''; }, 1800); } function findInWidgetScope(node, selector) { var layout = node && node.closest ? node.closest('.tool-layout') : null; if (layout) { var insideLayout = layout.querySelector(selector); if (insideLayout) return insideLayout; } return node ? node.querySelector(selector) : null; } async function copyText(text, button) { try { await navigator.clipboard.writeText(text); setCopyFeedback(button, 'Скопировано'); emitMetric('copy_result', button, { copied_value: text }); } catch (e) { var temp = document.createElement('textarea'); temp.value = text; document.body.appendChild(temp); temp.select(); try { document.execCommand('copy'); setCopyFeedback(button, 'Скопировано'); emitMetric('copy_result', button, { copied_value: text }); } catch (err) { setCopyFeedback(button, 'Не удалось скопировать'); } document.body.removeChild(temp); } } document.querySelectorAll('[data-copy-target]').forEach(function (button) { button.addEventListener('click', function () { var selector = button.dataset.copyTarget; var source = button.closest('[data-copy-scope]') || document; var node = source.querySelector(selector); if (!node) return; var text = (button.dataset.copyText || node.textContent || '').trim(); if (!text) return; copyText(text, button); }); }); document.querySelectorAll('[data-related-link], .hub-card, .page-card, .quick-link-card, .home-card').forEach(function (link) { link.addEventListener('click', function () { emitMetric('click_related', link, { target_href: link.getAttribute('href') || '' }); }); }); document.querySelectorAll('[data-widget="ratio-converter"]').forEach(function (node) { var factor = Number(node.dataset.factor || '1'); var mode = node.dataset.mode || 'multiply'; var input = node.querySelector('input'); var button = node.querySelector('button'); var result = findInWidgetScope(node, '[data-role="result"]'); var resultValue = findInWidgetScope(node, '[data-role="result-value"]'); var output = findInWidgetScope(node, '[data-role="output"]'); function render(track) { var value = Number(input.value); if (!isFinite(value) || value <= 0) { var msg = 'Введите значение больше нуля'; if (result) result.textContent = msg; if (resultValue) resultValue.textContent = '—'; if (output) output.value = ''; return; } var out = mode === 'multiply' ? value * factor : mode === 'divide' ? value / factor : factor / value; var text = formatNumber(out); if (result) result.textContent = text; if (resultValue) resultValue.textContent = text; if (output) output.value = text; if (track) { emitMetric('calc_submit', node, { input_value: formatNumber(value), output_value: text }); } } if (button) { button.addEventListener('click', function () { render(true); }); } if (input) { input.addEventListener('input', function () { render(false); }); input.addEventListener('change', function () { render(false); }); input.addEventListener('keydown', function (event) { if (event.key === 'Enter') { event.preventDefault(); render(true); } }); } node.querySelectorAll('[data-preset-value]').forEach(function (chip) { chip.addEventListener('click', function () { input.value = chip.dataset.presetValue; render(true); }); }); render(false); }); document.querySelectorAll('[data-widget="dual-length-converter"]').forEach(function (node) { var inchInput = node.querySelector('[data-role="inch"]'); var mmInput = node.querySelector('[data-role="mm"]'); var fromInch = node.querySelector('[data-action="from-inch"]'); var fromMm = node.querySelector('[data-action="from-mm"]'); var resultValue = findInWidgetScope(node, '[data-role="result-value"]'); var resultLabel = findInWidgetScope(node, '[data-role="result-label"]'); var output = findInWidgetScope(node, '[data-role="output"]'); function sync(source, track) { if (source === 'inch') { var inch = Number(inchInput.value); if (!isFinite(inch) || inch <= 0) { resultValue.textContent = '—'; resultLabel.textContent = 'Введите длину в дюймах'; if (output) output.value = ''; return; } var mm = inch * 25.4; var mmText = formatNumber(mm); mmInput.value = mmText; resultLabel.textContent = 'Результат в миллиметрах'; resultValue.textContent = mmText; if (output) output.value = mmText; if (track) emitMetric('calc_submit', node, { direction: 'inch_to_mm', input_value: formatNumber(inch), output_value: mmText }); } else { var mmRaw = Number(mmInput.value); if (!isFinite(mmRaw) || mmRaw <= 0) { resultValue.textContent = '—'; resultLabel.textContent = 'Введите длину в миллиметрах'; if (output) output.value = ''; return; } var inchOut = mmRaw / 25.4; var inchText = formatNumber(inchOut); inchInput.value = inchText; resultLabel.textContent = 'Результат в дюймах'; resultValue.textContent = inchText; if (output) output.value = inchText; if (track) emitMetric('calc_submit', node, { direction: 'mm_to_inch', input_value: formatNumber(mmRaw), output_value: inchText }); } } if (fromInch) fromInch.addEventListener('click', function () { sync('inch', true); }); if (fromMm) fromMm.addEventListener('click', function () { sync('mm', true); }); if (inchInput) inchInput.addEventListener('change', function () { sync('inch', false); }); if (mmInput) mmInput.addEventListener('change', function () { sync('mm', false); }); node.querySelectorAll('[data-preset-inch]').forEach(function (chip) { chip.addEventListener('click', function () { inchInput.value = chip.dataset.presetInch; sync('inch', true); }); }); sync('inch', false); }); document.querySelectorAll('[data-widget="weight-calculator"]').forEach(function (node) { var d = node.querySelector('[data-role="diameter"]'); var l = node.querySelector('[data-role="length"]'); var button = node.querySelector('button'); var result = findInWidgetScope(node, '[data-role="result"]'); var totalValue = findInWidgetScope(node, '[data-role="total"]'); var perMeter = findInWidgetScope(node, '[data-role="per-meter"]'); var grams = findInWidgetScope(node, '[data-role="grams"]'); var output = findInWidgetScope(node, '[data-role="output"]'); function render(track) { var diameter = Number(d.value); var length = Number(l.value); if (!isFinite(diameter) || !isFinite(length) || diameter <= 0 || length <= 0) { if (result) result.textContent = 'Введите диаметр и длину больше нуля'; if (totalValue) totalValue.textContent = '—'; if (perMeter) perMeter.textContent = '—'; if (grams) grams.textContent = '—'; if (output) output.value = ''; return; } var perMeterMass = Math.PI * Math.pow((diameter / 1000) / 2, 2) * 7850; var totalMass = perMeterMass * length; var totalText = formatNumber(totalMass); var perMeterText = formatNumber(perMeterMass); var gramsText = formatNumber(totalMass * 1000); if (result) result.textContent = totalText + ' кг'; if (totalValue) totalValue.textContent = totalText + ' кг'; if (perMeter) perMeter.textContent = perMeterText + ' кг/м'; if (grams) grams.textContent = gramsText + ' г'; if (output) output.value = totalText; if (track) { emitMetric('calc_submit', node, { diameter_mm: formatNumber(diameter), length_m: formatNumber(length), output_value: totalText }); } } if (button) button.addEventListener('click', function () { render(true); }); if (d) d.addEventListener('input', function () { render(false); }); if (l) l.addEventListener('input', function () { render(false); }); node.querySelectorAll('[data-preset-diameter][data-preset-length]').forEach(function (chip) { chip.addEventListener('click', function () { d.value = chip.dataset.presetDiameter; l.value = chip.dataset.presetLength; render(true); }); }); render(false); }); document.querySelectorAll('[data-widget="selector-map"]').forEach(function (node) { var dataNode = node.querySelector('script[type="application/json"]'); if (!dataNode) return; var data = JSON.parse(dataNode.textContent); var select = node.querySelector('select'); var tbody = node.querySelector('tbody'); var summary = findInWidgetScope(node, '[data-role="selector-summary"]'); var output = findInWidgetScope(node, '[data-role="output"]'); function bindSummaryCopy() { if (!summary) return; summary.querySelectorAll('[data-copy-target]').forEach(function (button) { button.addEventListener('click', function () { var scope = button.closest('[data-copy-scope]'); if (!scope) return; var source = scope.querySelector(button.dataset.copyTarget); if (!source) return; copyText(source.textContent.trim(), button); }); }); } function render(track) { var item = data[select.value]; if (!item) return; tbody.innerHTML = Object.keys(item).map(function (key, index) { var value = item[key]; return '