PageSourceSearch

https://osm2cdr.com/js/mapsshop_banner.js?v=20260731nocta

js osm2cdr.com collected 2026-09-25 20:39:21 UTC 3,967 bytes, 112 lines download raw bytes

1/**
2 * MapsShop entry-point onboarding banner.
3 *
4 * Background (S66-2, follow-up to the 27 May UX-regression briefing)
5 * ------------------------------------------------------------------
6 * MapsShop.ru is the storefront: a customer buys a city map there, gets an
7 * email with a link to osm2cdr.ru, lands here, and does not understand how to
8 * download "their" map ("как скачать / непонятная навигация"). 6 such
9 * complaints in 18-25 May. The existing Open-Beta / Format-Wizard / post-gen
10 * banners do NOT cover this entry-point case.
11 *
12 * This banner is shown ONLY to visitors arriving from MapsShop and gives a
13 * 1-2-3 navigation hint (select area -> pick format -> Create -> file in ~30s,
14 * no signup). Regular visitors never see it.
15 *
16 * Detection (any one signal is enough):
17 *   - ``utm_source=mapsshop`` query param (canonical — MapsShop email links
18 *     can/should carry it; the funnel tracker in map.js already reads UTM).
19 *   - ``document.referrer`` host contains "mapsshop" (best-effort fallback for
20 *     links that lack the UTM tag; referrer can be empty under strict
21 *     referrer-policy, hence the UTM param is the primary signal).
22 *
23 * Dismiss is persisted in localStorage so the hint is shown at most once.
24 *
25 * Progressive enhancement: the banner markup starts hidden (CSS ``hidden``
26 * class) and is only revealed by this script, so visitors with JS disabled —
27 * and every non-MapsShop visitor — never see it. This is the inverse of the
28 * Open-Beta banner (which is shown by default); here the default is hidden.
29 *
30 * Security: all banner text is static, localized via ``data-i18n`` (textContent,
31 * not innerHTML), so no user-controlled value (referrer / UTM) is ever written
32 * into the DOM. Detection only reads those values for boolean matching.
33 */
34(function () {
35  'use strict';
36
37  var STORAGE_KEY = 'mapsshop_banner_dismissed_v1';
38  var MARKER = 'mapsshop';
39
40  /**
41   * @returns {boolean} true if this visit looks like it came from MapsShop.
42   */
43  function cameFromMapsShop() {
44    // Signal 1: explicit utm_source=mapsshop (case-insensitive).
45    try {
46      var params = new URLSearchParams(window.location.search);
47      var src = (params.get('utm_source') || '').toLowerCase();
48      if (src.indexOf(MARKER) !== -1) {
49        return true;
50      }
51    } catch (e) {
52      // URLSearchParams unavailable — fall through to referrer check.
53    }
54
55    // Signal 2: referrer host contains "mapsshop" (best-effort; may be empty
56    // under a strict referrer policy, which is why UTM is the primary signal).
57    try {
58      var ref = (document.referrer || '').toLowerCase();
59      if (ref.indexOf(MARKER) !== -1) {
60        return true;
61      }
62    } catch (e) {
63      // referrer access blocked — ignore.
64    }
65
66    return false;
67  }
68
69  function init() {
70    var banner = document.getElementById('mapsShopBanner');
71    if (!banner) {
72      return;
73    }
74
75    // Show only for MapsShop arrivals — every other visitor keeps the
76    // default-hidden state.
77    if (!cameFromMapsShop()) {
78      return;
79    }
80
81    // Already dismissed in a previous visit — stay hidden.
82    try {
83      if (window.localStorage && localStorage.getItem(STORAGE_KEY) === '1') {
84        return;
85      }
86    } catch (e) {
87      // localStorage unavailable (private mode) — show the banner this view.
88    }
89
90    banner.classList.remove('hidden');
91
92    var dismissBtn = banner.querySelector('.mapsshop-banner-dismiss');
93    if (dismissBtn) {
94      dismissBtn.addEventListener('click', function () {
95        banner.classList.add('hidden');
96        try {
97          if (window.localStorage) {
98            localStorage.setItem(STORAGE_KEY, '1');
99          }
100        } catch (e) {
101          // Storage blocked — hide for this page view only.
102        }
103      });
104    }
105  }
106
107  if (document.readyState === 'loading') {
108    document.addEventListener('DOMContentLoaded', init);
109  } else {
110    init();
111  }
112})();

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.