PageSourceSearch

https://cdnn.1prime.ru//js/libs/ria.chat.js

js 1prime.ru collected 2026-09-24 08:26:38 UTC 51,067 bytes, 1,518 lines download raw bytes

1var ria_chat = {};
2
3(function() {
4    var initialState = {
5        addUrl: '/services/chat/add/',
6        eventUrl: '/services/chat/event/',
7        likeUrl: '/services/chat/like/',
8        emojiUrl: '/services/chat/add_emoji/',
9        getUrl: '/services/chat/get/',
10        deleteUrl: '/services/chat/delete/',
11        deleteModeratorUrl: '/services/chat/moderation/delete/',
12        reportUrl: '/services/chat/report/',
13        unreadUrl: '/services/chat/get_unread_counter/',
14        getUnreadUrl: '/services/chat/get_unread_message/',
15        setLastUrl: '/services/chat/set_last_message/',
16        sockUrl: 'http://docker-test1.rian.off:8008/chat',
17        article_id: '',
18        chat: null,
19        sock: false,
20        loading: false,
21        unread: 0
22    }
23
24    ria_chat = {
25        state: {},
26        init: function(options) {
27            _.assign(options, {
28                sock: ria_sock.get()
29            });
30            _.assign(initialState, options);
31            _.assign(this.state, initialState);
32
33            ria_sock.on('chat_message', function(data) {
34                addMessageCallback(data);
35            })
36
37            ria_sock.on('chat_message_delete', function(data) {
38                deleteMessageCallback(data);
39            })
40
41            ria_sock.on('chat_emoji_add', function(data) {
42                emojiAddCallback(data);
43            })
44
45            ria_sock.on('onopen', function() {
46                var article_id = ria_chat.state.article_id;
47                // Если на странице статьи
48                if (article_id) {
49                    ria_chat.left();
50                    ria_chat.join( article_id );
51                }
52            });
53
54            ria_sock.on('user_notify', function(data) {
55                if (data.subtype === 'site_user_ban') {
56                    $('.chat__banned').show();
57
58                    $('.chat__lenta').addClass('m-banned');
59
60                    if (data.count) {
61                        $('#chatBannedTime').text(data.count + ' часов');
62                    } else {
63                        $('#chatBannedTime').text('∞');
64                    }
65                }
66
67                if (data.subtype === 'site_user_unban') {
68                    $('.chat__form').show();
69                    $('.chat__banned').hide();
70                    $('.chat__lenta').removeClass('m-banned');
71                }
72            })
73
74            return this;
75        },
76        join: function (article_id) {
77            _.assign(ria_chat.state, {
78                article_id: article_id
79            });
80
81            ria_sock.send({
82                type: 'chat_user_join',
83                message: {
84                    obj_id: article_id
85                }
86            });
87
88            userJoinCallback();
89        },
90        left: function() {
91            if (!ria_chat.state.article_id) {
92                return
93            }
94
95            if (ria_chat.state.sock && ria_sock.connected) {
96                ria_sock.send({
97                    type: 'chat_user_left',
98                    message: {
99                        obj_id: ria_chat.state.article_id
100                    }
101                });
102            }
103
104            userLeftCallback();
105        },
106        disconnect: function() {
107            if (this.state.sock) {
108                this.state.sock.close();
109            }
110        },
111        auth: function() {
112            var article_id = ria_chat.state.article_id;
113            // Если на странице статьи
114            if (article_id) {
115                ria_chat.left();
116                ria_chat.join( article_id );
117            }
118
119            if (GLOBAL.user.isBanned) {
120                $('.chat__banned').show();
121
122                $('.chat__lenta').addClass('m-banned');
123
124                if (GLOBAL.user.banTimeEnd) {
125                    $('#chatBannedTime').text(GLOBAL.user.banTimeEnd);
126                } else {
127                    $('#chatBannedTime').text('∞');
128                }
129            }
130
131            ria_chat.state.chat.find('.chat__auth').hide();
132            ria_chat.state.chat.find('.chat__input').show();
133        }
134    }
135
136    /**
137     * Получить время в нужном формате
138     * @param {number} timestamp js timestamp
139     * @requires moment.js
140     */
141    function formatTime(timestamp) {
142        return moment(timestamp).calendar(null, {
143            sameDay: 'LT',
144            lastDay: '[Вчера], LT',
145            lastWeek: 'DD MMMM, hh:mm',
146            sameElse: function(now) {
147                return this.isBefore(now.startOf('year')) ? 'DD MMMM YYYY, hh:mm' : 'DD MMMM, hh:mm'
148            }
149        });
150    }
151
152    /**
153     * Загрузить все сообщения и переместиться наверх
154     */
155    function loadAllMessages() {
156        if (!ria_chat.state.last_date) {
157            scrollTo('0');
158            return
159        }
160
161        $.ajax({
162            url: ria_chat.state.getUrl,
163            dataType: 'json',
164            beforeSend: function() {
165                ria_chat.state.loading = true;
166                ria_chat.state.chat.addClass('chat-loader');
167            },
168            data: {
169                article_id: ria_chat.state.article_id,
170                date: ria_chat.state.last_date.sec,
171                date_usec: ria_chat.state.last_date.usec,
172                id_exc: ria_chat.state.last_id,
173                limit: 9999
174            }
175        }).done(function(response) {
176            if (!response.chat.messages) {
177                return;
178            }
179
180            var emoji = response.emoji_chat;
181
182            ria_chat.state.last_date = response.chat.last_date;
183            ria_chat.state.last_id = response.chat.last_id;
184
185            // Если последняя загрузка
186            if (!ria_chat.state.last_date) {
187                window.dataLayer = window.dataLayer || [];
188                dataLayer.push({
189                    'event':'chat',
190                    'gaEventAction':'chat_scroll',
191                    'gaEventLabel':'comments_100%'
192                });
193            }
194
195            // Добавить комментарии
196            addMessage({
197                banned_profiles: response.banned_profiles,
198                data: response.chat.messages,
199                prepend: true
200            });
201
202            // Добавить эмоции
203            if (emoji && emoji.length) {
204                for (var i in emoji) {
205                    var item = emoji[i];
206
207                    emojiAddCallback({
208                        emotions: item.emotions,
209                        sorted_emotions: item.sorted_emotions,
210                        message_id: item.object_id
211                    });
212                }
213            }
214
215            scrollTo('0');
216        }).always(function() {
217            ria_chat.state.loading = false;
218            ria_chat.state.chat.removeClass('chat-loader');
219        });
220    }
221
222    /**
223     * Подгрузка сообщений
224     */
225    function loadMoreMessages() {
226        if (!ria_chat.state.last_date) {
227            return
228        }
229
230        $.ajax({
231            url: ria_chat.state.getUrl,
232            dataType: 'json',
233            beforeSend: function() {
234                ria_chat.state.loading = true;
235            },
236            data: {
237                article_id: ria_chat.state.article_id,
238                date: ria_chat.state.last_date.sec,
239                date_usec: ria_chat.state.last_date.usec,
240                id_exc: ria_chat.state.last_id
241                // reverse: 0
242            }
243        }).done(function(response) {
244            if (!response.chat.messages) {
245                return;
246            }
247
248            var emoji = response.emoji_chat;
249
250            ria_chat.state.last_date = response.chat.last_date;
251            ria_chat.state.last_id = response.chat.last_id;
252
253            // Если последняя загрузка
254            if (!ria_chat.state.last_date) {
255                window.dataLayer = window.dataLayer || [];
256                dataLayer.push({
257                    'event':'chat',
258                    'gaEventAction':'chat_scroll',
259                    'gaEventLabel':'comments_100%'
260                });
261            }
262
263            // Вычислить текущую позицию скролла
264            var scrollData = ria_chat.state.chat_lenta.data('theinScroll'),
265                scrollPosition = scrollData.$content.height() - scrollData.$box.height();
266
267            // Добавить комментарии
268            addMessage({
269                banned_profiles: response.banned_profiles,
270                data: response.chat.messages,
271                prepend: true
272            });
273
274            // Добавить эмоции
275            if (emoji && emoji.length) {
276                for (var i in emoji) {
277                    var item = emoji[i];
278
279                    emojiAddCallback({
280                        emotions: item.emotions,
281                        sorted_emotions: item.sorted_emotions,
282                        message_id: item.object_id
283                    });
284                }
285            }
286
287            // Скроллить в прежнее положение
288            if (response.chat.messages.length) {
289                ria_chat.state.chat_lenta.trigger( 'scroll-down.the-in-scroll', [ scrollPosition, 100 ] )
290            }
291        }).always(function() {
292            ria_chat.state.loading = false;
293        });
294    }
295
296    /**
297     * Показать непрочитанные сообщения
298     */
299    function addUnread(options) {
300        // увеличить счетчик непрочитанных
301        _.assign(ria_chat.state, {
302            unread: ria_chat.state.unread + options.count
303        })
304
305
306        if (ria_chat.state.unread === 0) {
307            return
308        }
309
310        var unreadBanner = $('.chat__alert-unread');
311
312        // Показать баннер
313        if (!unreadBanner.length) {
314            var result = ria_chat.state.alertUnreadTemplate();
315            if (options.before) {
316                options.before.before(result);
317            } else {
318                ria_chat.state.chat_lenta.trigger('add-content.the-in-scroll', [ result ]);
319            }
320
321            // Убрать баннер, если доскролили до непрочитанных
322            setTimeout(function() {
323                unreadBanner = $('.chat__alert-unread');
324                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
325                    name: 'unread_trigger',
326                    position: unreadBanner.position().top + 1,
327                    sign: '>',
328                    // move: true,
329                    once: true
330                } ]);
331
332                ria_chat.state.chat_lenta.on('unread_trigger.the-in-scroll', function(e, data) {
333                    markAsRead();
334                });
335            }, 200);
336        }
337
338        // Поменять цифру на кнопке
339        $('#chatScrollDownBtn').attr('count', ria_chat.state.unread);
340    }
341
342    /**
343     * Пометить все сообщения в чате как прочитанные
344     */
345    function markAsRead() {
346        if (ria_chat.state.markAsReadTimeout) {
347            clearTimeout(ria_chat.state.markAsReadTimeout);
348        }
349
350        ria_chat.state.markAsReadTimeout = setTimeout(function() {
351            $.ajax({
352                url: ria_chat.state.setLastUrl,
353                data: {
354                    room_id: ria_chat.state.article_id,
355                    message_id: ria_chat.state.last_unread.id,
356                    date: ria_chat.state.last_unread.created.sec,
357                    usec: ria_chat.state.last_unread.created.usec
358                }
359            }).done(function() {
360                // Обновить глобальный счетчик
361                ria_chat_manager.updateUnread();
362
363                // Обновить локальный счетчик
364                _.assign(ria_chat.state, {
365                    unread: 0
366                });
367
368                // Поменять цифру на кнопке
369                $('#chatScrollDownBtn').removeAttr('count');
370            })
371        }, 5000)
372    }
373
374    /**
375     * Скролить вниз
376     */
377    function scrollBottom() {
378        scrollTo('100%');
379    }
380
381    /**
382     * Скролить до непрочитанных
383     */
384    function scrollToUnread() {
385        var unreadBanner = $('.chat__alert-unread');
386
387        if (unreadBanner.length) {
388            scrollTo( unreadBanner.position().top - ria_chat.state.chat_lenta.data('theinScroll').$box.height() + 50 );
389        } else {
390            scrollBottom();
391        }
392
393        ria_chat.state.unreadWhenChatOpen = false;
394    }
395
396    // Скролл к сообщению
397    function scrollToMessage(message_id) {
398        var message = $('#message_' + message_id);
399
400        if (message.length) {
401            scrollTo( message.position().top - ria_chat.state.chat_lenta.data('theinScroll').$box.height()/2 );
402        } else {
403            scrollBottom();
404        }
405    }
406
407    /**
408     * Скролить на n пикселей
409     * @param {number} n кол-во пикселей
410     */
411    function scrollTo(n) {
412        ria_chat.state.chat_lenta.trigger( 'scroll-to.the-in-scroll', [ n, 100 ] )
413    }
414
415    /**
416     * Скролл вниз
417     * @param {event} e
418     */
419    function clickScrollDownHandler(e) {
420        e.preventDefault();
421        if (ria_chat.state.unreadWhenChatOpen) {
422            scrollToUnread();
423        } else {
424            scrollBottom();
425        }
426    }
427
428    /**
429     * Скролл вверх
430     */
431    function clickScrollTopHandler(e) {
432        e.preventDefault();
433        loadAllMessages();
434    }
435
436    /**
437     * Отправить сообщение на сервис
438     * @param {string} url
439     * @param {object} data
440     */
441    function sendMessage(url, data) {
442        if (!url) {
443            return;
444        }
445
446        var data = data || {}
447
448        return $.ajax({
449            url: url,
450            data: data,
451            method: 'POST'
452        });
453    }
454
455    function userLeftCallback() {
456        // Убрать обработчик скролла
457        ria_chat.state.chat_lenta.off('refreshed_trigger.the-in-scroll');
458        ria_chat.state.chat_lenta.off('unread_trigger.the-in-scroll');
459        ria_chat.state.chat_lenta.off('show_arrow_trigger.the-in-scroll');
460        ria_chat.state.chat_lenta.off('show_arrow_top_trigger.the-in-scroll');
461        ria_chat.state.chat_lenta.off('hide_arrow_trigger.the-in-scroll');
462        ria_chat.state.chat_lenta.off('hide_arrow_top_trigger.the-in-scroll');
463
464        // Очистить окно чата
465        ria_chat.state.chat_lenta.trigger('clear-content.the-in-scroll');
466
467        // Очистить форму
468        ria_chat.state.chat.find('form')[0].reset();
469
470        $('#chatScrollDownBtn').removeAttr('count').fadeIn();
471        $('#chatScrollTopBtn').fadeIn();
472        $('.chat__alert-unread').remove();
473
474        // Обнулить данные
475        _.assign(ria_chat.state, initialState);
476    }
477
478    function userJoinCallback() {
479        if (!ria_chat.state.article_id) {
480            return;
481        };
482
483        // Установить фокус в поле ввода, исключить мобильные устройства
484        if (!('ontouchstart' in window)) {
485            ria_chat.state.chat.find('form textarea').focus();
486        }
487
488        // Загрузить последние
489        $.ajax({
490            url: ria_chat.state.getUnreadUrl,
491            dataType: 'json',
492            data: {
493                article_id: ria_chat.state.article_id,
494                limit: ria_chat.state.goto_message ? 1000 : 20
495            }
496        }).done(function(response) {
497
498            var readList = response.chat_messages,
499                unreadList = response.chat_unread_messages,
500                emoji = response.emoji_chat;
501
502            if (!readList && !unreadList) {
503                return;
504            }
505
506            // Добавить прочитанные ранее сообщения
507            if (readList) {
508                _.assign(ria_chat.state, {
509                    user_id: response.user_id,
510                    last_date: readList.last_date,
511                    last_id: readList.last_id
512                });
513
514                addMessage({
515                    banned_profiles: response.banned_profiles,
516                    data: readList.messages
517                });
518            }
519
520            // Пометить сообщения, на которые жаловался пользователь
521            if (response.report_message_ids ) {
522                for (var i = 0; i < response.report_message_ids.length; i++) {
523                    reportLoadMessageHandler( response.report_message_ids[i] );
524                }
525            }
526
527            // Добавить непрочитанные сообщения
528            if (unreadList && unreadList.messages.length) {
529                _.assign(ria_chat.state, {
530                    last_unread: unreadList.messages[unreadList.messages.length -1]
531                });
532                addUnread({
533                    count: unreadList.total
534                });
535                addMessage({
536                    banned_profiles: response.banned_profiles,
537                    data: unreadList.messages
538                });
539            }
540
541            // Добавить эмоции
542            if (emoji && emoji.length) {
543                for (var i in emoji) {
544                    var item = emoji[i];
545
546                    emojiAddCallback({
547                        emotions: item.emotions,
548                        sorted_emotions: item.sorted_emotions,
549                        message_id: item.object_id
550                    });
551                }
552            }
553
554            setTimeout(function() {
555                var dataScroll = ria_chat.state.chat_lenta.data('theinScroll');
556
557                // Если нет скролла
558                if (dataScroll.percentSizeScroller === 100) {
559                    // Скрыть стрелку
560                    $('#chatScrollDownBtn').fadeOut();
561
562                    // Пометить все как прочитанные
563                    if (ria_chat.state.unread > 0) {
564                        markAsRead();
565                    }
566                }
567
568                if (dataScroll.percentSizeScroller === 0) {
569                    // Скрыть стрелку
570                    $('#chatScrollTopBtn').fadeOut();
571                }
572
573                // Если нет скролла или скролл маленький
574                if (dataScroll.percentSizeScroller === 100 || ((dataScroll.sizeScrollLine - dataScroll.pxSizeScroller) < 100)) {
575                    window.dataLayer = window.dataLayer || [];
576                    dataLayer.push({
577                        'event':'chat',
578                        'gaEventAction':'chat_scroll',
579                        'gaEventLabel':'comments_100%'
580                    });
581                }
582            }, 99);
583
584            // При первоначальной загрузке чата скролим до непрочитанных или до сообщения
585            setTimeout(function() {
586                if (ria_chat.state.goto_message) {
587                    scrollToMessage( ria_chat.state.goto_message );
588                    ria_chat.state.goto_message = null;
589                } else {
590                    scrollToUnread();
591                }
592            }, 100)
593
594            // Подгрузка комментариев при скролле
595            setTimeout(function() {
596                // Добавить триггер
597                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
598                    name: 'refreshed_trigger',
599                    position: 100,
600                    sign: '<',
601                    move: true,
602                    everytime: true
603                } ]);
604
605                // Подписаться на свой триггер
606                ria_chat.state.chat_lenta.on('refreshed_trigger.the-in-scroll', function(e, data) {
607                    if (!ria_chat.state.loading) {
608                        loadMoreMessages();
609                    }
610                });
611            }, 101);
612
613            // Показать/скрыть стрелку вниз/вверх
614            setTimeout(function() {
615                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
616                    name: 'hide_arrow_trigger',
617                    position: '99.9%',
618                    move: true,
619                    everytime: true
620                } ]);
621
622                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
623                    name: 'show_arrow_trigger',
624                    position: '99.9%',
625                    sign: '<',
626                    move: true,
627                    everytime: true
628                } ]);
629
630                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
631                    name: 'hide_arrow_top_trigger',
632                    position: '50px',
633                    sign: '<',
634                    move: true,
635                    everytime: true
636                } ]);
637
638                ria_chat.state.chat_lenta.trigger('add-scrolling-trigger.the-in-scroll', [ {
639                    name: 'show_arrow_top_trigger',
640                    position: '50px',
641                    sign: '>',
642                    move: true,
643                    everytime: true
644                } ]);
645
646                ria_chat.state.chat_lenta.on('hide_arrow_trigger.the-in-scroll', function(e, data) {
647                    $('#chatScrollDownBtn').fadeOut();
648
649                    // Отметить непрочитанные, если есть
650                    if (ria_chat.state.unread > 0) {
651                        markAsRead();
652                    }
653                });
654
655                ria_chat.state.chat_lenta.on('show_arrow_trigger.the-in-scroll', function(e, data) {
656                    $('#chatScrollDownBtn').fadeIn();
657                });
658
659                ria_chat.state.chat_lenta.on('show_arrow_top_trigger.the-in-scroll', function(e, data) {
660                    $('#chatScrollTopBtn').fadeIn();
661                });
662
663                ria_chat.state.chat_lenta.on('hide_arrow_top_trigger.the-in-scroll', function(e, data) {
664                    $('#chatScrollTopBtn').fadeOut();
665                });
666            }, 102);
667        });
668    }
669
670    function addMessageCallback(data) {
671        // Добавить комментарий в DOM
672        addMessage({
673            data: [data]
674        });
675
676        // Если свой комментарий скролить вниз всегда
677        if (data.user_id === ria_chat.state.user_id) {
678            scrollBottom();
679            return;
680        }
681
682        // Если скролла нет
683        if (ria_chat.state.chat_lenta.data('theinScroll').percentSizeScroller === 100) {
684            _.assign(ria_chat.state, {
685                last_unread: {
686                    id: data.id,
687                    created: {
688                        sec: data.date.sec,
689                        usec: data.date.usec
690                    }
691                }
692            });
693            markAsRead();
694            return;
695        }
696
697        // Если есть скролл и пользователь не внизу чата
698        if (ria_chat.state.chat_lenta.data('theinScroll').scrollingPercentage < 98) {
699            _.assign(ria_chat.state, {
700                last_unread: {
701                    id: data.id,
702                    created: {
703                        sec: data.date.sec,
704                        usec: data.date.usec
705                    }
706                }
707            });
708            addUnread({
709                before: $('#message_' + data.id),
710                count: 1
711            });
712            ria_chat.state.unreadWhenChatOpen = true;
713            return;
714        }
715
716        // Если пользователь внизу чата
717        if (ria_chat.state.chat_lenta.data('theinScroll').scrollingPercentage >= 98) {
718            _.assign(ria_chat.state, {
719                last_unread: {
720                    id: data.id,
721                    created: {
722                        sec: data.date.sec,
723                        usec: data.date.usec
724                    }
725                }
726            });
727            markAsRead();
728            scrollBottom();
729            return;
730        }
731    }
732
733    /**
734     * Добавить сообщение в DOM
735     * @param {Object} options
736     */
737    function addMessage(options) {
738        var html = '',
739            data = options.data,
740            prepend = options.prepend || false;
741
742        for (var i = 0; i < data.length; i++) {
743            data[i].time = formatTime(data[i].ts_gmt * 1000);
744            data[i].auth = GLOBAL.auth.status === 'ok';
745            data[i].letters = [];
746            data[i].bg_number = 0;
747
748            var names = data[i].nickname.split(' ');
749
750            for (var j = 0; j < 2; j++) {
751                if (names[j]) {
752                    data[i].bg_number += names[j].length;
753                    data[i].letters.push(names[j].charAt(0));
754                }
755            }
756            data[i].bg_number = data[i].bg_number > 20 ? Math.ceil(data[i].bg_number / 10) : data[i].bg_number;
757
758            // Модератор
759            data[i].is_moderator = !!GLOBAL.auth.moderator;
760
761            // Свой комментарий
762            if (data[i].user_id === ria_chat.state.user_id) {
763                data[i].is_my = true
764            }
765
766            if (data[i].parent_comment && (data[i].parent_comment.user_id === ria_chat.state.user_id)) {
767                data[i].parent_comment.is_my = true
768            }
769
770            if (data[i].avatar) {
771                data[i].avatar = data[i].avatar.replace('https://cdn22.img.ria.ru/images/', '').replace('https://cdn1.img.ria.ru/userpic/', '');
772                data[i].avatar = GLOBAL.userpic + data[i].avatar;
773            }
774
775            if (options.banned_profiles && options.banned_profiles.length) {
776                data[i].is_blocked = !!options.banned_profiles.filter(function(item) {
777                    return item.id === data[i].user_id
778                }).length;
779            }
780
781            html += ria_chat.state.messageTemplate({ data: data[i] });
782        }
783
784        // Добавить сообщение
785        ria_chat.state.chat_lenta.trigger('add-content.the-in-scroll', [ html, prepend ]);
786
787        for (var i = 0; i < data.length; i++) {
788            linkToSnippet( $('#message_' + data[i].id) );
789        }
790    }
791
792    /**
793     * Удалить сообщение из DOM
794     * @param {object} data
795     */
796    function deleteMessageCallback(data) {
797        // Сообщение
798        var message = $('#message_' + data.message_id);
799
800        // Если сообщение загружено в чат
801        if (!message.length) {
802            return;
803        }
804
805        // Если не последнее в списке
806        if (message.next('.chat__lenta-item').length) {
807            message
808                .addClass('m-removed')
809                .find('.chat__lenta-item-message')
810                .html('Сообщение удалено автором');
811        } else {
812            message.slideUp('slow', function() {
813                message.remove();
814            });
815        }
816    };
817
818    /**
819     * Поставить лайк
820     * @param {object} data данные
821     */
822    function emojiAddCallback(data) {
823        var emotions_count = 0;
824
825        for (var i in data.emotions ) {
826            emotions_count += parseInt(data.emotions[i]);
827        }
828
829        var emotions_icons = {
830            's1': {
831                icon: 'like_circle',
832                title: 'Нравится'
833            },
834            's2': {
835                icon: 'haha_filled',
836                title: 'Ха-Ха'
837            },
838            's3': {
839                icon: 'wow_filled',
840                title: 'Удивительно'
841            },
842            's4': {
843                icon: 'sad_filled',
844                title: 'Грустно'
845            },
846            's5': {
847                icon: 'angry_filled',
848                title: 'Возмутительно'
849            },
850            's6': {
851                icon: 'dislike_circle',
852                title: 'Не нравится'
853            },
854        }
855
856        var result = ria_chat.state.messageEmojiTemplate({ data: {
857            icons: emotions_icons,
858            emotions: data.emotions,
859            sorted_emotions: data.sorted_emotions,
860            emotions_count: emotions_count
861        } });
862
863        var message = $('#message_' + data.message_id);
864
865        if (!message.length) {
866            return;
867        }
868
869        message.find('.chat__lenta-item-message-likes .m-placeholder').empty().html( result );
870        message.data('emotions', data.emotions);
871    }
872
873    /**
874     * Отправка комментария
875     * @param {event} e
876     */
877    function submitMessageFormHandler(e) {
878        e.preventDefault();
879
880        var form = $(this);
881
882        // Получить данные формы
883        var data = form.serializeArray();
884
885        // Если пустое сообщение
886        if (!data[0].value) {
887            return;
888        }
889
890        data.push({
891            name: 'article_id',
892            value: ria_chat.state.article_id
893        });
894
895        if (GLOBAL.user.showCaptcha === '1') {
896            checkCaptchaToken({
897                type: 'chat',
898                callback: function(token) {
899                    data.push({ name: 'g-recaptcha-response', value: token });
900                    sendMessage(ria_chat.state.addUrl, data);
901                }
902            })
903        } else {
904            // Отправить на сервер
905            sendMessage(ria_chat.state.addUrl, data);
906        }
907
908        // Стереть форму ввода
909        form[0].reset();
910
911        // Установить фокус в поле ввода, исключить мобильные устройства
912        if (!('ontouchstart' in window)) {
913            form.find('textarea').focus().trigger('keyup');
914        }
915
916        // Удалить цитируемое сообщение
917        $('.chat__reply').remove()
918    }
919
920    /**
921     * Валидация формы
922     */
923    function inputMessageFormHandler(e) {
924        $('.chat__input-send').attr('disabled', !this.checkValidity());
925    }
926
927    /**
928     * Обработка нажатия Enter
929     * @param {event} e
930     */
931    function submitMessageFormByEnterHandler(e) {
932        if (e.which == 13 && !e.shiftKey) {
933            $(this).closest('form').submit();
934            e.preventDefault();
935        }
936    }
937
938    /**
939     * Сообщение на которое пожаловались
940     * @param {number|string} id
941     */
942    function reportLoadMessageHandler(id) {
943
944        // Сообщение
945        var msg = $('#message_' + id);
946
947        msg.addClass('m-removed')
948            .find('.chat__lenta-item-message')
949            .html('Жалоба на комментарий отправлена администраторам сайта');
950    }
951
952    /**
953     * Пожаловаться на сообщение
954     * @param {event} e
955     */
956    function clickReportMessageHandler(e) {
957        e.preventDefault();
958
959        // Сообщение
960        var id = $(this).data('id'),
961            message = $('#message_' + id);
962
963        var data = {
964            article_id: ria_chat.state.article_id,
965            message_id: id
966        }
967
968        sendMessage(ria_chat.state.reportUrl, data);
969
970        message
971            .addClass('m-removed')
972            .find('.chat__lenta-item-message')
973            .html('Жалоба на комментарий отправлена администраторам сайта');
974    }
975
976    /**
977     * Удалить сообщение
978     * @param {event} e
979     */
980    function clickDeleteMessageHandler(e) {
981        e.preventDefault();
982
983        sendMessage(ria_chat.state.deleteUrl, {
984            article_id: ria_chat.state.article_id,
985            message_id: $(this).data('id')
986        });
987    }
988
989    // Удалить сообщение / Модератор
990    function clickDeleteMessageModeratorHandler(e) {
991        e.preventDefault();
992
993        sendMessage(ria_chat.state.deleteModeratorUrl, {
994            article_id: ria_chat.state.article_id,
995            message_id: $(this).data('id')
996        });
997    }
998
999    // Удалить комментарий из блока Лучшие комментарии в статье
1000    function deleteBestCommentHandler(e) {
1001        var btn = $(this);
1002
1003        var data = {
1004            article_id: GLOBAL.article.id,
1005            message_id: btn.data('message_id')
1006        }
1007
1008        sendMessage(ria_chat.state.deleteModeratorUrl, data);
1009
1010        btn.closest('.best-comments__item').remove();
1011    }
1012
1013    /**
1014     * Ответить на сообщение
1015     * @param {event} e
1016     */
1017    function replyMessageHandler(e) {
1018        e.preventDefault();
1019
1020        if (GLOBAL.auth.status.toLowerCase() !== 'ok') {
1021            return;
1022        }
1023
1024        var id = $(this).data('id'),
1025            message = $('#message_' + id);
1026
1027        var data = {
1028            id: id,
1029            user: message.find('.chat__lenta-item-name-text')[0].innerText,
1030            comment: message.find('.chat__lenta-item-message-text')[0].innerText
1031        }
1032
1033        var result = ria_chat.state.replyTemplate({ data: data });
1034
1035        ria_chat.state.chat.find('.chat__reply').remove();
1036
1037        ria_chat.state.chat
1038            .find('.chat__input form')
1039            .append(result);
1040
1041        // Установить курсор в поле ввода
1042        ria_chat.state.chat.find('form textarea').focus();
1043    }
1044
1045    /**
1046     * Удалить цитируемое сообщение
1047     * @param {event} e
1048     */
1049    function removeReplyMessageHandler(e) {
1050        $(this).closest('.chat__reply').remove();
1051    }
1052
1053    /**
1054     * Лайк сообщения
1055     * @param {event} e
1056     */
1057    function clickLikeMessageHandler(e) {
1058        e.stopPropagation();
1059        e.preventDefault();
1060
1061        if (GLOBAL.auth.status !== 'ok') {
1062            return
1063        }
1064
1065        if (ria_chat.state.emoji_loading) {
1066            return;
1067        }
1068
1069        var btn = $(this);
1070
1071        var data = {
1072            article_id: ria_chat.state.article_id,
1073            message_id: btn.data('id'),
1074            emotion: btn.data('type')
1075        }
1076
1077        ria_chat.state.emoji_loading = true;
1078
1079        sendMessage(ria_chat.state.emojiUrl, data).done(function(data) {
1080            if (!data) {
1081                return
1082            }
1083
1084            data = JSON.parse(data);
1085
1086            if (data.emoji.status === 'error') {
1087                return;
1088            }
1089
1090            var result = ria_chat.state.emojiPopperTemplate({ data: {
1091                id: data.emoji.data.object_id,
1092                emotions: data.emoji.data.emotions
1093            } });
1094
1095            $('.chat__popper-emoji').html( $(result).find('.emoji') );
1096        }).always(function() {
1097            ria_chat.state.emoji_loading = false;
1098        });
1099    }
1100
1101    // Добавить реакцию в блоке лучших комментариев
1102    function clickLikeTopMessageHandler(e) {
1103        e.stopPropagation();
1104        e.preventDefault();
1105
1106        if (GLOBAL.auth.status !== 'ok') {
1107            return
1108        }
1109
1110        if (ria_chat.state.emoji_loading) {
1111            return;
1112        }
1113
1114        var btn = $(this);
1115
1116        var data = {
1117            article_id: GLOBAL.article.id,
1118            message_id: btn.data('id'),
1119            emotion: btn.data('type')
1120        }
1121
1122        ria_chat.state.emoji_loading = true;
1123
1124        sendMessage(ria_chat.state.emojiUrl, data).done(function(data) {
1125            data = JSON.parse(data);
1126
1127            if (data.emoji.status === 'error') {
1128                return;
1129            }
1130
1131            var result = ria_chat.state.emojiPopperTemplate({ data: {
1132                id: data.emoji.data.object_id,
1133                emotions: data.emoji.data.emotions
1134            } });
1135
1136            btn.closest('.emoji').replaceWith( $(result).find('.emoji') );
1137        }).always(function() {
1138            ria_chat.state.emoji_loading = false;
1139        });
1140    }
1141
1142    /**
1143     * Изменение размера окна ввода сообщения
1144     * @param {event} e
1145     */
1146    function chatAutosizeHandler(e) {
1147        var chat = $(this).closest('.chat'),
1148            chat_editor = chat.find('.chat__input-editor'),
1149            chat_textarea =  $(this),
1150            chat_admin = chat.find('.chat__input-admin');
1151
1152        setTimeout(function() {
1153            chat_textarea.css('height', 0);
1154
1155            var height = Math.min(16 * 4, chat_textarea[0].scrollHeight);
1156
1157            chat_editor.css('height', height);
1158            chat_textarea.css('height', height);
1159            ria_chat.state.chat_lenta.css('bottom', 33 + height + chat_admin.outerHeight())
1160        }, 0);
1161    }
1162
1163    // Переход по внешней ссылке
1164    function externalLinkHandler(e) {
1165        e.preventDefault();
1166
1167        modalLayer.open({
1168            customTitle: 'Переход на внешний сайт',
1169            customContent: '<div class="modal__text">Вы уверены, что хотите перейти по ссылке? <br />Выбранная Вами ссылка откроется в новом окне.</div><div class="modal__submit"><a class="form__btn" target="_blank" href="$1">Перейти по ссылке</a></div><a class="modal__button-link" data-modal-close="">Отменить</a>'.replace(/\$1/g, $(this).attr('href'))
1170        })
1171    }
1172
1173    /**
1174     * Конвертировать ссылку в сниппет
1175     * @param {Object} message Сообщение
1176     */
1177    function linkToSnippet(message) {
1178        var text = message.find('.chat__lenta-item-message-text').text().trim();
1179
1180        var expression_ria = /\b(?:https?):\/\/1prime.ru\/[a-z0-9-+&@#\/%=~_.|]*/gi;
1181        // var expression_ria = /\b(?:https?):\/\/rhel7-devel1\.rian\.off\:7298\/[a-z0-9-+&@#\/%=~_.|]*/gi;
1182        var expression = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi;
1183
1184        if (expression_ria.test(text)) {
1185            expression_ria.lastIndex = 0;
1186            var urls;
1187            while ((urls = expression_ria.exec(text)) !== null) {
1188                var url = urls[0];
1189
1190                $.ajax({
1191                    url: url,
1192                    dataType: 'html'
1193                }).done(function(response) {
1194                    if (!response.length) {
1195                        return;
1196                    }
1197
1198                    var respHtml = $(response);
1199
1200                    var data = {
1201                        title: respHtml.filter('title').text(),
1202                        img: respHtml.filter('meta[property="og:image"]').attr('content'),
1203                        url: url
1204                    }
1205
1206                    var result = ria_chat.state.snippetTemplate({ data: data });
1207
1208                    message.find('.chat__lenta-item-message-text').append(result);
1209                })
1210            }
1211        } else if (expression.test(text)){
1212            text = text.replace(expression, '<a class="m-external" href="$1" target="_blank">$1</a>');
1213            message.find('.chat__lenta-item-message-text').html(text);
1214        }
1215    }
1216
1217    // Раскрыть цитируемое сообщение
1218    function openQuoteHandler(e) {
1219        $(this).toggleClass('m-open');
1220    }
1221
1222    // Открыть попап
1223    function openPopperHandler(e) {
1224        e.stopPropagation();
1225
1226        var target = $(this),
1227            popover,
1228            container = target.closest('.popper-wrapper'),
1229            template = target.data('for'),
1230            result;
1231
1232        // Закрыть другие попапы
1233        $('.chat__popper-inner').remove();
1234
1235        result = ria_chat.state[template]({ data: {
1236            id: container.data('id'),
1237            user_id: container.data('user_id'),
1238            emotions: container.data('emotions')
1239        } });
1240
1241        $('body').append(result);
1242
1243        popover = $('.chat__popper-inner');
1244
1245        if (!popover.length) {
1246            return;
1247        }
1248
1249        // Позиционирование
1250        new Popper(target, popover, {
1251            placement: target.data('placement') || 'right',
1252            modifiers: {
1253                preventOverflow: {
1254                    enabled: true,
1255                    padding: 0,
1256                    boundariesElement: $(document).width() > 768 ? target.closest('.the-in-scroll__content') : 'window',
1257                },
1258            }
1259        });
1260
1261        popover.fadeToggle();
1262
1263        // Клик на любое место закрывает попап
1264        $('body').one('click.chat__popper-inner', function() {
1265            $('.chat__popper-inner').remove();
1266        })
1267    }
1268
1269    function updateIndicator() {
1270        if(navigator.onLine && window.console && window.console.log) {
1271            console.log('Соединение восстановлено');
1272        } else {
1273            console.log('Потеряно интернет-соединение');
1274        }
1275    }
1276
1277    /**
1278     * Поиск собеседника по никнейму
1279     * @param {event} e
1280     */
1281    function chatFindByNicknameHandler(e) {
1282        var words = $(this).val().split(" ");
1283
1284        if (/@/.test(words[words.length - 1])) {
1285            // Если список пользователей не открыт
1286            if ($('.chat__input-users').hasClass('m-open')) {
1287                return;
1288            }
1289
1290            // Открываем список пользователей
1291            $('.chat__input-users').addClass('m-open');
1292
1293            // Устанавливаем выбор на первый элемент списка
1294            $('.chat__input-users').find('.chat__input-users-item').eq(0).addClass('m-select');
1295
1296            $(document).on('keydown.arrows', function(e) {
1297                var current = $('.chat__input-users').find('.chat__input-users-item.m-select');
1298
1299                switch(e.which) {
1300                    case 38: // up
1301                    if (current.prev().length) {
1302                        current.removeClass('m-select').prev().addClass('m-select');
1303                    }
1304                    break;
1305
1306                    case 40: // down
1307                    if (current.next().length) {
1308                        current.removeClass('m-select').next().addClass('m-select');
1309                    }
1310                    break;
1311
1312                    default: return;
1313                }
1314            });
1315        } else {
1316            $('.chat__input-users').removeClass('m-open');
1317            $(document).off('keydown.arrows');
1318        }
1319    }
1320
1321    /**
1322     * Показываем тултип при наведении курсора
1323     * @param {event} e
1324     */
1325    function createTooltipHandler(e) {
1326        var that = $(this);
1327
1328        if (!$('#chatTooltip').length) {
1329            $('body').append('<div id="chatTooltip" class="chat__popper-inner" style="display: none"></div>');
1330        }
1331
1332        $('#chatTooltip').html( that.data('title') ).show();
1333
1334        new Popper(that, $('#chatTooltip'), {
1335                placement: that.data('placement') || 'top',
1336                eventsEnabled: false,
1337                modifiers: {
1338                    offset: {
1339                        enabled: true,
1340                        offset: '0, 10'
1341                    }
1342                }
1343            }
1344        );
1345    }
1346
1347    // Удалить тултип при потере фокуса
1348    function destroyTooltipHandler(e) {
1349        $('#chatTooltip').hide();
1350    }
1351
1352    // Выделить сообщение
1353    function selectMessageHandler(e) {
1354        $(this).closest('.chat__lenta-item').addClass('m-select');
1355    }
1356
1357    // Снять выделение сообщения
1358    function unselectMessageHandler(e) {
1359        $(this).closest('.chat__lenta-item').removeClass('m-select');
1360    }
1361
1362    // Заблокировать пользователя
1363    function blockUserHandler(e) {
1364        var url = '/services/chat/blacklist/add/',
1365            btn = $(this),
1366            user_id = btn.data('user_id'),
1367            comments = $('.chat__lenta-item[data-user_id="' + user_id + '"]');
1368
1369        $.ajax({
1370            url: url,
1371            data: {
1372                'blocked_user_id': user_id
1373            }
1374        }).done(function() {
1375            comments.each(function() {
1376                var comment = $(this);
1377
1378                // Добавить сообщение о блокировке
1379                comment
1380                    .addClass('m-blocked')
1381                    .find('.chat__lenta-item-message').eq(0)
1382                    .after('<div class="chat__lenta-item-message m-blocked">Вы заблокировали комментарии этого пользователя <a class="chat__actions-unblock">Разблокировать</a></div>');
1383            })
1384        })
1385    }
1386
1387    // Разблокировать пользователя
1388    function unblockUserHandler(e) {
1389        var url = '/services/chat/blacklist/remove/',
1390            btn = $(this),
1391            user_id = btn.closest('.chat__lenta-item').data('user_id'),
1392            comments = $('.chat__lenta-item[data-user_id="' + user_id + '"]');
1393
1394        $.ajax({
1395            url: url,
1396            data: {
1397                'blocked_user_id': user_id
1398            }
1399        }).done(function() {
1400            comments.each(function() {
1401                var comment = $(this);
1402
1403                // Удалить сообщение о блокировке
1404                comment
1405                    .removeClass('m-blocked')
1406                    .find('.chat__lenta-item-message.m-blocked')
1407                    .remove();
1408            })
1409        })
1410    }
1411
1412    $(function() {
1413        if (!$('#messageTemplate').length) {
1414            try {
1415                loadCustomTemplates();
1416            } catch (error) {
1417                console.log(error);
1418            }
1419        }
1420
1421        ria_chat.init({
1422            chat: $('#chat'),
1423            chat_lenta: $('#chat').find('.chat__lenta'),
1424            messageTemplate: _.template( $('#messageTemplate').html() ),
1425            replyTemplate: _.template( $('#replyTemplate').html() ),
1426            snippetTemplate: _.template( $('#snippetTemplate').html() ),
1427            alertDownTemplate: _.template( $('#alertDownTemplate').html() ),
1428            alertUnreadTemplate: _.template( $('#alertUnreadTemplate').html() ),
1429            userbarPopperTemplate: _.template( $('#userbarPopperTemplate').html() ),
1430            myuserbarPopperTemplate: _.template( $('#myuserbarPopperTemplate').html() ),
1431            emojiPopperTemplate: _.template( $('#emojiPopperTemplate').html() ),
1432            messageEmojiTemplate: _.template( $('#messageEmojiTemplate').html() )
1433        })
1434
1435        var wrapper = $('body');
1436
1437        // Submit формы ввода комментария
1438        wrapper.on('submit', '.chat__form', submitMessageFormHandler);
1439
1440        wrapper.on('input', '.chat__form', inputMessageFormHandler);
1441
1442        // Обработка нажатия Enter
1443        wrapper.on('keypress', '.chat__form-textarea', submitMessageFormByEnterHandler);
1444
1445        // Пожаловаться на сообщение
1446        wrapper.on('click', '.chat__actions-report', clickReportMessageHandler);
1447
1448        // Удалить сообщение
1449        wrapper.on('click', '.chat__actions-delete', clickDeleteMessageHandler);
1450
1451        // Удалить сообщение / Модератор
1452        wrapper.on('click', '.chat__actions-delete-moderator', clickDeleteMessageModeratorHandler);
1453
1454        // Лайк сообщения
1455        wrapper.on('click', '.chat__popper-emoji .emoji-item', clickLikeMessageHandler);
1456
1457        // Ответить на сообщение
1458        wrapper.on('click', '.chat__lenta-item-message-reply', replyMessageHandler);
1459
1460        wrapper.on('dblclick', '.chat__lenta-item-message', function() {
1461            $(this)
1462                .closest('.chat__lenta-item')
1463                .find('.chat__lenta-item-message-reply')
1464                .trigger('click');
1465        });
1466
1467        // Удалить цитируемое сообщение
1468        wrapper.on('click', '.chat__reply-remove', removeReplyMessageHandler);
1469
1470        // Выделить сообщение
1471        // wrapper.on('click', '.chat__lenta-item-select .m-add', selectMessageHandler);
1472
1473        // Снять выделение сообщения
1474        // wrapper.on('click', '.chat__lenta-item-select .m-remove', unselectMessageHandler);
1475
1476        // Показываем тултип при наведении
1477        // wrapper.on('mouseenter', '.chat .popper:visible', createTooltipHandler);
1478
1479        // Удалить тултип при потере фокуса
1480        // wrapper.on('mouseleave', '.chat .popper', destroyTooltipHandler);
1481
1482        // Скролл вниз
1483        wrapper.on('click', '.chat__alert-down', clickScrollDownHandler);
1484
1485        // Скролл вверх
1486        wrapper.on('click', '.chat__alert-top', clickScrollTopHandler);
1487
1488        // Изменение размера окна ввода сообщения
1489        wrapper.on('input change paste keyup mouseup', '.chat__form-textarea', chatAutosizeHandler);
1490
1491        // Поиск собеседника по никнейму
1492        // wrapper.on('keyup', '.chat__form-textarea', chatFindByNicknameHandler);
1493
1494        // Переход по внешней ссылке
1495        wrapper.on('click', '.chat a.m-external', externalLinkHandler);
1496
1497        // Раскрыть цитируемое сообщение
1498        wrapper.on('click', '.chat__lenta-quote', openQuoteHandler)
1499
1500        // window.addEventListener('offline', updateIndicator);
1501        // window.addEventListener('online', updateIndicator);
1502
1503        // Удалить комментарий из блока Лучшие комментарии в статье
1504        wrapper.on('click', '.best-comments__item-message-moderation .m-delete', deleteBestCommentHandler);
1505
1506        // Добавить реакцию в блоке лучших комментариев
1507        wrapper.on('click', '.best__popper-emoji .emoji-item', clickLikeTopMessageHandler)
1508
1509        // Открыть попап
1510        wrapper.on('click', '.popper-btn', openPopperHandler);
1511
1512        // Заблокировать пользователя
1513        wrapper.on('click', '.chat__actions-block', blockUserHandler);
1514
1515        // Разблокировать пользователя
1516        wrapper.on('click', '.chat__actions-unblock', unblockUserHandler);
1517    });
1518})()

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.