PageSourceSearch

https://link.prosto585.ru/lk/_content/Zoloto585.Pawnshop.Client.Components/scripts/app.uz8jztxxxc.js

js prosto585.ru collected 2026-10-04 03:58:40 UTC 28,184 bytes, 916 lines download raw bytes

1function focusInput(id, value, moveCaretToEnd = false) {
2    const element = document.getElementById(id);
3    if (!element)
4        return;
5
6    if (value !== null && value !== undefined)
7        element.value = value;
8
9    element.focus();
10
11    if (moveCaretToEnd && typeof element.setSelectionRange === "function") {
12        try {
13            const caretPosition = element.value.length;
14            element.setSelectionRange(caretPosition, caretPosition);
15        } catch {
16            // Некоторые типы input не поддерживают управление выделением.
17        }
18    }
19}
20
21function setInputValueById(id, value) {
22    const element = document.getElementById(id);
23    if (element)
24        element.value = value ?? "";
25}
26
27window.openLinkInNewTab = function (url) {
28    window.open(url, '_blank', 'noopener,noreferrer');
29};
30
31window.copyTextToClipboard = async function (text) {
32    const value = text == null ? "" : String(text);
33    if (!value) return false;
34
35    if (window.isSecureContext &&
36        navigator.clipboard &&
37        typeof navigator.clipboard.writeText === "function") {
38        try {
39            await navigator.clipboard.writeText(value);
40            return true;
41        } catch {
42            // Clipboard API может быть запрещён политикой браузера/WebView.
43            // Ниже остаётся совместимый fallback для обычного текста.
44        }
45    }
46
47    const textArea = document.createElement("textarea");
48    textArea.value = value;
49    textArea.setAttribute("readonly", "");
50    textArea.style.position = "fixed";
51    textArea.style.top = "0";
52    textArea.style.left = "-9999px";
53    textArea.style.opacity = "0";
54    textArea.style.pointerEvents = "none";
55
56    const activeElement = document.activeElement;
57    const selection = document.getSelection ? document.getSelection() : null;
58    const selectedRange = selection && selection.rangeCount > 0
59        ? selection.getRangeAt(0)
60        : null;
61
62    document.body.appendChild(textArea);
63
64    try {
65        try {
66            textArea.focus({ preventScroll: true });
67        } catch {
68            textArea.focus();
69        }
70
71        textArea.select();
72        textArea.setSelectionRange(0, value.length);
73        return document.execCommand("copy");
74    } catch {
75        return false;
76    } finally {
77        textArea.remove();
78
79        if (selectedRange && selection) {
80            selection.removeAllRanges();
81            selection.addRange(selectedRange);
82        }
83
84        if (activeElement instanceof HTMLElement) {
85            try {
86                activeElement.focus({ preventScroll: true });
87            } catch {
88                activeElement.focus();
89            }
90        }
91    }
92};
93
94window.copyPromocodeFromElement = async function (element) {
95    if (!element || !element.dataset) return false;
96
97    const successMessage = document.getElementById(element.dataset.copySuccessId);
98    const failedMessage = document.getElementById(element.dataset.copyFailedId);
99    const version = Number(element.dataset.copyVersion || "0") + 1;
100    element.dataset.copyVersion = String(version);
101
102    const copied = await window.copyTextToClipboard(element.dataset.copyText);
103
104    if (successMessage) successMessage.hidden = !copied;
105    if (failedMessage) failedMessage.hidden = copied;
106
107    setTimeout(function () {
108        if (Number(element.dataset.copyVersion || "0") !== version) return;
109        if (successMessage) successMessage.hidden = true;
110        if (failedMessage) failedMessage.hidden = true;
111    }, 2000);
112
113    return copied;
114};
115
116window.triggerFileDownload = (fileName, url) => {
117    const anchorElement = document.createElement('a');
118    anchorElement.href = url;
119    anchorElement.target = '_blank';
120    anchorElement.download = fileName ?? '';
121    anchorElement.click();
122    anchorElement.remove();
123}
124
125window.scrollElementToTop = function (element) {
126    if (!element) return;
127
128    element.scrollTop = 0;
129    element.scrollLeft = 0;
130};
131
132window.blurActiveElement = function () {
133    var active = document.activeElement;
134    if (active && active instanceof HTMLElement) {
135        active.blur();
136    }
137};
138
139window.saveAsFile = (filename, bytesBase64) => {
140    const anchorElement = document.createElement('a');
141    anchorElement.href = "data:application/octet-stream;base64," + bytesBase64;
142    anchorElement.target = '_blank';
143    anchorElement.download = filename;
144    anchorElement.click();
145    anchorElement.remove();
146}
147
148window.openPdfInNewTab = (bytesBase64, fileName) => {
149    const byteCharacters = atob(bytesBase64);
150    const byteNumbers = new Array(byteCharacters.length);
151    for (let i = 0; i < byteCharacters.length; i++) {
152        byteNumbers[i] = byteCharacters.charCodeAt(i);
153    }
154
155    const blob = new Blob([new Uint8Array(byteNumbers)], { type: "application/pdf" });
156    const blobUrl = URL.createObjectURL(blob);
157
158    const w = window.open(blobUrl, "_blank");
159    if (w && fileName) w.document.title = w;
160    setTimeout(() => URL.revokeObjectURL(blobUrl), 60_000);
161};
162
163window.openPdfLinkInNewTab = (url) => {
164    window.open(url, "_blank");
165};
166
167(function () {
168    var isIos =
169        /iPad|iPhone|iPod/.test(navigator.userAgent) ||
170        (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
171
172    if (!isIos || !window.visualViewport) {
173        return;
174    }
175
176    var activeStepper = null;
177    var keyboardOpen = false;
178    var lastInset = 0;
179    var syncQueued = false;
180
181    function getKeyboardInset() {
182        var viewport = window.visualViewport;
183        var layoutHeight = document.documentElement.clientHeight || window.innerHeight || 0;
184        var inset = layoutHeight - viewport.height - viewport.offsetTop;
185        return Math.max(0, Math.round(inset));
186    }
187
188    function queueSync() {
189        if (syncQueued) return;
190        syncQueued = true;
191
192        requestAnimationFrame(function () {
193            syncQueued = false;
194            syncKeyboardState();
195        });
196    }
197
198    function syncKeyboardState() {
199        lastInset = getKeyboardInset();
200        keyboardOpen = lastInset > 80;
201
202        document.documentElement.classList.toggle("vzo-keyboard-open", keyboardOpen);
203
204        if (activeStepper) {
205            activeStepper.classList.toggle("vzo-keyboard-active", keyboardOpen);
206            activeStepper.style.setProperty("--vzo-keyboard-inset", lastInset + "px");
207        }
208
209        // Не скроллим выбранные карточки/поля принудительно: iOS и так пытается
210        // удержать focused input, а дополнительный scrollBy ломает верх списка в ВЗО.
211        // Видимую область регулирует CSS через --vzo-keyboard-inset.
212    }
213
214    function setActiveStepper(element) {
215        var stepper = element && element.closest
216            ? element.closest(".loan-request-stepper")
217            : null;
218
219        if (activeStepper && activeStepper !== stepper) {
220            activeStepper.classList.remove("vzo-keyboard-active");
221            activeStepper.style.removeProperty("--vzo-keyboard-inset");
222        }
223
224        activeStepper = stepper;
225        queueSync();
226    }
227
228    function findScrollableStepperBody(stepper) {
229        if (!stepper) return null;
230
231        for (var i = 0; i < stepper.children.length; i++) {
232            var wrapper = stepper.children[i];
233            if (!wrapper.classList || !wrapper.classList.contains("screen-body-wrapper")) {
234                continue;
235            }
236
237            for (var j = 0; j < wrapper.children.length; j++) {
238                var child = wrapper.children[j];
239                if (child.classList && child.classList.contains("screen-body")) {
240                    return child;
241                }
242            }
243        }
244
245        return null;
246    }
247
248    function keepElementInside(scroller, element, topGap, bottomGap) {
249        if (!scroller || !element) return;
250
251        var scrollerRect = scroller.getBoundingClientRect();
252        var elementRect = element.getBoundingClientRect();
253        var minTop = scrollerRect.top + topGap;
254        var maxBottom = scrollerRect.bottom - bottomGap;
255
256        if (elementRect.top < minTop) {
257            scroller.scrollBy({
258                top: elementRect.top - minTop,
259                behavior: "smooth"
260            });
261        } else if (elementRect.bottom > maxBottom) {
262            scroller.scrollBy({
263                top: elementRect.bottom - maxBottom,
264                behavior: "smooth"
265            });
266        }
267    }
268
269    function keepLoanRequestFocusVisible() {
270        var active = document.activeElement;
271        var stepper = active && active.closest
272            ? active.closest(".loan-request-stepper")
273            : activeStepper;
274
275        if (!stepper) return;
276
277        var scroller = findScrollableStepperBody(stepper);
278        var bottomGap = Math.max(24, lastInset + 24);
279
280        var selectedPromotion = stepper.querySelector(".loan-request-step2 .loan-offer-card.selected");
281        if (selectedPromotion) {
282            keepElementInside(scroller, selectedPromotion, 8, bottomGap + 128);
283        }
284
285        if (active && stepper.contains(active)) {
286            keepElementInside(scroller, active, 8, bottomGap);
287        }
288    }
289
290    document.addEventListener("focusin", function (event) {
291        setActiveStepper(event.target);
292        setTimeout(queueSync, 250);
293    }, true);
294
295    document.addEventListener("focusout", function () {
296        setTimeout(function () {
297            if (!document.activeElement || !document.activeElement.closest(".loan-request-stepper")) {
298                if (activeStepper) {
299                    activeStepper.classList.remove("vzo-keyboard-active");
300                    activeStepper.style.removeProperty("--vzo-keyboard-inset");
301                }
302                activeStepper = null;
303                keyboardOpen = false;
304                document.documentElement.classList.remove("vzo-keyboard-open");
305            }
306        }, 150);
307    }, true);
308
309    window.visualViewport.addEventListener("resize", queueSync);
310    window.visualViewport.addEventListener("scroll", queueSync);
311})();
312
313var pawnMap = null;
314var pawnMapClusterer = null;
315var pawnMapClickHandler = null;
316var pawnMapGeolocationControl = null;
317var pawnMapGeolocationHandler = null;
318var pawnMapOpenLinkHandler = null;
319var lastYandexMapsOpenAt = 0;
320var lastClickedPlacemark = null;
321var dotnetCallbackObjectRef = null;
322
323var yandexMapsLoadingPromise = null;
324var yandexMapsScriptId = "yandex-maps-api-script";
325var yandexMapsScriptUrl = "https://api-maps.yandex.ru/2.1/?apikey=41b6f152-19d1-4690-b22e-eaf90258113c&lang=ru_RU";
326
327function safeInvokeDotNet(methodName /*, args... */) {
328    var ref = dotnetCallbackObjectRef;
329    if (!ref) return;
330
331    var args = Array.prototype.slice.call(arguments, 1);
332    try {
333        return ref.invokeMethodAsync.apply(ref, [methodName].concat(args));
334    } catch (e) {
335        console.warn("[YandexMaps] DotNet callback failed:", e);
336    }
337}
338
339function getYandexMapsIconUrl() {
340    return new URL(
341        "_content/Zoloto585.Pawnshop.Client.Components/images/geomark.svg",
342        document.baseURI
343    ).toString();
344}
345
346function isYandexMapsUrl(url) {
347    if (!url) return false;
348
349    try {
350        var parsed = new URL(url, document.baseURI);
351        return parsed.protocol === "yandexmaps:" ||
352            parsed.protocol === "yandexnavi:" ||
353            parsed.hostname === "yandex.ru" ||
354            parsed.hostname.endsWith(".yandex.ru") ||
355            parsed.hostname === "yandex.com" ||
356            parsed.hostname.endsWith(".yandex.com");
357    } catch {
358        return false;
359    }
360}
361
362function getYandexMapsView() {
363    if (!pawnMap) {
364        return { lat: null, lon: null, zoom: null };
365    }
366
367    var center = typeof pawnMap.getCenter === "function" ? pawnMap.getCenter() : null;
368    return {
369        lat: Array.isArray(center) && center.length > 1 ? center[0] : null,
370        lon: Array.isArray(center) && center.length > 1 ? center[1] : null,
371        zoom: typeof pawnMap.getZoom === "function" ? pawnMap.getZoom() : null
372    };
373}
374
375function openYandexMapsExternal(url) {
376    var now = Date.now();
377    if (now - lastYandexMapsOpenAt < 700) {
378        return;
379    }
380    lastYandexMapsOpenAt = now;
381
382    var view = getYandexMapsView();
383    safeInvokeDotNet("OnOpenYandexMaps", url || null, view.lat, view.lon, view.zoom);
384}
385
386function findYandexMapsOpenUrl(target, mapElement) {
387    if (!target || !target.closest) {
388        return undefined;
389    }
390
391    var anchor = target.closest("a[href]");
392    if (anchor && mapElement.contains(anchor) && isYandexMapsUrl(anchor.href)) {
393        return anchor.href;
394    }
395
396    // В мобильном WebView штатная кнопка Яндекс.Карт иногда рисуется не как обычная ссылка
397    // или гасит навигацию внутри SDK. Перехватываем именно элементы штатного блока открытия,
398    var openBlock = target.closest(
399        "[class*='map-copyrights-promo']," +
400        "[class*='copyrights-promo']," +
401        "[class*='gotoymaps']," +
402        "[class*='open-in-maps']," +
403        "[class*='map-open-block']"
404    );
405
406    if (openBlock && mapElement.contains(openBlock)) {
407        return null;
408    }
409
410    return undefined;
411}
412
413function attachYandexMapsOpenBridge() {
414    var mapElement = document.getElementById("pawnmap");
415    if (!mapElement) return;
416
417    pawnMapOpenLinkHandler = function (event) {
418        var url = findYandexMapsOpenUrl(event.target, mapElement);
419        if (url === undefined) {
420            return;
421        }
422
423        event.preventDefault();
424        event.stopPropagation();
425        openYandexMapsExternal(url);
426    };
427
428    mapElement.addEventListener("click", pawnMapOpenLinkHandler, true);
429    mapElement.addEventListener("touchend", pawnMapOpenLinkHandler, true);
430}
431
432function ensureYandexMapsLoaded() {
433    if (typeof ymaps !== "undefined") {
434        return Promise.resolve(ymaps);
435    }
436
437    if (yandexMapsLoadingPromise) {
438        return yandexMapsLoadingPromise;
439    }
440
441    yandexMapsLoadingPromise = new Promise(function (resolve, reject) {
442        var script = document.getElementById(yandexMapsScriptId);
443        var createdNow = false;
444
445        if (!script) {
446            script = document.createElement("script");
447            script.id = yandexMapsScriptId;
448            script.src = yandexMapsScriptUrl;
449            script.type = "text/javascript";
450            script.async = true;
451            createdNow = true;
452        }
453
454        function cleanup() {
455            script.removeEventListener("load", onLoad);
456            script.removeEventListener("error", onError);
457        }
458
459        function fail(error) {
460            cleanup();
461            yandexMapsLoadingPromise = null;
462
463            if (createdNow && script.parentNode) {
464                script.parentNode.removeChild(script);
465            }
466
467            reject(error);
468        }
469
470        function onLoad() {
471            cleanup();
472
473            if (typeof ymaps === "undefined") {
474                fail(new Error("Yandex Maps SDK loaded, but ymaps is undefined."));
475                return;
476            }
477
478            try {
479                ymaps.ready(function () {
480                    resolve(ymaps);
481                });
482            } catch (e) {
483                fail(e instanceof Error ? e : new Error("ymaps.ready failed."));
484            }
485        }
486
487        function onError() {
488            fail(new Error("Не удалось загрузить Yandex Maps SDK."));
489        }
490
491        script.addEventListener("load", onLoad);
492        script.addEventListener("error", onError);
493
494        if (typeof ymaps !== "undefined") {
495            onLoad();
496            return;
497        }
498
499        if (createdNow) {
500            document.head.appendChild(script);
501        }
502    });
503
504    return yandexMapsLoadingPromise;
505}
506
507function disposeYandexMaps() {
508    try {
509        if (pawnMapClusterer && pawnMapClickHandler) {
510            pawnMapClusterer.events.remove("click", pawnMapClickHandler);
511        }
512    } catch { }
513
514    try {
515        if (pawnMapGeolocationControl && pawnMapGeolocationHandler) {
516            pawnMapGeolocationControl.events.remove("locationchange", pawnMapGeolocationHandler);
517        }
518    } catch { }
519
520    try {
521        var mapElement = document.getElementById("pawnmap");
522        if (mapElement && pawnMapOpenLinkHandler) {
523            mapElement.removeEventListener("click", pawnMapOpenLinkHandler, true);
524            mapElement.removeEventListener("touchend", pawnMapOpenLinkHandler, true);
525        }
526    } catch { }
527
528    try {
529        if (pawnMap) pawnMap.destroy();
530    } catch { }
531
532    pawnMap = null;
533    pawnMapClusterer = null;
534    pawnMapClickHandler = null;
535    pawnMapGeolocationControl = null;
536    pawnMapGeolocationHandler = null;
537    pawnMapOpenLinkHandler = null;
538    lastYandexMapsOpenAt = 0;
539    lastClickedPlacemark = null;
540    dotnetCallbackObjectRef = null;
541}
542
543function initYandexMaps(pawnshops, center, tryResolveUserLocationOnInit) {
544    var fallbackLocation = [55.76, 37.64];
545    var currentLocation =
546        center && typeof center.lat === "number" && typeof center.lon === "number"
547            ? [center.lat, center.lon]
548            : fallbackLocation;
549
550    if (!Array.isArray(pawnshops)) {
551        pawnshops = [];
552    }
553
554    pawnMap = new ymaps.Map("pawnmap", {
555        center: currentLocation,
556        zoom: 10
557    }, {
558        suppressMapOpenBlock: false
559    });
560
561    try { pawnMap.container.fitToViewport(); } catch { }
562    attachYandexMapsOpenBridge();
563
564    pawnMapClusterer = new ymaps.Clusterer({
565        preset: "islands#redClusterIcons",
566        zoomMargin: 120
567    });
568
569    var iconUrl = getYandexMapsIconUrl();
570
571    pawnshops.forEach(function (pawnshop) {
572        pawnMapClusterer.add(new ymaps.Placemark(
573            pawnshop.location,
574            { companyCode: pawnshop.companyCode, code: pawnshop.code },
575            {
576                hasBalloon: false,
577                hasHint: false,
578                iconLayout: "default#image",
579                iconImageHref: iconUrl,
580                iconImageSize: [48, 48],
581                iconImageOffset: [-24, -48]
582            }
583        ));
584    });
585
586    pawnMapClickHandler = function (e) {
587        var clickedPlacemark = e.get("target");
588
589        if (lastClickedPlacemark) {
590            lastClickedPlacemark.options
591                .set("iconImageSize", [48, 48])
592                .set("iconImageOffset", [-24, -48]);
593        }
594
595        lastClickedPlacemark = clickedPlacemark;
596        lastClickedPlacemark.options
597            .set("iconImageSize", [64, 64])
598            .set("iconImageOffset", [-32, -64]);
599
600        var companyCode = clickedPlacemark.properties.get("companyCode");
601        if (companyCode === undefined) return;
602
603        var code = clickedPlacemark.properties.get("code");
604        safeInvokeDotNet("OnPawnshopClicked", companyCode, code);
605    };
606
607    pawnMapClusterer.events.add(["click"], pawnMapClickHandler);
608
609    pawnMap.controls.remove("trafficControl");
610    pawnMap.controls.remove("typeSelector");
611    pawnMap.controls.remove("searchControl");
612    pawnMap.controls.remove("zoomControl");
613    pawnMap.controls.remove("rulerControl");
614    pawnMap.controls.remove("fullscreenControl");
615
616    pawnMap.geoObjects.add(pawnMapClusterer);
617
618    pawnMapGeolocationControl = pawnMap.controls.get("geolocationControl");
619    if (pawnMapGeolocationControl) {
620        pawnMapGeolocationHandler = function (event) {
621            var position = event.get("position");
622            if (!Array.isArray(position) || position.length < 2) return;
623
624            safeInvokeDotNet("OnUserLocationChanged", position[0], position[1]);
625        };
626
627        pawnMapGeolocationControl.events.add("locationchange", pawnMapGeolocationHandler);
628    }
629
630    if (tryResolveUserLocationOnInit) {
631        ymaps.geolocation.get()
632            .then(function (res) {
633                if (!dotnetCallbackObjectRef) return;
634
635                var geoObject =
636                    res &&
637                        res.geoObjects &&
638                        typeof res.geoObjects.get === "function" &&
639                        res.geoObjects.getLength() > 0
640                        ? res.geoObjects.get(0)
641                        : null;
642
643                var position =
644                    geoObject &&
645                        geoObject.geometry &&
646                        typeof geoObject.geometry.getCoordinates === "function"
647                        ? geoObject.geometry.getCoordinates()
648                        : null;
649
650                if (!Array.isArray(position) || position.length < 2) return;
651
652                safeInvokeDotNet("OnUserLocationChanged", position[0], position[1]);
653            })
654            .catch(function (e) {
655                console.warn("[YandexMaps] startup geolocation failed:", e);
656            });
657    }
658
659    var layer = pawnMap.layers.get(0).get(0);
660
661    waitForTilesLoad(layer)
662        .then(function () {
663            if (dotnetCallbackObjectRef) {
664                safeInvokeDotNet("OnMapReady");
665            }
666        })
667        .catch(function () {
668            if (dotnetCallbackObjectRef) {
669                safeInvokeDotNet("OnMapReady");
670            }
671        });
672
673    setTimeout(function () {
674        if (!dotnetCallbackObjectRef) return;
675        safeInvokeDotNet("OnMapReady");
676    }, 1500);
677}
678
679function waitForTilesLoad(layer) {
680    return new ymaps.vow.Promise(function (resolve) {
681        var tc = getTileContainer(layer);
682
683        if (!tc || !tc.tiles) {
684            resolve();
685            return;
686        }
687
688        var readyAll = true;
689        tc.tiles.each(function (tile) {
690            if (!tile.isReady()) readyAll = false;
691        });
692
693        if (readyAll) {
694            resolve();
695            return;
696        }
697
698        var timeoutId = setTimeout(function () {
699            resolve();
700        }, 1500);
701
702        tc.events.once("ready", function () {
703            clearTimeout(timeoutId);
704            resolve();
705        });
706    });
707}
708
709function getTileContainer(layer) {
710    for (var k in layer) {
711        if (layer.hasOwnProperty(k)) {
712            var v = layer[k];
713            if (v && v.tiles && v.events) return v;
714
715            if (
716                v instanceof ymaps.layer.tileContainer.CanvasContainer ||
717                v instanceof ymaps.layer.tileContainer.DomContainer
718            ) {
719                return v;
720            }
721        }
722    }
723
724    return null;
725}
726
727window.startYandexMaps = async function (dotnetObjectRef, pawnshops, center, tryResolveUserLocationOnInit) {
728    disposeYandexMaps();
729
730    dotnetCallbackObjectRef = dotnetObjectRef;
731
732    try {
733        await ensureYandexMapsLoaded();
734
735        if (dotnetCallbackObjectRef !== dotnetObjectRef) {
736            return;
737        }
738
739        initYandexMaps(pawnshops, center, tryResolveUserLocationOnInit);
740    } catch (e) {
741        console.warn("[YandexMaps] start failed:", e);
742
743        if (!dotnetCallbackObjectRef) {
744            return;
745        }
746
747        safeInvokeDotNet(
748            "OnMapLoadFailed",
749            e && e.message ? e.message : "Не удалось загрузить карту."
750        );
751    }
752};
753
754window.stopYandexMaps = function () {
755    disposeYandexMaps();
756};
757
758window.setPlaceholder = function (id, text) {
759    const el = document.getElementById(id);
760    if (el) el.setAttribute("placeholder", text);
761}
762
763window.getInputCaretPos = function (el) {
764    return el ? el.selectionStart : -1;
765}
766window.setInputCaretPos = function (el, pos) {
767    if (el) el.selectionStart = el.selectionEnd = pos;
768}
769window.getInputSelection = function (el) {
770    return el ? [el.selectionStart, el.selectionEnd] : null;
771}
772window.getInputValue = function (el) {
773    return el ? el.value : null;
774}
775window.setInputValue = function (el, value) {
776    if (el) el.value = value;
777}
778
779window.masked = function (el, pattern, slots, accept, prepare) {
780    var format = null;
781    if (!el) return null;
782    if (el.dataset.maskedBound === "1") return format != null ? format() : null;
783    el.dataset.maskedBound = "1";
784
785    if (pattern)
786        el.setAttribute("placeholder", pattern);
787    else
788        pattern = el.getAttribute("placeholder");
789    slots = new Set(slots || el.dataset.slots || "_");
790    accept = new RegExp(accept || el.dataset.accept || "\\d", "g");
791    const prev = (j => Array.from(pattern, (c, i) => slots.has(c) ? j = i + 1 : j))(0),
792        first = [...pattern].findIndex(c => slots.has(c)),
793        clean = input => {
794            if (prepare) input = prepare(input);
795            input = input.match(accept) || [];
796            return Array.from(pattern, c =>
797                input[0] === c || slots.has(c) ? input.shift() || c : c
798            );
799        };
800    format = () => {
801        const [i, j] = [el.selectionStart, el.selectionEnd].map(i => {
802            i = clean(el.value.slice(0, i)).findIndex(c => slots.has(c));
803            return i < 0 ? prev.at(-1) : back ? prev[i - 1] || first : i;
804        });
805        el.value = clean(el.value).join("");
806        el.setSelectionRange(i, j);
807        back = false;
808        return el.value;
809    };
810    let back = false;
811    el.addEventListener("keydown", (e) => back = e.key === "Backspace");
812    el.addEventListener("input", format);
813    el.addEventListener("focus", format);
814    el.addEventListener("blur", () => el.value === pattern && (el.value = ""));
815    return format();
816}
817
818window.maskedInput = function (el, pattern, slots, accept) {
819    return window.masked(el, pattern, slots, accept);
820}
821
822window.maskedPhone = function (el, pattern, slots, accept) {
823    return window.masked(el, pattern, slots, accept, function (v) {
824        v = (v ?? "").replace(/\D/g, "");
825        while (v.startsWith("7") || v.startsWith("8")) v = v.substring(1);
826        if (v.length > 10) v.substring(0, 11);
827        return v;
828    });
829}
830
831window.maskPhone = function (id) {
832    const input = document.getElementById(id);
833    if (!input) return;
834
835    if (input.dataset.maskBound === "1") return;
836    input.dataset.maskBound = "1";
837
838    input.addEventListener("input", function () {
839        let x = this.value.replace(/\D/g, "");
840
841        if (x.startsWith("7")) x = x.substring(1);
842        if (x.startsWith("8")) x = x.substring(1);
843
844        let formatted = "+7";
845        if (x.length > 0) formatted += " (" + x.substring(0, 3);
846        if (x.length >= 4) formatted += ") " + x.substring(3, 6);
847        if (x.length >= 7) formatted += "-" + x.substring(6, 8);
848        if (x.length >= 9) formatted += "-" + x.substring(8, 10);
849
850        this.value = formatted;
851    });
852};
853
854window.initScroll = (element, dotNetHelper) => {
855    if (!element) return;
856    const handleScroll = () => {
857        dotNetHelper.invokeMethodAsync('OnScroll');
858    };
859    element.addEventListener('scroll', handleScroll);
860    element._scrollHandler = handleScroll;
861};
862
863window.scrollHorizontalBy = (element, amount) => {
864    if (element) {
865        element.scrollBy({
866            left: amount,
867            behavior: 'smooth'
868        });
869    }
870};
871
872window.scrollVerticalBy = (element, amount) => {
873    if (element) {
874        element.scrollBy({
875            top: amount,
876            behavior: 'smooth'
877        });
878    }
879};
880
881window.scrollVerticalTo = (element, position) => {
882    if (element) {
883        element.scrollTop = position;
884    }
885};
886
887window.getHorizontalScrollInfo = (element) => {
888    if (!element) {
889        return { scrollLeft: 0, scrollWidth: 0, clientWidth: 0 };
890    }
891    return {
892        scrollLeft: element.scrollLeft,
893        scrollWidth: element.scrollWidth,
894        clientWidth: element.clientWidth
895    };
896};
897
898window.getVerticalScrollInfo = (element) => {
899    if (!element) {
900        return { scrollTop: 0, scrollHeight: 0, clientHeight: 0 };
901    }
902    return {
903        scrollTop: element.scrollTop,
904        scrollHeight: element.scrollHeight,
905        clientHeight: element.clientHeight
906    };
907};
908
909function getBrowserTimeZone() {
910    return Intl.DateTimeFormat().resolvedOptions().timeZone;
911}
912
913window.getClientUtcOffsetMinutes = function () {
914    const offset = new Date().getTimezoneOffset();
915    return offset === 0 ? 0 : -offset;
916};

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.