PageSourceSearch

https://hobbygames.by/assets/js/global-2025-03-10-01.js

js hobbygames.by collected 2026-09-26 02:59:45 UTC 9,508 bytes, 272 lines download raw bytes

1// console-заглушки
2if (!window.console) {
3    window.console = {};
4}
5if (!window.console.log) {
6    window.console.log = function () { };
7}
8
9
10(function (window) {
11    const SELECTORS = {
12        GLOBAL_LOADER: '.global-loader',
13        LOCAL_LOADER: '.local-loader',
14    };
15
16    window.locale = {
17        LC_RU: 'ru',
18        LC_BY: 'by',
19        LC_KZ: 'kz',
20        LC_AM: 'am',
21        is: (locale1, locale2) => locale1.toLowerCase() === locale2.toLowerCase(),
22    };
23
24    const Application = function () { };
25    Application.prototype = {
26
27        waitScript: (name, cb = null) => {
28
29            return new Promise(resolve => {
30
31                const observer = new MutationObserver(() => {
32                    const $script = $(`script[src*="${CSS.escape(name)}"]`);
33                    if (!$script.length) {
34                        return;
35                    }
36                    observer.disconnect();
37                    $script.on('load', () => setTimeout(() => {
38                        cb?.() + resolve()
39                    }));
40                });
41
42                observer.observe(document, { childList: true, subtree: true });
43
44            });
45
46        },
47
48        addStyle: function (href, callback) {
49            if (!$('head link[href="' + href + '"]').length) {
50
51                const successFn = function () {
52                    if (callback && $.isFunction(callback)) {
53                        callback.apply(this, arguments);
54                    }
55                    //console.log(href + ' added');
56                },
57                    link = document.createElement('link');
58
59                link.type = 'text/css';
60                link.href = href;
61                link.rel = 'stylesheet';
62                document.head.appendChild(link);
63
64                link.onload = link.onerror = function () {
65                    if (!this.executed) {
66                        this.executed = true;
67                        successFn();
68                    }
69                };
70
71                link.onreadystatechange = function () {
72                    const self = this;
73                    if (this.readyState === 'complete' || this.readyState === 'loaded') {
74                        setTimeout(function () { self.onload() }, 0);
75                    }
76                };
77
78            }
79        },
80
81        addScript: async function (src, callback = null) {
82
83            return new Promise((resolve, reject) => {
84
85                if (!$('body script[src="' + src + '"]').length) {
86
87                    const script = document.createElement('script');
88
89                    Object.assign(script, {
90                        src,
91                        type: 'text/javascript',
92                        onload() {
93                            if (!this.executed) {
94                                this.executed = true;
95                                callback?.call(this);
96                                resolve();
97                            }
98                        },
99                        onerror: reject,
100                    });
101
102                    if (!document.body) {
103                        setTimeout(() => document.body.appendChild(script));
104                    } else {
105                        document.body.appendChild(script);
106                    }
107
108                } else {
109                    return resolve();
110                }
111
112            });
113        },
114
115        showGlobalLoader: function () {
116            $(function () {
117                $(SELECTORS.GLOBAL_LOADER).each(function () {
118                    if ($(this).parent().is(':visible')) {
119                        $(this).show();
120                        return false;
121                    }
122                });
123            });
124        },
125
126        hideGlobalLoader: function () {
127            $(function () {
128                $(SELECTORS.GLOBAL_LOADER).hide();
129            });
130        },
131
132        showButtonLoader: function ($button) {
133            window.Application.checkoutPendingRequestCounter++;
134
135            if (window.Application.checkoutPendingRequestCounter <= 1) {
136                $button.each(function () {
137                    $(this).addClass('show-spinner').html(`<span class="btn-spinner">
138                    <div class="animation">
139                        <div></div>
140                        <div></div>
141                        <div></div>
142                        <div></div>
143                        <div></div>
144                        <div></div>
145                        <div></div>
146                        <div></div>
147                        <div></div>
148                        <div></div>
149                    </div>
150                </span>` + $(this).html());
151                });
152            }
153        },
154
155        /**
156         * Скролл к последнему активному шагу корзин
156ы по окончанию анимации спиннера на кнопке "Далее"
157         * Само скрытие происходит в обработчике ивента 'checkout:scrollToStep'
158         * Если нужно скрыть лоадер сразу - воспользуйся removeButtonLoader
159         */
160        scrollAndHideButtonLoader: function () {
161            --window.Application.checkoutPendingRequestCounter;
162
163            if (window.Application.checkoutPendingRequestCounter <= 0) {
164                window.Application.checkoutPendingRequestCounter = 0;
165
166                window.Application.dispatcher?.trigger('checkout:scrollToStep');
167            }
168        },
169
170        /**
171         * Скрытие лоадера на кнопке "Далее" в корзине
172         */
173        removeButtonLoader: function () {
174            $('.show-spinner').each(function () {
175                $(this).removeClass('show-spinner').find('.btn-spinner').remove();
176            });
177        },
178
179        /**
180         * Обертка над window.scrollTo с коллбеком по окончанию анимации скролла
181         * @param offset - сколько нужно проскроллить пикселей
182         * @param callback
183         */
184        scrollTo: function (offset, callback) {
185            let isScrolling;
186
187            // Проверяем скроллится ли страица? По окончанию скролла нужно будет вызвать коллбек
188            const onScroll = function () {
189                // Fallback для больших экранов, где не триггерится скролл
190                window.clearTimeout(isScrolling);                
191                isScrolling = setTimeout(callback, 100);
192
193                window.addEventListener('scroll', function () {
194                    window.clearTimeout( isScrolling );
195                    isScrolling = setTimeout(callback, 30);
196                }, { once: true });
197            }
198
199            onScroll()
200            window.scrollTo({
201                top: offset,
202                behavior: 'smooth',
203            })
204        },
205
206        showLocalLoader: function () {
207            $(SELECTORS.LOCAL_LOADER).each(function () {
208                if ($(this).parent().is(':visible')) {
209                    $(this).show();
210                    return false;
211                }
212            });
213        },
214        hideLocalLoader: function () {
215            $(SELECTORS.LOCAL_LOADER).hide();
216        },
217        showFormErrors: function (form, errors) {
218            for (const key in errors) {
219                const input = form.find("[name='" + key + "']");
220                if (input.length) {
221                    if (!input.next().hasClass('error')) {
222                        input.after('<div class="error"></div>');
223                    }
224                    input.addClass("error-input");
225                    input.next().text(errors[key]);
226                }
227            }
228        },
229        clearFormErrors: function (form) {
230            form.find('.error').remove();
231            form.find('.error-input').removeClass("error-input");
232        },
233        formErrors: function (form, errors) {
234            for (const key in errors) {
235                const input = form.find("[name='" + key + "']");
236                if (input.length) {
237                    if (!input.next().hasClass('error')) {
238                        input.after('<div class="error"></div>');
239                    }
240                    input.addClass("error-input");
241                    input.next().text(errors[key]);
242                }
243            }
244        },
245        flashMessage: function ($object, text, cb) {
246            if ($object.length) {
247                $object.text(text)
248                    .fadeIn(200)
249                    .delay(3000)
250                    .queue(function (n) {
251                        const $this = $(this);
252                        $this.fadeOut(200);
253                        $this.text('');
254                        n();
255                        cb && cb();
256                    });
257            }
258        },
259        declination: function (number, titles) {
260            const cases = [2, 0, 1, 1, 1, 2];
261            return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
262        },
263        priceDigits(price){
264            return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
265        },
266        priceText(price) {
267            return `${window.config.currencyL}${this.priceDigits(price)}${window.config.currencyR}`;
268        }
269    };
270
271    window.APP = new Application();
272})(window);

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.