Telegram Message Preview on Hover

Shows full message content when hovering over contacts in the chat list

Size

7.6 KB

Version

1.0.1

Created

Jan 8, 2026

Updated

14 days ago

1// ==UserScript==
2// @name		Telegram Message Preview on Hover
3// @description		Shows full message content when hovering over contacts in the chat list
4// @version		1.0.1
5// @match		https://*.web.telegram.org/*
6// @icon		https://web.telegram.org/a/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Telegram Message Preview on Hover - Extension loaded');
12
13    // Add styles for the tooltip
14    TM_addStyle(`
15        .telegram-message-tooltip {
16            position: fixed;
17            background: rgba(0, 0, 0, 0.95);
18            color: #ffffff;
19            padding: 12px 16px;
20            border-radius: 8px;
21            max-width: 400px;
22            font-size: 14px;
23            line-height: 1.5;
24            z-index: 10000;
25            pointer-events: none;
26            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
27            word-wrap: break-word;
28            white-space: pre-wrap;
29            opacity: 0;
30            transition: opacity 0.2s ease-in-out;
31        }
32
33        .telegram-message-tooltip.visible {
34            opacity: 1;
35        }
36
37        .telegram-message-tooltip .tooltip-header {
38            font-weight: bold;
39            margin-bottom: 8px;
40            padding-bottom: 8px;
41            border-bottom: 1px solid rgba(255, 255, 255, 0.2);
42            color: #8ab4f8;
43        }
44
45        .telegram-message-tooltip .tooltip-content {
46            color: #e8eaed;
47        }
48    `);
49
50    let tooltip = null;
51    let currentHoveredElement = null;
52    let showTimeout = null;
53
54    // Create tooltip element
55    function createTooltip() {
56        if (tooltip) return tooltip;
57        
58        tooltip = document.createElement('div');
59        tooltip.className = 'telegram-message-tooltip';
60        document.body.appendChild(tooltip);
61        console.log('Tooltip element created');
62        return tooltip;
63    }
64
65    // Get message content from chat item
66    function getMessageContent(chatItem) {
67        try {
68            // Find the last message summary
69            const messageSummary = chatItem.querySelector('.last-message-summary');
70            if (!messageSummary) {
71                console.log('No message summary found');
72                return null;
73            }
74
75            // Get the text content, excluding media preview labels
76            let messageText = '';
77            const textNodes = [];
78            
79            // Walk through all text nodes
80            const walker = document.createTreeWalker(
81                messageSummary,
82                NodeFilter.SHOW_TEXT,
83                null,
84                false
85            );
86
87            let node;
88            while (node = walker.nextNode()) {
89                const text = node.textContent.trim();
90                if (text) {
91                    textNodes.push(text);
92                }
93            }
94
95            messageText = textNodes.join(' ');
96
97            // Get chat name
98            const chatName = chatItem.querySelector('.fullName')?.textContent || 'Unknown';
99
100            console.log('Extracted message:', messageText.substring(0, 50) + '...');
101            
102            return {
103                chatName: chatName,
104                message: messageText
105            };
106        } catch (error) {
107            console.error('Error extracting message content:', error);
108            return null;
109        }
110    }
111
112    // Position tooltip near cursor
113    function positionTooltip(event) {
114        if (!tooltip) return;
115
116        const padding = 15;
117        const tooltipRect = tooltip.getBoundingClientRect();
118        let x = event.clientX + padding;
119        let y = event.clientY + padding;
120
121        // Adjust if tooltip goes off screen
122        if (x + tooltipRect.width > window.innerWidth) {
123            x = event.clientX - tooltipRect.width - padding;
124        }
125        if (y + tooltipRect.height > window.innerHeight) {
126            y = event.clientY - tooltipRect.height - padding;
127        }
128
129        tooltip.style.left = x + 'px';
130        tooltip.style.top = y + 'px';
131    }
132
133    // Show tooltip
134    function showTooltip(chatItem, event) {
135        const content = getMessageContent(chatItem);
136        if (!content || !content.message) {
137            console.log('No content to show');
138            return;
139        }
140
141        createTooltip();
142        
143        tooltip.innerHTML = `
144            <div class="tooltip-header">${content.chatName}</div>
145            <div class="tooltip-content">${content.message}</div>
146        `;
147
148        positionTooltip(event);
149        
150        // Show tooltip with slight delay
151        setTimeout(() => {
152            if (tooltip && currentHoveredElement === chatItem) {
153                tooltip.classList.add('visible');
154            }
155        }, 50);
156    }
157
158    // Hide tooltip
159    function hideTooltip() {
160        if (tooltip) {
161            tooltip.classList.remove('visible');
162        }
163        currentHoveredElement = null;
164        if (showTimeout) {
165            clearTimeout(showTimeout);
166            showTimeout = null;
167        }
168    }
169
170    // Handle mouse enter on chat item
171    function handleMouseEnter(event) {
172        const chatItem = event.currentTarget;
173        currentHoveredElement = chatItem;
174        
175        // Show tooltip after a short delay
176        showTimeout = setTimeout(() => {
177            if (currentHoveredElement === chatItem) {
178                showTooltip(chatItem, event);
179            }
180        }, 300);
181    }
182
183    // Handle mouse move to update tooltip position
184    function handleMouseMove(event) {
185        if (tooltip && tooltip.classList.contains('visible')) {
186            positionTooltip(event);
187        }
188    }
189
190    // Handle mouse leave
191    function handleMouseLeave() {
192        hideTooltip();
193    }
194
195    // Attach event listeners to chat items
196    function attachListeners() {
197        const chatItems = document.querySelectorAll('.ListItem.Chat');
198        console.log(`Found ${chatItems.length} chat items`);
199
200        chatItems.forEach(chatItem => {
201            // Check if already has listeners
202            if (chatItem.dataset.tooltipAttached) return;
203            
204            chatItem.addEventListener('mouseenter', handleMouseEnter);
205            chatItem.addEventListener('mousemove', handleMouseMove);
206            chatItem.addEventListener('mouseleave', handleMouseLeave);
207            chatItem.dataset.tooltipAttached = 'true';
208        });
209    }
210
211    // Debounce function
212    function debounce(func, wait) {
213        let timeout;
214        return function executedFunction(...args) {
215            const later = () => {
216                clearTimeout(timeout);
217                func(...args);
218            };
219            clearTimeout(timeout);
220            timeout = setTimeout(later, wait);
221        };
222    }
223
224    // Observe DOM changes to handle dynamically loaded chats
225    function observeChatList() {
226        const chatListContainer = document.querySelector('.chat-list');
227        if (!chatListContainer) {
228            console.log('Chat list container not found, retrying...');
229            setTimeout(observeChatList, 1000);
230            return;
231        }
232
233        console.log('Chat list container found, setting up observer');
234
235        const debouncedAttach = debounce(attachListeners, 500);
236
237        const observer = new MutationObserver(debouncedAttach);
238        observer.observe(chatListContainer, {
239            childList: true,
240            subtree: true
241        });
242
243        // Initial attachment
244        attachListeners();
245    }
246
247    // Initialize
248    function init() {
249        console.log('Initializing Telegram Message Preview extension');
250        
251        TM_runBody(() => {
252            // Wait for chat list to load
253            setTimeout(() => {
254                observeChatList();
255            }, 1000);
256        });
257    }
258
259    init();
260})();
Telegram Message Preview on Hover | Robomonkey