PageSourceSearch

https://mirthailand.com/assets/js/common.js?v=20261002-1

js mirthailand.com collected 2026-10-08 11:48:06 UTC 38,884 bytes, 926 lines download raw bytes

1/* MIR THAILAND common.js — audited and fixed 2026-09-14 */
2(function () {
3  "use strict";
4
5  function defaultRussianUrl(value) {
6    try {
7      var url = new URL(value, window.location.href);
8      var language = (url.searchParams.get("lang") || "").toLowerCase();
9
10      if (url.origin !== window.location.origin || language !== "ru") {
11        return null;
12      }
13
14      url.searchParams.delete("lang");
15      return url;
16    } catch (error) {
17      return null;
18    }
19  }
20
21  function normalizedUrlValue(originalValue, url) {
22    if (/^[a-z][a-z0-9+.-]*:/i.test(originalValue) || originalValue.indexOf("//") === 0) {
23      return url.origin + url.pathname + url.search + url.hash;
24    }
25
26    return url.pathname + url.search + url.hash;
27  }
28
29  function normalizeCurrentDefaultLanguageUrl() {
30    if (window.__mirDefaultLanguageRedirecting) {
31      return true;
32    }
33
34    var url = defaultRussianUrl(window.location.href);
35
36    if (!url) {
37      return false;
38    }
39
40    document.documentElement.setAttribute("lang", "ru");
41
42    try {
43      window.localStorage.setItem("mirLang", "ru");
44    } catch (error) {
45      void error;
46    }
47
48    var cleanLocation = url.pathname + url.search + url.hash;
49    var currentLocation = window.location.pathname + window.location.search + window.location.hash;
50
51    if (cleanLocation !== currentLocation) {
52      window.__mirDefaultLanguageRedirecting = true;
53      window.location.replace(cleanLocation);
54      return true;
55    }
56
57    return false;
58  }
59
60  function normalizeDefaultLanguageUrls(root) {
61    var selector = 'a[href], link[rel="canonical"][href], link[rel="alternate"][href], meta[property="og:url"][content]';
62    var elements = [];
63
64    if (root && root.nodeType !== 1 && root.nodeType !== 9) {
65      return;
66    }
67
68    if (root && root.nodeType === 1 && root.matches && root.matches(selector)) {
69      elements.push(root);
70    }
71
72    var scope = root || document;
73    scope.querySelectorAll(selector).forEach(function (element) {
74      elements.push(element);
75    });
76
77    elements.forEach(function (element) {
78      var attribute = element.tagName === "META" ? "content" : "href";
79      var originalValue = element.getAttribute(attribute) || "";
80      var url = defaultRussianUrl(originalValue);
81
82      if (!url) {
83        return;
84      }
85
86      var cleanValue = normalizedUrlValue(originalValue, url);
87      if (cleanValue !== originalValue) {
88        element.setAttribute(attribute, cleanValue);
89      }
90    });
91  }
92
93  function improveCookieAccessibility() {
94    var cookieClose = document.getElementById("cookiePolicyHide");
95
96    if (cookieClose && !cookieClose.getAttribute("aria-label")) {
97      cookieClose.setAttribute("aria-label", "Закрыть уведомление о cookies");
98    }
99  }
100
101  function pageImageLabel(image) {
102    var galleryImage = document.querySelector('.mt-gallery-item img[alt]:not([alt=""])');
103    var heading = document.querySelector("h1, .mt-article-title");
104
105    if (image.classList.contains("mt-plan-image")) {
106      var planTitle = document.getElementById("mt-plan-title");
107      if (planTitle && planTitle.textContent.trim()) {
108        return planTitle.textContent.trim();
109      }
110    }
111
112    if (galleryImage) {
113      return galleryImage.getAttribute("alt").trim();
114    }
115
116    if (heading && heading.textContent.trim()) {
117      return heading.textContent.trim();
118    }
119
120    return "MIR THAILAND";
121  }
122
123  function improveSingleImage(image) {
124    if (!image || image.tagName !== "IMG") {
125      return;
126    }
127
128    var src = image.getAttribute("src") || "";
129
130    if (image.matches("img.captcha-question") || /^\/secure\//i.test(src)) {
131      if (!image.getAttribute("alt")) {
132        image.setAttribute("alt", "Security code CAPTCHA");
133      }
134      return;
135    }
136
137    if (/\/\.s\/img\/wd\/7\/sample\.gif(?:$|[?#])/i.test(src)) {
138      image.setAttribute("alt", "");
139      image.setAttribute("aria-hidden", "true");
140      image.setAttribute("role", "presentation");
141      return;
142    }
143
144    if (image.matches(".leaflet-tile")) {
145      image.setAttribute("alt", "");
146      image.setAttribute("aria-hidden", "true");
147      image.setAttribute("role", "presentation");
148      return;
149    }
150
151    if (
152      image.matches(".mt-lightbox-image, .mt-plan-image") &&
153      !image.getAttribute("alt")
154    ) {
155      image.setAttribute("alt", pageImageLabel(image));
156      return;
157    }
158
159    if (!image.hasAttribute("alt") && image.getAttribute("title")) {
160      image.setAttribute("alt", image.getAttribute("title").trim());
161    }
162  }
163
164  function improveImageAccessibility(root) {
165    if (root && root.nodeType !== 1 && root.nodeType !== 9) {
166      return;
167    }
168
169    var scope = root || document;
170
171    if (root && root.nodeType === 1) {
172      improveSingleImage(root);
173    }
174
175    if (!scope.querySelectorAll) {
176      return;
177    }
178
179    scope.querySelectorAll("img").forEach(improveSingleImage);
180  }
181
182  // 2026-10-01: all news categories and articles use Mariam's WhatsApp.
183  function isNewsPage() {
184    return !!document.querySelector('.mt-article-title, .mt-news-main');
185  }
186
187  function normalizeNewsContacts(root) {
188    if (!isNewsPage() || !root || (root.nodeType !== 1 && root.nodeType !== 9)) return;
189    var links = [];
190    if (root.matches && root.matches('a[href]')) links.push(root);
191    root.querySelectorAll('a[href]').forEach(function (a) { links.push(a); });
192    links.forEach(function (a) {
193      if (a.matches('.js-share-whatsapp, [data-share], [data-mir-share]')) return;
194      var url;
195      try { url = new URL(a.getAttribute('href'), location.href); } catch (e) { return; }
196      var host = url.hostname.toLowerCase();
197      var isShort = host === 'wa.me' && /^\/(?:\d+|undefined|null)\/?$/.test(url.pathname);
198      var isSend = /^(?:api|web|www)\.whatsapp\.com$/.test(host) && url.pathname === '/send' && url.searchParams.has('phone');
199      if (!isShort && !isSend) return;
200      if (isShort) url.pathname = '/37495040785';
201      else url.searchParams.set('phone', '37495040785');
202      if (a.href !== url.href) a.href = url.href;
203      if (a.getAttribute('data-wa-number') !== '37495040785') a.setAttribute('data-wa-number', '37495040785');
204      var walker = document.createTreeWalker(a, NodeFilter.SHOW_TEXT);
205      var node;
206      while ((node = walker.nextNode())) {
207        var text = node.nodeValue.replace(/\+?66[\s()-]*64[\s()-]*062[\s()-]*00[\s()-]*56|\+?66[\s()-]*83[\s()-]*528[\s()-]*47[\s()-]*09/g, '+374 95 040 785');
208        if (text !== node.nodeValue) node.nodeValue = text;
209      }
210      ['aria-label', 'title'].forEach(function (attr) {
211        var value = a.getAttribute(attr);
212        if (!value) return;
213        var updated = value.replace(/\+?66[\s()-]*64[\s()-]*062[\s()-]*00[\s()-]*56|\+?66[\s()-]*83[\s()-]*528[\s()-]*47[\s()-]*09/g, '+374 95 040 785');
214        if (updated !== value) a.setAttribute(attr, updated);
215      });
216    });
217    // Keep one direct WhatsApp contact in each footer; channel links are untouched.
218    document.querySelectorAll('footer, .mt-footer').forEach(function (footer) {
219      var found = false;
220      footer.querySelectorAll('a[href="https://wa.me/37495040785"]').forEach(function (a) {
221        a.hidden = found;
222        if (!found && a.textContent !== 'WhatsApp: +374 95 040 785') a.textContent = 'WhatsApp: +374 95 040 785';
223        found = true;
224      });
225    });
226  }
227
228  function normalizeNewsContactSchema() {
229    if (!isNewsPage()) return;
230    document.querySelectorAll('script[type="application/ld+json"]').forEach(function (script) {
231      var data;
232      try { data = JSON.parse(script.textContent); } catch (e) { return; }
233      function visit(value) {
234        if (!value || typeof value !== 'object') return;
235        if (value['@type'] === 'ContactPoint' && /^https:\/\/wa\.me\/\d+/.test(value.url || '')) {
236          value.url = 'https://wa.me/37495040785';
237          value.telephone = '+37495040785';
238          value.contactType = 'customer service';
239        }
240        Object.keys(value).forEach(function (key) { visit(value[key]); });
241        if (Array.isArray(value.contactPoint)) {
242          value.contactPoint = value.contactPoint.filter(function (point, index, all) {
243            return all.findIndex(function (other) { return JSON.stringify(other) === JSON.stringify(point); }) === index;
244          });
245        }
246      }
247      visit(data);
248      var updated = JSON.stringify(data);
249      if (updated !== script.textContent) script.textContent = updated;
250    });
251  }
252
253  function watchSystemImages() {
254    if (!window.MutationObserver || !document.documentElement || window.__mirMarkupObserver) {
255      return;
256    }
257
258    var observer = new MutationObserver(function (mutations) {
259      mutations.forEach(function (mutation) {
260        if (mutation.type === "attributes") {
261          improveImageAccessibility(mutation.target);
262          normalizeDefaultLanguageUrls(mutation.target);
263          normalizeNewsContacts(mutation.target);
264          return;
265        }
266
267        mutation.addedNodes.forEach(function (node) {
268          improveImageAccessibility(node);
269          normalizeDefaultLanguageUrls(node);
270          normalizeNewsContacts(node);
271        });
272      });
273    });
274
275    observer.observe(document.documentElement, {
276      childList: true,
277      subtree: true,
278      attributes: true,
279      attributeFilter: ["href", "src", "content"]
280    });
281
282    window.__mirMarkupObserver = observer;
283  }
284
285  function localizeCookieNotice() {
286    var message = document.querySelector("#cookiePolicy .bottom-info-block-content");
287    var agree = document.getElementById("cookiePolicyAgree");
288
289    if (!message || !agree) {
290      return;
291    }
292
293    var language = (document.documentElement.lang || "ru").toLowerCase().split("-")[0];
294    var copy = {
295      ru: {
296        before: "Мы используем cookies, чтобы сайт работал корректно. Продолжая пользоваться сайтом, вы соглашаетесь с ",
297        link: "политикой cookies",
298        after: ".",
299        agree: "Принять"
300      },
301      en: {
302        before: "We use cookies so the website works correctly. By continuing to use the website, you agree to the ",
303        link: "Cookie Policy",
304        after: ".",
305        agree: "Accept"
306      },
307      th: {
308        before: "เราใช้คุกกี้เพื่อให้เว็บไซต์ทำงานได้อย่างถูกต้อง การใช้งานเว็บไซต์ต่อหมายถึงคุณยอมรับ ",
309        link: "นโยบายคุกกี้",
310        after: "",
311        agree: "ยอมรับ"
312      }
313    };
314    var selected = copy[language] || copy.ru;
315    var policyLink = message.querySelector("a") || document.createElement("a");
316
317    policyLink.href = "/index/cookiepolicy";
318    policyLink.target = "_blank";
319    policyLink.rel = "noopener noreferrer";
320    policyLink.textContent = selected.link;
321    message.textContent = selected.before;
322    message.appendChild(policyLink);
323    message.appendChild(document.createTextNode(selected.after));
324    agree.textContent = selected.agree;
325  }
326
327  function removeInactivePlanViewer() {
328  var planViewer = document.getElementById("mt-plan-viewer");
329
330  if (!planViewer) {
331    return;
332  }
333
334  var planElements = document.querySelectorAll(
335    ".mir-palm__plan, .js-plan-album"
336  );
337
338  var hasExternalPlanContent = Array.prototype.some.call(
339    planElements,
340    function (element) {
341      return !planViewer.contains(element);
342    }
343  );
344
345  if (!hasExternalPlanContent) {
346    planViewer.remove();
347  }
348}
349
350  function watchLanguageControls() {
351    if (window.__mirLanguageControlsBound) {
352      return;
353    }
354
355    window.__mirLanguageControlsBound = true;
356    document.addEventListener("click", function (event) {
357      var control = event.target && event.target.closest
358        ? event.target.closest("[data-lang]")
359        : null;
360
361      if (!control) {
362        return;
363      }
364
365      window.setTimeout(function () {
366        normalizeCurrentDefaultLanguageUrl();
367        normalizeDefaultLanguageUrls(document);
368        localizeCookieNotice();
369      }, 75);
370    });
371  }
372
373  function applySafetyFixes() {
374    normalizeCurrentDefaultLanguageUrl();
375    normalizeDefaultLanguageUrls(document);
376    normalizeNewsContacts(document);
377    normalizeNewsContactSchema();
378    improveCookieAccessibility();
379    improveImageAccessibility(document);
380    watchSystemImages();
381    watchLanguageControls();
382    localizeCookieNotice();
383    removeInactivePlanViewer();
384  }
385
386  normalizeCurrentDefaultLanguageUrl();
387  normalizeDefaultLanguageUrls(document);
388
389  if (document.readyState === "loading") {
390    document.addEventListener("DOMContentLoaded", applySafetyFixes);
391  } else {
392    applySafetyFixes();
393  }
394
395  window.setTimeout(applySafetyFixes, 800);
396  window.setTimeout(applySafetyFixes, 2500);
397})();
398
399/* MIR THAILAND — GA4 analytics, audited 2026-09-14 v4 */
400(function () {
401  "use strict";
402
403  if (window.__mirAnalyticsBound) return;
404  window.__mirAnalyticsBound = true;
405
406  var MEASUREMENT_ID = "G-8EWLDNMSKB";
407
408  /*
409   * Analytics labels only — never send phone numbers or email addresses to GA4.
410   * Thai property contacts: +66 64 062 0056 = Edgar, +66 83 528 4709 = Ilya.
411   * Service WhatsApp: +374 95 040 785.
412   */
413  var CONTACT_LABELS = {
414    "66640620056": "edgar_whatsapp",
415    "66835284709": "ilya_whatsapp",
416    "37495040785": "services_whatsapp"
417  };
418
419  function initGoogleAnalytics() {
420    window.dataLayer = window.dataLayer || [];
421    window.gtag = window.gtag || function () {
422      window.dataLayer.push(arguments);
423    };
424
425    if (!window.__mirGa4Configured) {
426      window.__mirGa4Configured = true;
427      window.gtag("js", new Date());
428      window.gtag("config", MEASUREMENT_ID);
429    }
430
431    if (!document.querySelector('script[src*="googletagmanager.com/gtag/js?i
431d=' + MEASUREMENT_ID + '"]')) {
432      var script = document.createElement("script");
433      script.async = true;
434      script.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(MEASUREMENT_ID);
435      (document.head || document.documentElement).appendChild(script);
436    }
437  }
438
439  function sendEvent(name, params) {
440    if (typeof window.gtag !== "function") return;
441    window.gtag("event", name, params || {});
442  }
443
444  function pagePath() {
445    return window.location.pathname + window.location.search;
446  }
447
448  function pageLanguage() {
449    return (document.documentElement.getAttribute("lang") || "ru").toLowerCase().split("-")[0];
450  }
451
452  function safeUrl(value) {
453    try {
454      return new URL(value, window.location.href);
455    } catch (error) {
456      return null;
457    }
458  }
459
460  function hostMatches(hostname, domain) {
461    var host = (hostname || "").toLowerCase();
462    return host === domain || host.endsWith("." + domain);
463  }
464
465  function digitsOnly(value) {
466    return String(value || "").replace(/\D/g, "");
467  }
468
469  function whatsappNumber(target, url) {
470    var dataNumber = target && target.getAttribute
471      ? digitsOnly(target.getAttribute("data-wa-number"))
472      : "";
473
474    if (dataNumber) return dataNumber;
475    if (!url) return "";
476
477    var host = (url.hostname || "").toLowerCase();
478    var pathParts;
479    var phone;
480
481    if (hostMatches(host, "wa.me")) {
482      pathParts = url.pathname.split("/").filter(Boolean);
483      return digitsOnly(pathParts[0] || "");
484    }
485
486    if (hostMatches(host, "whatsapp.com")) {
487      phone = url.searchParams.get("phone") || "";
488      return digitsOnly(phone);
489    }
490
491    return "";
492  }
493
494  function phoneNumber(target) {
495    if (!target || !target.getAttribute) return "";
496    return digitsOnly(target.getAttribute("href") || "");
497  }
498
499  function contactTargetLabel(channel, target, url) {
500    var number;
501    var path = url ? (url.pathname || "").toLowerCase() : "";
502
503    if (channel === "whatsapp" || channel === "phone") {
504      number = channel === "whatsapp" ? whatsappNumber(target, url) : phoneNumber(target);
505      return CONTACT_LABELS[number] || "other_contact";
506    }
507
508    if (channel === "email") return "business_email";
509
510    if (channel === "telegram") {
511      if (path.indexOf("/+") === 0) return "telegram_mirthailand";
512      return "telegram_other";
513    }
514
515    if (channel === "facebook") return "facebook_mirthailand";
516    if (channel === "instagram") return "instagram_mirthailand";
517    if (channel === "max") return "max_mirthailand";
518    if (channel === "whatsapp_channel") return "whatsapp_channel_mirthailand";
519
520    return "other";
521  }
522
523  function cleanEnquiryId(value) {
524    var candidate = String(value || "").trim().toUpperCase();
525    if (!candidate) return "";
526    if (!/^[A-Z0-9_-]{3,100}$/.test(candidate)) return "";
527    return candidate;
528  }
529
530  function idFromText(value) {
531    var text = String(value || "").toUpperCase();
532    var match = text.match(/\b(?:SALE|RENT|VILLA|CONDO|PROPERTY|MANAGEMENT|VISA|LEGAL|CONSTRUCTION|SERVICES|MIR)-[A-Z0-9_-]+\b/);
533    return match ? cleanEnquiryId(match[0]) : "";
534  }
535
536  function enquiryId(target, url) {
537    var value = "";
538    var holder;
539    var message;
540    var meta;
541    var pageHolders;
542    var index;
543
544    if (target && target.getAttribute) {
545      value = cleanEnquiryId(
546        target.getAttribute("data-enquiry-id") ||
547        target.getAttribute("data-property-id") ||
548        target.getAttribute("data-reference") ||
549        ""
550      );
551      if (value) return value;
552
553      if (target.closest) {
554        holder = target.closest("[data-enquiry-id], [data-property-id], [data-reference]");
555        if (holder) {
556          value = cleanEnquiryId(
557            holder.getAttribute("data-enquiry-id") ||
558            holder.getAttribute("data-property-id") ||
559            holder.getAttribute("data-reference") ||
560            ""
561          );
562          if (value) return value;
563        }
564      }
565    }
566
567    if (url && url.searchParams) {
568      message = url.searchParams.get("text") || "";
569      value = idFromText(message);
570      if (value) return value;
571    }
572
573    meta = document.querySelector('meta[name="mir:enquiry-id"], meta[name="property-id"]');
574    if (meta) {
575      value = cleanEnquiryId(meta.getAttribute("content"));
576      if (value) return value;
577    }
578
579    /*
580     * Only explicitly page-level identifiers are safe fallbacks. Never take the
581     * first card identifier from a catalogue or the homepage: that would attach
582     * unrelated form and social clicks to the first property shown on the page.
583     */
584    pageHolders = [
585      document.documentElement,
586      document.body,
587      document.querySelector("main")
588    ];
589
590    for (index = 0; index < pageHolders.length; index += 1) {
591      holder = pageHolders[index];
592      if (!holder || !holder.getAttribute) continue;
593
594      value = cleanEnquiryId(
595        holder.getAttribute("data-enquiry-id") ||
596        holder.getAttribute("data-property-id") ||
597        holder.getAttribute("data-reference") ||
598        ""
599      );
600      if (value) return value;
601    }
602
603    return "";
604  }
605
606  function contactRole(channel, targetLabel, enquiry, target) {
607    var explicit = target && target.getAttribute
608      ? String(target.getAttribute("data-contact-role") || "").toLowerCase()
609      : "";
610    var path = window.location.pathname.toLowerCase();
611    var allowed = ["sale", "rent", "property", "services", "general"];
612
613    if (allowed.indexOf(explicit) !== -1) return explicit;
614    if (targetLabel === "services_whatsapp") return "services";
615
616    if (/^RENT[-_]/.test(enquiry)) return "rent";
617    if (/^SALE[-_]/.test(enquiry)) return "sale";
618    if (/^(?:VISA|LEGAL|CONSTRUCTION|MANAGEMENT|SERVICES)[-_]/.test(enquiry)) return "services";
619
620    if (path.indexOf("for-rent") !== -1 || /(?:^|\/)rent(?:-|\/|$)/.test(path)) return "rent";
621    if (path.indexOf("for-sale") !== -1 || /(?:^|\/)sale(?:-|\/|$)/.test(path)) return "sale";
622
623    if (targetLabel === "edgar_whatsapp" || targetLabel === "ilya_whatsapp") return "property";
624    if (channel === "email") return "general";
625
626    return "general";
627  }
628
629  function formContactRole(context, enquiry, target) {
630    var value = String(context || "").toLowerCase();
631
632    if (
633      /продать|сдать объект|разместить объект|sell|list(?:ing)? property|submit property|ขายหรือปล่อยเช่า/.test(value)
634    ) {
635      return "property";
636    }
637
638    if (/аренд|\brent\b|เช่า/.test(value)) return "rent";
639    if (/купить|покуп|\bbuy\b|purchase|\bsale\b|ซื้อ/.test(value)) return "sale";
640
641    if (
642      /обслуж|управлен|ремонт|строит|виз|юрид|бизнес|service|management|maintenance|construction|renovation|visa|legal|business|บริการ|ดูแล|ก่อสร้าง|วีซ่า|กฎหมาย|ธุรกิจ/.test(value)
643    ) {
644      return "services";
645    }
646
647    return contactRole("form", "", enquiry, target);
648  }
649
650  function contactEventParams(channel, target, url) {
651    var targetLabel = contactTargetLabel(channel, target, url);
652    var enquiry = enquiryId(target, url);
653    var params = {
654      page_path: pagePath(),
655      page_language: pageLanguage(),
656      contact_channel: channel,
657      contact_target: targetLabel,
658      contact_role: contactRole(channel, targetLabel, enquiry, target),
659      transport_type: "beacon"
660    };
661
662    if (enquiry) {
663      params.enquiry_id = enquiry;
664      if (/^(?:SALE|RENT|VILLA|CONDO)[-_]/.test(enquiry)) {
665        params.property_id = enquiry;
666      }
667    }
668
669    return params;
670  }
671
672  function formAnalyticsContext(target) {
673    var enquiry = enquiryId(target, null);
674    var context = target && target.getAttribute
675      ? String(target.getAttribute("data-context") || "general_enquiry").trim()
676      : "general_enquiry";
677    var params = {
678      page_path: pagePath(),
679      page_language: pageLanguage(),
680      form_context: context || "general_enquiry",
681      form_name: "MIR THAILAND enquiry",
682      contact_role: formContactRole(context, enquiry, target),
683      transport_type: "beacon"
684    };
685
686    if (enquiry) {
687      params.enquiry_id = enquiry;
688      if (/^(?:SALE|RENT|VILLA|CONDO)[-_]/.test(enquiry)) {
689        params.property_id = enquiry;
690      }
691    }
692
693    return params;
694  }
695
696  function rememberedFormContext() {
697    var saved = window.__mirPendingFormAnalytics;
698    var params = {
699      page_path: pagePath(),
700      page_language: pageLanguage(),
701      form_name: "MIR THAILAND enquiry",
702      transport_type: "beacon"
703    };
704
705    if (!saved || typeof saved !== "object") return params;
706
707    ["form_context", "contact_role", "enquiry_id", "property_id"].forEach(function (key) {
708      if (saved[key]) params[key] = saved[key];
709    });
710
711    return params;
712  }
713
714  function fileNameFromUrl(href) {
715    try {
716      var url = new URL(href, window.location.href);
717      return decodeURIComponent(url.pathname.split("/").pop() || "document.pdf");
718    } catch (error) {
719      return "document.pdf";
720    }
721  }
722
723  function trackClicks(event) {
724    var target = event.target && event.target.closest ? event.target.closest("a,button") : null;
725    if (!target) return;
726
727    if (
728      target.matches(".open-form, .js-open-form, .mobile-request") ||
729      target.getAttribute("aria-controls") === "requestModal" ||
730      target.getAttribute("aria-controls") === "mt-request-modal"
731    ) {
732      var openFormParams = formAnalyticsContext(target);
733      window.__mirPendingFormAnalytics = openFormParams;
734      sendEvent("open_form", openFormParams);
735    }
736
737    if (target.tagName !== "A") return;
738
739    var rawHref = target.getAttribute("href") || target.href || "";
740    var hrefLower = rawHref.toLowerCase();
741    var url = safeUrl(rawHref);
742    var host = url ? (url.hostname || "").toLowerCase() : "";
743    var path = url ? (url.pathname || "").toLowerCase() : "";
744
745    var isWhatsAppChannel = hostMatches(host, "whatsapp.com") && path.indexOf("/channel/") === 0;
746    var isWhatsAppDirect =
747      hostMatches(host, "wa.me") ||
748      (hostMatches(host, "whatsapp.com") && !isWhatsAppChannel && (path.indexOf("/send") === 0 || url.searchParams.has("phone"))) ||
749      (!!target.getAttribute("data-wa-number") && !isWhatsAppChannel);
750    var isTelegram = hostMatches(host, "t.me") || hostMatches(host, "telegram.me");
751    var isFacebook = hostMatches(host, "facebook.com") || hostMatches(host, "fb.com");
752    var isInstagram = hostMatches(host, "instagram.com");
753    var isMax = hostMatches(host, "max.ru");
754    var isShareLink = target.matches(
755      ".js-share-whatsapp, .js-share-telegram, [data-share], [data-mir-share]"
756    );
757
758    if (isShareLink && (isWhatsAppDirect || isTelegram)) {
759      sendEvent("share", {
760        method: isWhatsAppDirect ? "whatsapp" : "telegram",
761        content_type: "page",
762        page_path: pagePath(),
763        page_language: pageLanguage(),
764        transport_type: "beacon"
765      });
766      return;
767    }
768
769    if (isWhatsAppChannel) {
770      sendEvent("click_whatsapp_channel", contactEventParams("whatsapp_channel", target, url));
771      return;
772    }
773
774    if (isWhatsAppDirect) {
775      sendEvent("click_whatsapp", contactEventParams("whatsapp", target, url));
776      return;
777    }
778
779    if (isTelegram) {
780      sendEvent("click_telegram", contactEventParams("telegram", target, url));
781      return;
782    }
783
784    if (isFacebook) {
785      sendEvent("click_facebook", contactEventParams("facebook", target, url));
786      return;
787    }
788
789    if (isInstagram) {
790      sendEvent("click_instagram", contactEventParams("instagram", target, url));
791      return;
792    }
793
794    if (isMax) {
795      sendEvent("click_max", contactEventParams("max", target, url));
796      return;
797    }
798
799    if (hrefLower.indexOf("tel:") === 0) {
800      sendEvent("click_phone", contactEventParams("phone", target, url));
801      return;
802    }
803
804    if (hrefLower.indexOf("mailto:") === 0) {
805      sendEvent("click_email", contactEventParams("email", target, url));
806      return;
807    }
808
809    if (/\.pdf(?:$|[?#])/i.test(rawHref)) {
810      sendEvent("download_pdf", {
811        page_path: pagePath(),
812        page_language: pageLanguage(),
813        transport_type: "beacon",
814        file_name: fileNameFromUrl(rawHref)
815      });
816    }
817  }
818
819  function findFormWrapper(form) {
820    if (!form || !form.closest) return null;
821    return form.closest(".ucoz-mail-form, .mt-form-box, .mt-mail-form");
822  }
823
824  function trackFormSubmit(event) {
825    var form = event.target;
826    if (!form || form.tagName !== "FORM") return;
827
828    var wrapper = findFormWrapper(form);
829    if (!wrapper) return;
830
831    wrapper.removeAttribute("data-mir-form-success");
832    wrapper.setAttribute("data-mir-form-pending", "1");
833    sendEvent("form_submit_attempt", rememberedFormContext());
834  }
835
836  function isSuccessText(text) {
837    var value = (text || "").toLowerCase().replace(/\s+/g, " ");
838    return [
839      "успешно отправ",
840      "сообщение отправлено",
841      "заявка отправлена",
842      "спасибо за обращение",
843      "successfully sent",
844      "message has been sent",
845      "message sent",
846      "thank you for your message",
847      "ส่งข้อความสำเร็จ",
848      "ส่งเรียบร้อย"
849    ].some(function (phrase) {
850      return value.indexOf(phrase) !== -1;
851    });
852  }
853
854  function watchSuccessfulForms() {
855    if (!window.MutationObserver || !document.body || window.__mirFormSuccessObserver) return;
856
857    var observer = new MutationObserver(function (mutations) {
858      mutations.forEach(function (mutation) {
859        var node = mutation.target && mutation.target.nodeType === 1
860          ? mutation.target
861          : mutation.target && mutation.target.parentElement;
862        if (!node || !node.closest) return;
863
864        var wrapper = node.closest(".ucoz-mail-form, .mt-form-box, .mt-mail-form");
865        var successSource = wrapper;
866        if (!wrapper) {
867          var candidates = [];
868          var ownPopup = node.closest('.myWinCont');
869          if (ownPopup) candidates.push(ownPopup);
870          Array.prototype.forEach.call(mutation.addedNodes || [], function (added) {
871            if (added.nodeType !== 1) return;
872            if (added.matches('.myWinCont')) candidates.push(added);
873            Array.prototype.push.apply(candidates, added.querySelectorAll('.myWinCont'));
874          });
875          successSource = candidates.find(function (popup) { return isSuccessText(popup.textContent); });
876          if (successSource) wrapper = document.querySelector('[data-mir-form-pending="1"]');
877        }
878        if (!wrapper || wrapper.getAttribute("data-mir-form-pending") !== "1") return;
879        if (wrapper.getAttribute("data-mir-form-success") === "1") return;
880
881        if (successSource && isSuccessText(successSource.textContent)) {
882          wrapper.setAttribute("data-mir-form-success", "1");
883          wrapper.removeAttribute("data-mir-form-pending");
884          var successParams = rememberedFormContext();
885          sendEvent("form_submit_success", successParams);
886
887          var leadParams = {};
888          Object.keys(successParams).forEach(function (key) {
889            leadParams[key] = successParams[key];
890          });
891          leadParams.lead_source = "website_form";
892          leadParams.lead_status = "confirmed_submission";
893          sendEvent("generate_lead", leadParams);
894
895          window.__mirPendingFormAnalytics = null;
896        }
897      });
898    });
899
900    observer.observe(document.body, {
901      childList: true,
902      subtree: true,
903      characterData: true
904    });
905    window.__mirFormSuccessObserver = observer;
906  }
907
908  initGoogleAnalytics();
909
910  if (document.readyState === "loading") {
911    document.addEventListener("DOMContentLoaded", function () {
912      watchSuccessfulForms();
913    });
914  } else {
915    watchSuccessfulForms();
916  }
917
918  document.addEventListener("click", trackClicks, true);
919  document.addEventListener("submit", trackFormSubmit, true);
920})();
921
922/* Enquiry context and dialog keyboard support — 2026-09-23. */
923(function(){'use strict';var lastTrigger=null;var prefix='';function applyContext(button){var modal=document.getElementById('mt-request-modal');if(!modal)return;if(!modal.classList.contains('is-open')){modal.classList.add('is-open');document.body.classList.remove('menu-open');document.body.style.overflow='hidden';var menu=document.querySelector('.mt-menu-button');var panel=document.querySelector('.mt-mobile-menu');if(menu)menu.setAttribute('aria-expanded','false');if(panel)panel.setAttribute('aria-hidden','true');}var form=modal.querySelector('form');if(!form)return;var message=form.querySelector('[name="f2"]');if(message&&message.tagName==='INPUT'&&message.type==='text'){var multiline=
923document.createElement('textarea');Array.prototype.forEach.call(message.attributes,function(attr){if(attr.name!=='type'&&attr.name!=='value')multiline.setAttribute(attr.name,attr.value);});multiline.value=message.value;multiline.rows=4;multiline.style.width='100%';multiline.style.minHeight='96px';multiline.style.setProperty('color','#17312c','important');multiline.style.setProperty('background','#ffffff','important');multiline.style.setProperty('border','1px solid #d4ddd8','important');message.replaceWith(multiline);message=multiline;}var select=form.querySelector('select[name="f3"]');var context=button.getAttribute('data-context')||document.title;var card=button.closest('.mt-news-card');var link=card&&card.querySelector('.mt-news-card-title a');var page=link?link.href:location.href;var role=button.getAttribute('data-contact-role')||'general';if(message){var userText=message.value;if(prefix&&userText.indexOf(prefix)===0)userText=userText.slice(prefix.length);prefix=context+' | '+page+' — ';message.value=prefix+userText;}if(select){var serviceContext=context+' '+(button.getAttribute('data-enquiry-id')||'');var choices={sale:'Купить недвижимость',rent:'Арендовать недвижимость',services:/яхт|yacht/i.test(serviceContext)?'Другое':/виз|visa/i.test(serviceContext)?'Визы':/бизнес|прав|legal/i.test(serviceContext)?'Бизнес и право':/строит|ремонт|construction/i.test(serviceContext)?'Ремонт и строительство':'Обслуживание'};var choice=choices[role];if(choice)Array.prototype.some.call(select.options,function(option){if(option.value===choice){select.value=choice;return true;}return false;});}lastTrigger=button;var input=form.querySelector('input:not([type="hidden"]):not([type="checkbox"]):not([type="submit"]),textarea');if(input)input.focus();}document.addEventListener('click',function(event){var button=event.target.closest&&event.target.closest('.js-open-form');if(button)applyContext(button);if(event.target.closest&&event.target.closest('.mt-modal-close')&&lastTrigger)lastTrigger.focus();});document.addEventListener('keydown',function(event){var modal=document.getElementById('mt-request-modal');if(!modal||!modal.classList.contains('is-open'))return;if(event.key==='Tab'){var nodes=Array.prototype.filter.call(modal.querySelectorAll('a[href],button,input,select,textarea,[tabindex="0"]'),function(e){return !e.disabled&&e.type!=='hidden'&&e.getClientRects().length;});if(!nodes.length)return;var first=nodes[0],last=nodes[nodes.length-1];if(event.shiftKey&&document.activeElement===first){event.preventDefault();last.focus();}else if(!event.shiftKey&&document.activeElement===last){event.preventDefault();first.focus();}}},true);document.addEventListener('keydown',function(event){if(event.key==='Escape'&&lastTrigger)lastTrigger.focus();});})();
924
925/* Full multilingual editorial content and category labels. */
926(function(){'use strict';function init(){var lang=(location.search.match(/[?&]lang=(ru|en|th)(?:&|$)/i)||[])[1]||'ru';var labels={'/thailand-property-management':{ru:'Обслуживание недвижимости',en:'Property management',th:'บริการดูแลอสังหาริมทรัพย์'},'/phuket-construction-renovation':{ru:'Ремонт и строительство',en:'Renovation and construction',th:'รีโนเวตและก่อสร้าง'},'/thailand-visas-relocation':{ru:'Визы и переезд',en:'Visas and relocation',th:'วีซ่าและการย้ายถิ่นฐาน'},'/thailand-business-legal-services':{ru:'Бизнес и право',en:'Business and legal',th:'ธุรกิจและกฎหมาย'},'/phuket-thailand-news':{ru:'Новости Таиланда и Пхукета',en:'Phuket and Thailand news',th:'ข่าวภูเก็ตและประเทศไทย'}};document.querySelectorAll('.mt-category-label a,.mt-news-card-category').forEach(function(a){var label=labels[new URL(a.href,location.origin).pathname.replace(/\/$/,'')];if(label)a.textContent=label[lang];});var ui={ru:{services:'услуги',name:'Имя',phone:'Телефон / WhatsApp / Telegram',service:'Услуга',message:'Сообщение',consent:'Согласие',code:'Код с картинки'},en:{services:'services',name:'Name',phone:'Phone / WhatsApp / Telegram',service:'Service',message:'Message',consent:'Consent',code:'Security code'},th:{services:'บริการ',name:'ชื่อ',phone:'โทรศัพท์ / WhatsApp / Telegram',service:'บริการ',message:'ข้อความ',consent:'ความยินยอม',code:'รหัสยืนยัน'}}[lang];document.querySelectorAll('footer a[href="https://wa.me/37495040785"],.mt-footer a[href="https://wa.me/37495040785"]').forEach(function(a){a.textContent='WhatsApp: +374 95 040 785 · '+ui.services;});document.querySelectorAll('#mt-request-modal tr').forEach(function(row){var cell=row.querySelector('td');if(!cell)return;var text=cell.textContent;var key=/Имя|Name|ชื่อ/.test(text)?'name':/Телефон|Phone|โทรศัพท์/.test(text)?'phone':/Услуга|Service|บริการ/.test(text)?'service':/Сообщение|Message|ข้อความ/.test(text)?'message':/Согласие|Consent|ความยินยอม/.test(text)?'consent':/Security code|Код с картинки|รหัสยืนยัน/.test(text)?'code':null;if(key)cell.textContent=ui[key]+(text.indexOf('*')>=0?' *:':':');});document.querySelectorAll('#mt-request-modal a[href^="/index/policy"]').forEach(function(a){a.href='/index/policy'+(lang==='ru'?'':'?lang='+lang);});var blocks=document.querySelectorAll('.mt-multilang-article .mt-editorial-language');if(!blocks.length)return;var selected;blocks.forEach(function(b){b.hidden=b.lang!==lang;if(!b.hidden)selected=b;});if(!selected)return;var title=(selected.getAttribute('data-title')||'').trim(),description=(selected.getAttribute('data-description')||'').trim();var h1=document.querySelector('h1');var fallbackTitle=(h1&&h1.textContent?h1.textContent.trim():'')||(document.title||'').replace(/\s*\|\s*MIR THAILAND\s*$/i,'').trim();
926var descriptionMetaExisting=document.querySelector('meta[name="description"]');var fallbackDescription=descriptionMetaExisting?(descriptionMetaExisting.getAttribute('content')||'').trim():'';if(!title)title=fallbackTitle;if(!description)description=fallbackDescription;if(h1&&title)h1.textContent=title;if(title)document.title=title+' | MIR THAILAND';document.querySelectorAll('.js-share-whatsapp').forEach(function(a){a.href='https://wa.me/?text='+encodeURIComponent(title+' '+location.href);});document.querySelectorAll('.js-share-telegram').forEach(function(a){a.href='https://t.me/share/url?url='+encodeURIComponent(location.href)+'&text='+encodeURIComponent(title);});document.querySelectorAll('meta[name="description"],meta[property="og:description"],meta[name="twitter:description"]').forEach(function(e){e.content=description;});document.querySelectorAll('meta[property="og:title"],meta[name="twitter:title"]').forEach(function(e){e.content=title;});document.querySelectorAll('.js-open-form').forEach(function(e){e.setAttribute('data-context',title);var role=e.getAttribute('data-contact-role');if(role!=='sale'&&role!=='rent'){var article=selected.closest('.mt-multilang-article');e.setAttribute('data-contact-role',article.getAttribute('data-contact-role')||'services');}});document.querySelectorAll('[data-contact-role="services"][href*="wa.me/"]').forEach(function(a){a.href='https://wa.me/37495040785?text='+encodeURIComponent(title+'\n'+location.href);});document.querySelectorAll('script[type="application/ld+json"]').forEach(function(s){try{var data=JSON.parse(s.textContent);var graph=data['@graph']||[data];graph.forEach(function(x){if(['WebPage','Article','NewsArticle'].includes(x['@type'])){x.name=title;if(x.headline)x.headline=title;x.description=description;x.inLanguage=lang;}});s.textContent=JSON.stringify(data);}catch(e){}});}if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();})();

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.