PageSourceSearch

https://yug-frost.ru/modules/users/view/js/rscomponent/verification.js

js yug-frost.ru collected 2026-10-08 16:16:54 UTC 7,035 bytes, 199 lines download raw bytes

1/**
2 * Плагин, инициализирующий работу двухфакторной авторизации, регистрации
3 */
4new class Verification extends RsJsCore.classes.component
5{
6    constructor()
7    {
8        super();
9        this.settings = {
10            verifyBlock:           '.rs-verify-code-block',
11            refreshButtonSelector: '.rs-verify-refresh-code',
12            resetButtonSelector:   '.rs-verify-reset',
13
14            verifyTimerLine:       '.rs-verify-timer-line',
15            verifyTimer:           '.rs-verify-timer .rs-time',
16            verifyPhoneInput:      'input[data-phone]',
17            verifyTokenInput:      'input[data-token]',
18            verifyKeyInput:        'input[data-key]',
19            autoSubmitInput:       'input[data-auto-submit-length]',
20            errorSelector:         '.rs-verify-error',
21            errorFieldSelector:    '.invalid-feedback',
22            waitClass:             'rs-wait'
23        };
24    }
25
26    onDocumentReady() {
27        this.utils.on('click', this.settings.refreshButtonSelector, (event) => this.refreshCode(event));
28        this.utils.on('click', this.settings.resetButtonSelector, (event) => this.resetCode(event));
29        this.utils.on('input', this.settings.autoSubmitInput, (event) => this.onKeyPressAutoSubmit(event));
30    }
31
32    onContentReady() {
33        document.querySelectorAll(this.settings.verifyBlock).forEach((element) => {
34            let timer = element.querySelector('[data-delay-refresh-code-sec]');
35            if (timer) {
36                this.runTimer(timer);
37            }
38        });
39    }
40
41    /**
42     *  Выполняет запрос к серверу, для обновления блока верификации
43     *
44     * @param url
45     * @param data
46     * @param context
47     */
48    refresh(url, data, context) {
49
50        let showError = (text) => {
51            let errorElement = context.querySelector(this.settings.errorSelector)
52            if (errorElement) {
53                errorElement.innerText = text;
54                errorElement.classList.remove('hidden');
55                errorElement.classList.add('invalid-feedback');
56            }
57        };
58
59        fetch(url, {
60            credentials:'include',
61            headers: {
62                'X-Requested-With': 'XMLHttpRequest'
63            },
64            method: 'POST',
65            body: new URLSearchParams(data)
66        }).then(async (data) => {
67            if (data.ok) {
68                let response = await data.json();
69
70                if (response.success) {
71                    //Сбрасываем отображаемую ошибку
72                    let input = context.querySelector(this.settings.verifyPhoneInput);
73                    if (input) {
74                        input.classList.remove('is-invalid');
75                        let name = input.getAttribute('name');
76
77                        let error = context.parentNode.querySelector(this.settings.errorFieldSelector + '[data-field="' + name + '"]');
78                        error && error.remove();
79                    }
80                }
81
82                if (response.html) {
83                    let parent = context.parentNode;
84                    context.insertAdjacentHTML("afterend", response.html);
85                    context.remove();
86                    parent.dispatchEvent(new CustomEvent('new-content', {bubbles: true}));
87
88                    let inputKey = parent.querySelector(this.settings.verifyKeyInput);
89                    if (inputKey) {
90                        inputKey.focus();
91                    }
92                }
93            } else {
94                if (data.status === 404) {
95                    showError(lang.t('Сессия истекла. Обновите страницу'));
96                }
97            }
98        }).catch((response) => {
99            showError(lang.t('Произошла ошибка. Попробуйте позже'));
100        });
101    }
102
103    /**
104     * Обработчик ввода клавиш в online-поле с кодом верификации
105     */
106    onKeyPressAutoSubmit(event) {
107        let target = event.rsTarget;
108        let context = target.closest(this.settings.verifyBlock);
109
110        if (event.keyCode === 13) {
111            event.preventDefault();
112        }
113
114        setTimeout(() => {
115            let value = target.value;
116            let url = context.dataset.checkCodeUrl;
117
118            let data = {
119                phone: context.querySelector(this.settings.verifyPhoneInput).value,
120                token: context.querySelector(this.settings.verifyTokenInput).value,
121                code: value,
122            };
123
124            if ( value.length == target.dataset.autoSubmitLength || event.keyCode === 13) {
125                this.refresh(url, data, context);
126            }
127        }, 0);
128    }
129
130    /**
131     * Обработчик кнопки "Отправить код"
132     */
133    refreshCode(event) {
134        let target = event.rsTarget;
135        let context = target.closest(this.settings.verifyBlock);
136        let phone = context.querySelector(this.settings.verifyPhoneInput)
137        let url = target.dataset.url;
138        let data = {
139            token: context.dataset.token,
140            phone: phone && phone.value
141        };
142
143        this.refresh(url, data, context);
144    }
145
146    /**
147     * Обработчик кнопки "Изменить номер"
148     */
149    resetCode(event) {
150        let target = event.rsTarget;
151        let context = target.closest(this.settings.verifyBlock);
152        let url = target.dataset.url;
153        let data = {
154            token: context.dataset.token
155        };
156
157        this.refresh(url, data, context);
158    }
159
160    /**
161     * Возвращает отформатированное количество времени
162     *
163     * @param second
164     * @returns {string}
165     */
166    formatTime(second)  {
167        let hours = Math.floor(second/3600);
168        let minutes = Math.floor((second - hours*3600)/60);
169        let seconds = Math.floor(second - (minutes * 60 + hours * 3600));
170
171        return (hours > 0 ? ("0" + hours).substr(-2,2) + ':' : '') +
172            ("0" + minutes).substr(-2,2) + ':' +
173            ("0" + seconds).substr(-2,2);
174    }
175
176    /**
177     * Запускает обратный отсчет до повтора отправки кода
178     */
179    runTimer(element) {
180        let interval = setInterval(() => {
181            let delay = element.dataset.delayRefreshCodeSec ? element.dataset.delayRefreshCodeSec : 0 ;
182            if (delay > 0) {
183                delay--;
184
185                let timer = element.querySelector(this.settings.verifyTimer);
186                if (timer) {
187                    timer.innerText = this.formatTime(delay);
188                }
189                element.dataset.delayRefreshCodeSec = delay;
190            }
191
192            if (delay <= 0) {
193                clearInterval(interval);
194                element.classList.remove(this.settings.waitClass);
195            }
196        }, 1000);
197
198    }
199};

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.