PageSourceSearch

https://osm2cdr.com/js/onboarding.js?v=20260803onbdemand

js osm2cdr.com collected 2026-09-25 20:40:48 UTC 4,870 bytes, 133 lines download raw bytes

1/**
2 * OSM2CDR Onboarding — 3-step instruction modal, ON DEMAND ONLY.
3 * Opened by the "?" help trigger (onboarding_tour.js) or window.showOnboarding().
4 *
5 * Учебник НИКОГДА не показывается сам: человек, пришедший из поиска, должен
6 * увидеть карту, а не полноэкранную инструкцию поверх неё (разбор воронки
7 * 03.08: главная → конструктор 8%). Автопоказ по localStorage снят сознательно
8 * — не возвращать.
9 */
10(function() {
11  'use strict';
12
13  // Три шага онбординга. Тексты — ключи locales/*.json (onb_step*), берутся
14  // через t() в момент рендера, чтобы отражать текущий язык интерфейса.
15  var steps = [
16    { icon: '1', titleKey: 'onb_step1_title', descKey: 'onb_step1_text' },
17    { icon: '2', titleKey: 'onb_step2_title', descKey: 'onb_step2_text' },
18    { icon: '3', titleKey: 'onb_step3_title', descKey: 'onb_step3_text' }
19  ];
20
21  // i18n lookup через глобальный I18N; fallback = ключ (I18N.t сам держит
22  // цепочку lang→en→ru→key).
23  function t(key) {
24    if (typeof I18N !== 'undefined' && typeof I18N.t === 'function') {
25      return I18N.t(key);
26    }
27    return key;
28  }
29
30  function createModal() {
31    var overlay = document.createElement('div');
32    overlay.id = 'onboardingOverlay';
33    overlay.className = 'onboarding-overlay';
34
35    var modal = document.createElement('div');
36    modal.className = 'onboarding-modal';
37
38    // Title
39    var title = document.createElement('h2');
40    title.className = 'onboarding-title';
41    title.textContent = t('onb_modal_title');
42    modal.appendChild(title);
43
44    // Steps
45    var stepsContainer = document.createElement('div');
46    stepsContainer.className = 'onboarding-steps';
47
48    steps.forEach(function(step) {
49      var stepEl = document.createElement('div');
50      stepEl.className = 'onboarding-step';
51
52      var iconEl = document.createElement('div');
53      iconEl.className = 'onboarding-step-icon';
54      iconEl.textContent = step.icon;
55
56      var textEl = document.createElement('div');
57      textEl.className = 'onboarding-step-text';
58
59      var h3 = document.createElement('h3');
60      h3.textContent = t(step.titleKey);
61
62      var p = document.createElement('p');
63      p.textContent = t(step.descKey);
64
65      textEl.appendChild(h3);
66      textEl.appendChild(p);
67      stepEl.appendChild(iconEl);
68      stepEl.appendChild(textEl);
69      stepsContainer.appendChild(stepEl);
70    });
71
72    modal.appendChild(stepsContainer);
73
74    // Close button
75    var closeBtn = document.createElement('button');
76    closeBtn.className = 'onboarding-close-btn';
77    closeBtn.textContent = t('onb_cta_start');
78    closeBtn.addEventListener('click', function() {
79      dismiss(overlay);
80      // «Понятно, начать!» — единственный путь к пошаговому туру: он тоже больше
81      // не запускается сам, только по явному действию человека.
82      startTourIfAvailable();
83    });
84    modal.appendChild(closeBtn);
85
86    // Help link hint
87    var helpLink = document.createElement('div');
88    helpLink.className = 'onboarding-help-link';
89    helpLink.innerHTML = t('onb_help_hint');
90    modal.appendChild(helpLink);
91
92    overlay.appendChild(modal);
93
94    // Close on overlay background click
95    overlay.addEventListener('click', function(e) {
96      if (e.target === overlay) dismiss(overlay);
97    });
98
99    // Close on Escape
100    function onEsc(e) {
101      if (e.key === 'Escape') {
102        dismiss(overlay);
103        document.removeEventListener('keydown', onEsc);
104      }
105    }
106    document.addEventListener('keydown', onEsc);
107
108    return overlay;
109  }
110
111  function dismiss(overlay) {
112    overlay.classList.add('onboarding-fade-out');
113    setTimeout(function() { overlay.remove(); }, 300);
114  }
115
116  // Тур живёт в отдельном файле и может быть не загружен (или отсутствовать на
117  // странице) — отсутствие API не должно ломать закрытие модалки.
118  function startTourIfAvailable() {
119    if (window.OnboardingTour && typeof window.OnboardingTour.start === 'function') {
120      window.OnboardingTour.start();
121    }
122  }
123
124  function show() {
125    var existing = document.getElementById('onboardingOverlay');
126    if (existing) existing.remove();
127    document.body.appendChild(createModal());
128  }
129
130  // Точка входа одна — «?» (onboarding_tour.js вешает её на этот же метод).
131  // Автопоказа нет: см. шапку файла.
132  window.showOnboarding = show;
133})();

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.