PageSourceSearch

https://xn----dtbfdbwspgnceulm.xn--p1ai/js/chat_s10.js

js xn----dtbfdbwspgnceulm.xn--p1ai collected 2026-10-06 02:17:28 UTC 21,119 bytes, 550 lines download raw bytes

1$(document).ready(function(){
2
3    // Запускаем метод init, когда документ будет готов:
4    chat.init();
5
6});
7
8var chat = {
9
10    // data содержит переменные для использования в классах:
11    data : {
12        lastID 			: 0,
13        noActivity		: 0,
14        userInteracted 	: false,
15        pageLoaded      : false, // флаг загрузки страницы
16        toastAlways     : true  // true - тост при КАЖДОЙ новости, false - умная логика
17    },
18
19    // Init привязывает обработчики событий и устанавливает таймеры:
20    init : function(){
21
22        // Используем плагин jQuery defaultText, включенный внизу:
23        $('#name').defaultText('Укажите Ваше имя');
24        $('#email').defaultText('');
25
26        // Сохраняем ссылку на контейнер
27        chat.data.container = $('#chatLineHolder');
28        
29        // Добавляем класс для скролла
30        chat.data.container.addClass('native-scroll');
31
32        // Отслеживаем взаимодействие пользователя со скроллом
33        chat.data.container.on('scroll', function() {
34            chat.data.userInteracted = true;
35        });
36
37        // Используем переменную working для предотвращения
38        // множественных отправок формы:
39        var working = false;
40
41        // Регистрируем персону в чате:
42        $('#loginForm').submit(function(){
43
44            if(working) return false;
45            working = true;
46
47            $.tzPOST('login',$(this).serialize(),function(r){
48                working = false;
49
50                if(r.error){
51                    chat.displayError(r.error);
52                }
53                else chat.login(r.name,r.gravatar);
54            });
55
56            return false;
57        });
58		
59        // Отправляем данные новой строки чата:
60        $('#submitForm').submit(function(){
61
62            var text = $('#chatText').val();
63
64            if(text.length == 0){
65                return false;
66            }
67
68            if(working) return false;
69            working = true;
70
71            // Генерируем временный ID для чата:
72            var tempID = 't'+Math.round(Math.random()*1000000),
73                params = {
74                    id			: tempID,
75                    author		: chat.data.name,
76                    text		: text.replace(/</g,'&lt;').replace(/>/g,'&gt;'),
77                    ip		    : chat.data.ip
78                };
79
80            // Добавляем временное сообщение в КОНЕЦ контейнера
81            chat.addChatLine($.extend({},params), true);
82
83            $.tzPOST('submitChat',$(this).serialize(),function(r){
84                working = false;
85
86                $('#chatText').val('');
87                $('div.chat-'+tempID).remove();
88
89                params['id'] = r.insertID;
90                // Добавляем постоянное сообщение в КОНЕЦ контейнера
91                chat.addChatLine($.extend({},params), false);
92            });
93
94            return false;
95        });
96
97        // Отключаем пользователя:
98        $('#chatContainer').on('click', '.logoutButton', function(){
99
100            $('#chatTopBar > span').fadeOut(function(){
101                $(this).remove();
102            });
103
104            $('#submitForm').fadeOut(function(){
105                $('#loginForm').fadeIn();
106            });
107
108            $.tzPOST('logout');
109
110            return false;
111        });
112
113        // Проверяем состояние подключения пользователя
114        $.tzGET('checkLogged',function(r){
115            if(r.logged){
116                chat.login(r.loggedAs.name,r.loggedAs.gravatar);
117            }
118        });
119
120        // Запускаем получение новых сообщений
121        (function getChatsTimeoutFunction(){
122            chat.getChats(getChatsTimeoutFunction);
123        })();
124
125    },
126
127    login : function(name){
128
129        chat.data.name = name;
130        $('#chatTopBar').html(chat.render('loginTopBar',chat.data));
131
132        $('#loginForm').fadeOut(function(){
133            $('#submitForm').fadeIn();
134            $('#chatText');
135        });
136
137    },
138
139// Метод для публикации новости через Web Share API
140shareNews: function(text, url, fullText) {
141    if (typeof ym !== 'undefined') {
142        ym('24810671', 'reachGoal', 'share_news');
143    }
144    // Декодируем текст для отображения
145    var decodedText = decodeURIComponent(text);
146    var decodedUrl = decodeURIComponent(url);
147    var decodedFullText = fullText ? decodeURIComponent(fullText) : decodedText;
148    
149    // Добавляем параметр share=news к URL
150    var shareUrl = decodedUrl;
151    if (shareUrl.indexOf('?') === -1) {
152        shareUrl += '?share=news';
153    } else {
154        shareUrl += '&share=news';
155    }
156    
157    // Формируем единый текст для отправки
158    var shareText = decodedFullText + '\n\n' + shareUrl;
159    
160    // Используем Web Share API
161    if (navigator.share) {
162        navigator.share({
163            title: 'Новость',
164            text: shareText
165        })
166        .catch(function(error) {
167            console.log('Поделиться отменено или ошибка:', error);
168        });
169    } else {
170        alert('Поделиться через соцсети можно скопировав ссылку из адресной строки');
171    }
172},
173
174    // Метод для показа подсказки
175    showNewMessageToast: function() {
176        // Проверяем, есть ли уже тост
177        if ($('#new-message-toast').length > 0) return;
178        
179        // Определяем мобильное устройство
180        var isMobile = window.innerWidth <= 768;
181        
182        var toast = $('<div>', {
183            id: 'new-message-toast',
184            html: 'Новая новость ↓',
185            css: {
186                position: 'fixed',
187                bottom: isMobile ? '60px' : '40px',
188                left: '50%',
189                transform: 'translateX(-50%)',
190                background: '#6EB238',
191                color: 'white',
192                padding: isMobile ? '18px 28px' : '10px 12px',
193                borderRadius: '30px',
194                boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
195                cursor: 'pointer',
196                zIndex: 9999,
197                fontSize: isMobile ? '21px' : '16px',
198                fontWeight: isMobile ? '700' : '400', 
199                animation: 'slideUp 0.3s ease',
200                border: '2px solid rgba(255,255,255,0.3)',
201                width: isMobile ? 'auto' : 'auto',
202                minWidth: isMobile ? '200px' : '150px',
203                textAlign: 'center',
204                letterSpacing: '0.5px'
205            }
206        });
207        
208        toast.click(function() {
209            if (typeof ym !== 'undefined') {
210                // Замените 'toast_click' на название вашей цели
211                ym('24810671', 'reachGoal', 'toast_click');
212            }
213            // Помечаем что пользователь взаимодействовал (через клик по тосту)
214            chat.data.userInteracted = true;
215            
216            var containerOffset = $('#chatContainer').offset().top;
217            var windowHeight = $(window).height();
218            var containerHeight = $('#chatContainer').height();
219            
220            var isMobile = window.innerWidth <= 768;
221            var targetScroll;
222            
223            if (isMobile) {
224                targetScroll = containerOffset - 10;
225            } else {
226                targetScroll = containerOffset + containerHeight - windowHeight + 50;
227            }
228            
229            $('html, body').animate({
230                scrollTop: targetScroll
231            }, 500, function() {
232                setTimeout(function() {
233                    chat.scrollToBottom();
234                }, 100);
235            });
236            
237            toast.fadeOut(300, function() { $(this).remove(); });
238        });
239        
240        $('body').append(toast);
241        
242        // Автоматически скрываем через 7 секунд
243        setTimeout(function() {
244            toast.fadeOut(300, function() { $(this).remove(); });
245        }, 7000);
246    },
247
248render : function(template,params){
249    var arr = [];
250    switch(template){
251        case 'chatLine':
252            // ===== 1. Выделяем цифры =====
253            var textWithNumbers = params.text.replace(/(\d+[\d\s]*[%₽$€]?)/g, '<b>$1</b>');
254            
255            // ===== 2. Рандомное количество слов от 3 до 7 =====
256            var words = textWithNumbers.split(' ');
257            var formattedText = textWithNumbers;
258            
259            // Генерируем случайное число от 3 до 7
260            var randomWords = Math.floor(Math.random() * 5) + 3; // 3,4,5,6,7
261            
262            if (words.length >= randomWords) {
263                var firstPart = words.slice(0, randomWords).join(' ');
264                var rest = words.slice(randomWords).join(' ');
265                formattedText = '<b style="color:#0000009e;">' + firstPart + '</b> ' + rest;
266            } else {
267                formattedText = '<b style="color:#0000009e;">' + textWithNumbers + '</b>';
268            }
269            
270            // ===== 3. Цвет точки в зависимости от автора =====
271            var dotColor = '#6EB238'; // зеленый по умолчанию
272            
273            if (params.author === 'Срочные новости' || 
274                params.author === 'СРОЧНЫЕ НОВОСТИ' || 
275                (params.author && params.author.toLowerCase().includes('срочн'))) {
276                dotColor = '#e44139'; // красный
277            }
278            
279            // ===== 4. Кнопка поделиться (будет видна только на мобильных) =====
280            var shareText = encodeURIComponent(params.text.substring(0, 100) + (params.text.length > 100 ? '...' : ''));
281            var fullText = encodeURIComponent(params.text);
282            var currentUrl = encodeURIComponent('https://форум-трейдеров.рф/chart-online.php');
283            
284            var shareButton = `
285                <div class="share-button" onclick="event.stopPropagation(); chat.shareNews('${shareText}', '${currentUrl}', '${fullText}')">
286                    <svg style="filter: drop-shadow(0 1px 1px rgba(0,0,0,0.2));" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
287                        <path d="M13.52,7.17V2.91a0.63,0.63,0,0,1,1-.51l9.22,7.46a0.61,0.61,0,0,1,0,1L14.5,18.34a0.63,0.63,0,0,1-1-.51V13.88c-5.76,0-10.65,2.57-12.44,7a11.29,11.29,0,0,1-.16-1.82C0.91,12.5,6.55,7.17,13.52,7.17Z" fill="#6EB238"/>
288
289                    </svg>
290                </div>
291            `;
292            
293            arr = [
294                '<div class="chat chat-',params.id,' rounded" data-news-id="',params.id,'">',
295                '<span class="text">',
296                '<style>.chat-',params.id,' .author::before { background: ',dotColor,' !important; }</style>',
297                formattedText,
298                '</span>',
299                '<span class="author">',
300                '<span style="color:#64748bab;">',params.time,'</span> ',
301                '<b style="display:none;"><a class="dropdown-top" style="color: #469e00e0;" title="" href="javascript:void(0)" onclick="getText_author(this)">',params.author,'</a></b>',
302                '</span>',
303                shareButton,
304                '</div>'
305            ];
306            break;
307    }
308    return arr.join('');
309},
310
311    // Метод addChatLine добавляет строку чата на страницу
312    addChatLine : function(params, isTemp){
313
314        // Все показания времени выводятся в формате временного пояса пользователя
315        var d = new Date();
316        if(params.time) {
317            d.setUTCHours(params.time.hours,params.time.minutes);
318        }
319
320        params.time = (d.getHours() < 10 ? '0' : '' ) + d.getHours()+':'+
321            (d.getMinutes() < 10 ? '0':'') + d.getMinutes();
322
323        var markup = chat.render('chatLine',params),
324            exists = $('#chatLineHolder .chat-'+params.id);
325
326        if(exists.length){
327            exists.remove();
328        }
329
330        if(!chat.data.lastID){
331            // Если это первая запись в чате, удаляем
332            // параграф с сообщением о том, что еще ничего не написано:
333            $('#chatLineHolder p').remove();
334        }
335
336        // Добавляем новость в КОНЕЦ контейнера (append)
337        if (params.id.toString().charAt(0) != 't') {
338            // Для постоянных сообщений добавляем с анимацией
339            var $newElement = $(markup).hide().fadeIn(1500);
340            chat.data.container.append($newElement);
341            
342            // Проверяем, видно ли последнее сообщение
343            var container = chat.data.container[0];
344            
345            // Вычисляем, видно ли последнее сообщение (с погрешностью 100px)
346            var scrollPosition = container.scrollTop + container.clientHeight;
347            var totalHeight = container.scrollHeight;
348            var isAtBottom = (totalHeight - scrollPosition < 100);
349            
350            // ===== ИСПРАВЛЕННАЯ ЛОГИКА =====
351            // Если это первая загрузка страницы
352            if (!chat.data.pageLoaded) {
353                // Просто скроллим вниз, тост НЕ показываем
354                chat.scrollToBottom();
355            }
356            // Если включен режим "всегда показывать тост"
357            else if (chat.data.toastAlways) {
358                // Показываем тост при каждой новой новости (кроме первой загрузки)
359                chat.showNewMessageToast();
360            } 
361            // Иначе работаем по обычной логике
362            else if (chat.data.userInteracted) {
363                if (!isAtBottom) { // если не внизу
364                    chat.showNewMessageToast();
365                } else { // если внизу
366                    chat.scrollToBottom();
367                }
368            } else {
369                // Первое взаимодействие после загрузки
370                chat.scrollToBottom();
371            }
372            // ================================
373            
374        } else {
375            // Для временных добавляем сразу
376            chat.data.container.append(markup);
377            chat.scrollToBottom();
378        }
379
380        // Обновляем lastID если это постоянное сообщение
381        if(params.id.toString().charAt(0) != 't' && params.id > chat.data.lastID){
382            chat.data.lastID = params.id;
383        }
384
385    },
386
387    // Метод для скролла вниз
388    scrollToBottom: function() {
389        var container = chat.data.container[0];
390        container.scrollTop = container.scrollHeight;
391    },
392
393    // Данный метод запрашивает последнюю запись в чате
394    getChats : function(callback){
395        $.tzGET('getChats',{lastID: chat.data.lastID},function(r){
396
397            // Сохраняем позицию скролла
398            var container = chat.data.container[0];
399            var wasAtBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 50;
400            
401            for(var i=0;i<r.chats.length;i++){
402                chat.addChatLine(r.chats[i], false);
403            }
404
405            if(r.chats.length){
406                chat.data.noActivity = 0;
407                chat.data.lastID = r.chats[i-1].id;
408                
409                // Если пользователь был внизу, остаемся внизу
410                if (wasAtBottom) {
411                    chat.scrollToBottom();
412                }
413            }
414            else{
415                chat.data.noActivity++;
416            }
417
418            if(!chat.data.lastID){
419                chat.data.container.html('<p class="noChats">Чат очищен модератором, пожалуйста соблюдайте правила общения<br></br><b>Приятного общения! Напишите сообщение и будьте первым!</b> <br><br><img src="/img/img18.jpg"></p>');
420            }
421            
422            // Устанавливаем флаг, что страница загружена
423            chat.data.pageLoaded = true;
424
425            var nextRequest = 15000;
426
427            if(chat.data.noActivity > 8){
428                nextRequest = 60000;
429            }
430
431            if(chat.data.noActivity > 40){
432                nextRequest = 120000;
433            }
434
435            setTimeout(callback,nextRequest);
436        });
437    },
438
439    displayError : function(msg){
440        var elem = $('<div>',{
441            id		: 'chatErrorMessage',
442            html	: msg
443        });
444
445        elem.click(function(){
446            $(this).fadeOut(function(){
447                $(this).remove();
448            });
449        });
450
451        setTimeout(function(){
452            elem.click();
453        },10000);
454
455        elem.hide().appendTo('body').slideDown();
456    }
457};
458
459// Формирование GET & POST:
460$.tzPOST = function(action,data,callback){
461    $.post('php/post.php?action='+action,data,callback,'json');
462}
463
464$.tzGET = function(action,data,callback){
465    $.get('php/ajax.php?action='+action,data,callback,'json');
466}
467
468// Метод jQuery для замещающего текста:
469$.fn.defaultText = function(value){
470
471    var element = this.eq(0);
472    element.data('defaultText',value);
473
474    element.focus(function(){
475        if(element.val() == value){
476            element.val('').removeClass('defaultText');
477        }
478    }).blur(function(){
479        if(element.val() == '' || element.val() == value){
480            element.addClass('defaultText').val(value);
481        }
482    });
483
484    return element.blur();
485}
486
487// Добавляем CSS для тоста и кнопки поделиться
488// Добавляем CSS для тоста и кнопки поделиться
489// Добавляем CSS для тоста и кнопки поделиться
490if (!$('#toast-styles').length) {
491    $('<style id="toast-styles">')
492        .text(`
493            @keyframes slideUp { 
494                from { opacity:0; transform:translate(-50%,20px); } 
495                to { opacity:1; transform:translate(-50%,0); } 
496            } 
497            #new-message-toast:hover { 
498                background:#5a9a2c; 
499            }
500						.share-button {
501				display: none;
502			}
503            
504            /* Только для мобильных устройств */
505            @media only screen and (max-width: 768px) {
506                .chat {
507                    position: relative;
508                    padding-bottom: 20px;
509                    -webkit-tap-highlight-color: transparent;
510                }
511                
512                .share-button {
513                    position: absolute;
514                    bottom: 20px;
515                    right: 20px;
516                    width: 40px;
517                    height: 40px;
518                    border-radius: 50%;
519                    background: #fff;
520                    display: flex;
521                    align-items: center;
522                    justify-content: center;
523                    cursor: pointer;
524                  /*  box-shadow: 0 6px 10px rgba(0,0,0,0.4); */
525                    z-index: 10;
526                    transition: transform 0.2s ease;
527                    opacity: 0;
528                    visibility: hidden;
529                    pointer-events: none;
530                }
531                
532                .chat:hover .share-button {
533                    opacity: 1;
534                    visibility: visible;
535                    pointer-events: auto;
536                }
537                
538                .share-button:hover {
539                    transform: scale(1.1);
540                }
541                
542                .share-button svg {
543                    width: 28px;
544                    height: 28px;
545					shadow: 0 2px 8px rgba(0,0,0,0.2);
546                }
547            }
548        `)
549        .appendTo('head');
550}

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.