המלצה | סקריפט לטמפרמונקי לשיפור נוחות השימוש בפורום!
-
אחרי הרבה עבודה...
// ==UserScript== // @name Mitmachim Forum Ultimate Enhancements // @namespace http://tampermonkey.net/ // @version 4.9 // @description החזרת מנגנון ההזרקה המדויק של גרסה 3.4, שילוב צ'אט אוטומטי ותצוגה מקדימה // @author ישראל מאיר שגיב & Gemini // @match https://mitmachim.top/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @connect mitmachim.top // @connect otzaria.org // @unsafeWindow // @run-at document-end // ==/UserScript== (function() { 'use strict'; function getForumBaseUrl() { const relativePath = (unsafeWindow.config && unsafeWindow.config.relative_path) || ''; return window.location.origin + relativePath; } // ========================================== // חלק א': יצירת הפופאפ המשותף // ========================================== const sharedPopup = document.createElement('div'); Object.assign(sharedPopup.style, { position: 'fixed', backgroundColor: '#ffffff', border: '1px solid #e2e8f0', borderRadius: '12px', padding: '16px', boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)', zIndex: '10005', display: 'none', width: '420px', maxHeight: '450px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.6', color: '#1e293b', fontFamily: 'system-ui, -apple-system, sans-serif' }); document.body.appendChild(sharedPopup); sharedPopup.addEventListener('click', (e) => e.stopPropagation()); document.addEventListener('click', () => { sharedPopup.style.display = 'none'; }); function positionPopup(anchorElement) { const rect = anchorElement.getBoundingClientRect(); sharedPopup.style.left = `${rect.right + 15}px`; sharedPopup.style.top = `${Math.min(rect.top, window.innerHeight - 460)}px`; sharedPopup.style.display = 'block'; } // --- פופאפ לקריאה בהמשך (פוסטים) --- function openReadLaterPopup(anchorElement) { positionPopup(anchorElement); const savedList = GM_getValue('saved_to_read_data', []); if (savedList.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">רשימת קריאה בהמשך (${savedList.length})</h4><div id="popup-items-container"></div>`; const container = sharedPopup.querySelector('#popup-items-container'); savedList.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/post/${item.pid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#2563eb; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${item.title}</a> <button class="delete-saved-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:11px; color:#64748b; margin-bottom:4px;">נכתב על ידי: <strong>${item.author}</strong></div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-saved-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentList = GM_getValue('saved_to_read_data', []); currentList = currentList.filter(x => x.pid !== item.pid); GM_setValue('saved_to_read_data', currentList); itemWrapper.remove(); updateBadgesAndCounters(); if (currentList.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; }); container.appendChild(itemWrapper); }); } // --- פופאפ סימניות שלי (נושאים) --- function openBookmarksPopup(anchorElement) { positionPopup(anchorElement); const savedTopics = GM_getValue('saved_topics_data', []); if (savedTopics.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">הסימניות שלי - נושאים (${savedTopics.length})</h4><div id="popup-topics-container"></div>`; const container = sharedPopup.querySelector('#popup-topics-container'); savedTopics.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/topic/${item.tid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#0284c7; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"><i class="fa fa-folder-open-o"></i> ${item.title}</a> <button class="delete-topic-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-topic-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentTopics = GM_getValue('saved_topics_data', []); currentTopics = currentTopics.filter(x => x.tid !== item.tid); GM_setValue('saved_topics_data', currentTopics); itemWrapper.remove(); updateBadgesAndCounters(); if (currentTopics.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; }); container.appendChild(itemWrapper); }); } // ========================================== // חלק ב': עדכון בועות מספרים (Badges) דינמי // ========================================== function updateBadgesAndCounters() { const readLaterCount = GM_getValue('saved_to_read_data', []).length; const bookmarksCount = GM_getValue('saved_topics_data', []).length; const rlBadge = document.getElementById('rl-count-badge'); if (rlBadge) { rlBadge.textContent = readLaterCount; rlBadge.style.display = readLaterCount > 0 ? 'inline-block' : 'none'; } const bmBadge = document.getElementById('bm-count-badge'); if (bmBadge) { bmBadge.textContent = bookmarksCount; bmBadge.style.display = bookmarksCount > 0 ? 'inline-block' : 'none'; } } // ========================================== // חלק ג': שילוב מושלם וחסין בסרגל השמאלי (מגרסה 3.4) // ========================================== function integrateIntoLeftSidebar() { const lists = document.querySelectorAll('#main-nav, .sidebar-nav, [component^="sidebar/"] ul, .nav-list, #menu, #user-control-list'); let leftSidebarNav = null; lists.forEach(el => { const rect = el.getBoundingClientRect(); if (rect.width > 0 && rect.left < window.innerWidth / 2) { leftSidebarNav = el; } }); if (!leftSidebarNav) return; if (!document.getElementById('custom-sidebar-styles')) { const style = document.createElement('style'); style.id = 'custom-sidebar-styles'; style.innerHTML = ` .custom-sidebar-item .nav-text { display: none; margin-right: 10px; } html.sidebar-left-open .custom-sidebar-item .nav-text, body.sidebar-left-open .custom-sidebar-item .nav-text, .sidebar-open .custom-sidebar-item .nav-text, .open .custom-sidebar-item .nav-text, #sidebar-left.open .custom-sidebar-item .nav-text { display: inline-block !important; } .custom-badge { position: absolute; top: 2px; left: 5px; background-color: #ef4444; color: white; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 10px; min-width: 18px; text-align: center; line-height: 1; box-shadow: 0 1px 3px rgba(0,0,0,0.2); } .custom-sidebar-item a { position: relative; } `; document.head.appendChild(style); } if (!document.getElementById('integrated-to-read-li')) { const li = document.createElement('li'); li.id = 'integrated-to-read-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="לקריאה בהמשך" style="cursor:pointer; display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-list-alt"></i> <span class="nav-text">לקריאה בהמשך</span> <span id="rl-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openReadLaterPopup(li); }, true); leftSidebarNav.appendChild(li); } if (!document.getElementById('integrated-bookmarks-li')) { const li = document.createElement('li'); li.id = 'integrated-bookmarks-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="הסימניות שלי" style="display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-bookmark"></i> <span class="nav-text">הסימניות שלי</span> <span id="bm-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openBookmarksPopup(li); }, true); leftSidebarNav.appendChild(li); } updateBadgesAndCounters(); } // ========================================== // חלק ד': הזרקת כפתור סימנייה לסרגל הכלים הראשי של הנושא // ========================================== function enhanceTopicHeaderTools() { if (document.getElementById('top-bar-save-topic-btn')) return; const currentTid = (unsafeWindow.ajaxify && unsafeWindow.ajaxify.data && unsafeWindow.ajaxify.data.tid) || null; if (!currentTid) return; const exportBtn = document.querySelector('.fa-download')?.closest('a, button'); if (!exportBtn) return; const parentContainer = exportBtn.parentElement; if (!parentContainer) return; const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; const topicBtn = document.createElement('button'); topicBtn.id = 'top-bar-save-topic-btn'; topicBtn.className = exportBtn.className || 'btn btn-sm btn-link text-secondary text-body'; topicBtn.style.cssText = 'cursor: pointer; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; background: none; border: none; margin-left: 12px;'; let savedTopics = GM_getValue('saved_topics_data', []); const isTopicSaved = savedTopics.some(x => x.tid === currentTid); topicBtn.innerHTML = `<i class="fa ${isTopicSaved ? 'fa-folder' : 'fa-folder-o'}"></i> <span>שמור כסימניה</span>`; topicBtn.addEventListener('click', (e) => { e.preventDefault(); let currentTopics = GM_getValue('saved_topics_data', []); const icon = topicBtn.querySelector('i'); if (currentTopics.some(x => x.tid === currentTid)) { currentTopics = currentTopics.filter(x => x.tid !== currentTid); icon.className = 'fa fa-folder-o'; } else { const firstPostEl = document.querySelector('[component="post"] .content, [component="post/content"]'); let snippet = firstPostEl ? firstPostEl.textContent.trim().substring(0, 120) : 'לחץ למעבר לצפייה בנושא המלא...'; if (snippet.length >= 120) snippet += '...'; currentTopics.push({ tid: currentTid, title: topicTitle, snippet: snippet }); icon.className = 'fa fa-folder'; } GM_setValue('saved_topics_data', currentTopics); updateBadgesAndCounters(); }); parentContainer.insertBefore(topicBtn, exportBtn); } // ========================================== // חלק ה': הזרקת כפתורים לפוסטים (צ'אט אוטומטי מלא) // ========================================== function enhancePosts() { const posts = document.querySelectorAll('[component="post"]:not(.enhanced-post)'); const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; posts.forEach(post => { post.classList.add('enhanced-post'); const tools = post.querySelector('.post-tools, [component="post/tools"], [component="post/actions"]'); if (!tools) return; const pid = post.getAttribute('data-pid'); const postUid = post.getAttribute('data-uid'); const authorName = post.getAttribute('data-username') || 'משתמש'; const currentUid = (unsafeWindow.app && unsafeWindow.app.user) ? unsafeWindow.app.user.uid : null; // 1. כפתור צ'אט אוטומטי חסין (הדמיית Mouseenter והזרקת קישור) if (postUid && currentUid && Array.of(0, currentUid).includes(Number(postUid)) === false && !tools.querySelector('.custom-chat-btn')) { const chatBtn = document.createElement('a'); chatBtn.className = 'btn btn-xs btn-link custom-chat-btn'; chatBtn.innerHTML = '<i class="fa fa-fw fa-comment-dots"></i> צ\'אט'; chatBtn.style.marginLeft = '8px'; chatBtn.style.cursor = 'pointer'; chatBtn.addEventListener('click', async function (e) { e.preventDefault(); e.stopPropagation(); const userLink = post.querySelector('a[data-uid]'); if (!userLink) return; userLink.dispatchEvent(new PointerEvent('pointerenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); const observer = new MutationObserver(() => { const popoverId = userLink.getAttribute('aria-describedby'); if (!popoverId) return; const popover = document.getElementById(popoverId); if (!popover) return; const btn = popover.querySelector('[component="account/new-chat"]') || popover.querySelector('[component="account/chat"]') || popover.querySelector('a[href*="/chats"]'); if (btn) { observer.disconnect(); const postUrl = pid ? `${getForumBaseUrl()}/post/${pid}` : window.location.href; const chatInputObserver = new MutationObserver(() => { const chatInput = document.querySelector('[component="chat/input"]') || document.querySelector('.chat-input'); if (chatInput) { chatInputObserver.disconnect(); if (!chatInput.value.includes(postUrl)) { chatInput.value = postUrl + '\n' + chatInput.value; chatInput.dispatchEvent(new Event('input', { bubbles: true })); chatInput.dispatchEvent(new Event('change', { bubbles: true })); chatInput.focus(); } } }); chatInputObserver.observe(document.body, { childList: true, subtree: true }); setTimeout(() => chatInputObserver.disconnect(), 5000); btn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), 5000); }); tools.appendChild(chatBtn); } // 2. כפתור שמור לקריאה (פוסטים) if (pid && !tools.querySelector('.custom-save-read-btn')) { const saveBtn = document.createElement('button'); saveBtn.className = 'btn btn-xs btn-link custom-save-read-btn'; saveBtn.style.marginLeft = '8px'; let savedList = GM_getValue('saved_to_read_data', []); const isSaved = savedList.some(x => x.pid === pid); saveBtn.innerHTML = `<i class="fa ${isSaved ? 'fa-bookmark' : 'fa-bookmark-o'}"></i> לקריאה בהמשך`; saveBtn.addEventListener('click', (e) => { e.preventDefault(); let currentList = GM_getValue('saved_to_read_data', []); if (currentList.some(x => x.pid === pid)) { currentList = currentList.filter(x => x.pid !== pid); saveBtn.querySelector('i').className = 'fa fa-bookmark-o'; } else { const contentEl = post.querySelector('.content') || post.querySelector('[component="post/content"]'); let snippet = contentEl ? contentEl.textContent.trim().substring(0, 120) : ''; if (snippet.length >= 120) snippet += '...'; currentList.push({ pid: pid, title: topicTitle, author: authorName, snippet: snippet }); saveBtn.querySelector('i').className = 'fa fa-bookmark'; } GM_setValue('saved_to_read_data', currentList); updateBadgesAndCounters(); }); tools.appendChild(saveBtn); } // 3. כפתור העתקת קישור מדויק לפוסט if (pid && !tools.querySelector('.custom-copy-link-btn')) { const copyBtn = document.createElement('button'); copyBtn.className = 'btn btn-xs btn-link custom-copy-link-btn'; copyBtn.style.marginLeft = '8px'; copyBtn.innerHTML = '<i class="fa fa-copy"></i> העתק קישור'; copyBtn.addEventListener('click', (e) => { e.preventDefault(); const postUrl = `${getForumBaseUrl()}/post/${pid}`; navigator.clipboard.writeText(postUrl); }); tools.appendChild(copyBtn); } }); } // ========================================== // חלק ו': תצוגה מקדימה של פוסטים באזורי צ'אט // ========================================== const previewPopup = document.createElement('div'); Object.assign(previewPopup.style, { position: 'absolute', backgroundColor: '#ffffff', border: '1px solid #dddddd', borderRadius: '8px', padding: '12px', boxShadow: '0 4px 15px rgba(0,0,0,0.15)', zIndex: '10000', display: 'none', maxWidth: '400px', maxHeight: '300px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.5', color: '#333333' }); document.body.appendChild(previewPopup); let activeRequest = null; let hideTimeout = null; previewPopup.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); }); previewPopup.addEventListener('mouseleave', () => { previewPopup.style.display = 'none'; }); function isInsideChat(link) { const path = window.location.pathname; if (path.includes('/chats') || /\/user\/[^/]+\/chats/.test(path)) return true; return !!link.closest('[component^="chat"]') || !!link.closest('.chat-window') || !!link.closest('.chat-modal') || !!link.closest('.chat-messages') || !!link.closest('.chat-content') || !!link.closest('.expanded-chat'); } function fetchPostContent(fullUrl, pid) { return new Promise((resolve) => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } activeRequest = GM_xmlhttpRequest({ method: "GET", url: fullUrl, onload: function(response) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, 'text/html'); const postContainer = doc.querySelector(`[data-pid="${pid}"]`); let contentEl = null; let authorEl = null; let avatarEl = null; if (postContainer) { contentEl = postContainer.querySelector('.content') || postContainer.querySelector('[component="post/content"]') || postContainer.querySelector('.post-content'); authorEl = postContainer.querySelector('[component="post/author"]') || postContainer.querySelector('.username') || postContainer.querySelector('[component="user/username"]') || postContainer.querySelector('.author-name') || postContainer.querySelector('[data-username]'); avatarEl = postContainer.querySelector('.avatar') || postContainer.querySelector('[component="user/picture"]') || postContainer.querySelector('.user-img') || postContainer.querySelector('.author-avatar') || postContainer.querySelector('.avatar-wrapper'); } else { contentEl = doc.querySelector('.content') || doc.querySelector('[component="post/content"]'); authorEl = doc.querySelector('.username') || doc.querySelector('[component="post/author"]'); avatarEl = doc.querySelector('.avatar') || doc.querySelector('[component="user/picture"]'); } let avatarHtml = ''; if (avatarEl) { const clone = avatarEl.cloneNode(true); clone.style.width = '24px'; clone.style.height = '24px'; clone.style.borderRadius = '50%'; clone.style.marginLeft = '8px'; clone.style.display = 'inline-block'; clone.style.verticalAlign = 'middle'; clone.style.objectFit = 'cover'; clone.style.lineHeight = '24px'; clone.style.fontSize = '11px'; avatarHtml = clone.outerHTML; } resolve({ content: contentEl ? contentEl.innerHTML : 'לא ניתן ליצור תצוגה מקדימה של הפוסט כרגע.', author: authorEl ? (authorEl.getAttribute('data-username') || authorEl.textContent.trim()) : 'משתמש', avatarHtml: avatarHtml }); } catch(e) { resolve({ content: 'שגיאה בפענוח התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }, onerror: function() { resolve({ content: 'שגיאה בטעינת התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }); }); } document.body.addEventListener('mouseover', async (e) => { const link = e.target.closest('a[href*="/post/"]'); if (!link || !isInsideChat(link)) return; const match = link.href.match(/(mitmachim\.top|otzaria\.org).*?\/post\/(\d+)/); if (!match) return; clearTimeout(hideTimeout); const pid = match[2]; const fullUrl = link.href; const rect = link.getBoundingClientRect(); previewPopup.style.left = `${rect.left + window.scrollX}px`; previewPopup.style.top = `${rect.bottom + window.scrollY + 8}px`; previewPopup.innerHTML = '<i class="fa fa-spinner fa-spin"></i> טוען תצוגה מקדימה...'; previewPopup.style.display = 'block'; const data = await fetchPostContent(fullUrl, pid); if (!data) return; previewPopup.innerHTML = ` <div style="font-weight: bold; color: #007bff; margin-bottom: 8px; display: flex; align-items: center;"> ${data.avatarHtml || '<i class="fa fa-user" style="margin-left: 8px;"></i>'} <span>${data.author}:</span> </div> <div class="post-preview-body">${data.content}</div> `; }); document.body.addEventListener('mouseout', (e) => { const link = e.target.closest('a[href*="/post/"]'); if (link && isInsideChat(link)) { hideTimeout = setTimeout(() => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } previewPopup.style.display = 'none'; }, 300); } }); // ========================================== // הפעלה מבוקרת ללא עומס DOM // ========================================== enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); let debounceTimer; const domObserver = new MutationObserver(() => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); }, 100); }); domObserver.observe(document.body, { childList: true, subtree: true }); })();עודכן לגרסה 4.9
-
אחרי הרבה עבודה...
// ==UserScript== // @name Mitmachim Forum Ultimate Enhancements // @namespace http://tampermonkey.net/ // @version 4.9 // @description החזרת מנגנון ההזרקה המדויק של גרסה 3.4, שילוב צ'אט אוטומטי ותצוגה מקדימה // @author ישראל מאיר שגיב & Gemini // @match https://mitmachim.top/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @connect mitmachim.top // @connect otzaria.org // @unsafeWindow // @run-at document-end // ==/UserScript== (function() { 'use strict'; function getForumBaseUrl() { const relativePath = (unsafeWindow.config && unsafeWindow.config.relative_path) || ''; return window.location.origin + relativePath; } // ========================================== // חלק א': יצירת הפופאפ המשותף // ========================================== const sharedPopup = document.createElement('div'); Object.assign(sharedPopup.style, { position: 'fixed', backgroundColor: '#ffffff', border: '1px solid #e2e8f0', borderRadius: '12px', padding: '16px', boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)', zIndex: '10005', display: 'none', width: '420px', maxHeight: '450px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.6', color: '#1e293b', fontFamily: 'system-ui, -apple-system, sans-serif' }); document.body.appendChild(sharedPopup); sharedPopup.addEventListener('click', (e) => e.stopPropagation()); document.addEventListener('click', () => { sharedPopup.style.display = 'none'; }); function positionPopup(anchorElement) { const rect = anchorElement.getBoundingClientRect(); sharedPopup.style.left = `${rect.right + 15}px`; sharedPopup.style.top = `${Math.min(rect.top, window.innerHeight - 460)}px`; sharedPopup.style.display = 'block'; } // --- פופאפ לקריאה בהמשך (פוסטים) --- function openReadLaterPopup(anchorElement) { positionPopup(anchorElement); const savedList = GM_getValue('saved_to_read_data', []); if (savedList.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">רשימת קריאה בהמשך (${savedList.length})</h4><div id="popup-items-container"></div>`; const container = sharedPopup.querySelector('#popup-items-container'); savedList.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/post/${item.pid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#2563eb; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${item.title}</a> <button class="delete-saved-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:11px; color:#64748b; margin-bottom:4px;">נכתב על ידי: <strong>${item.author}</strong></div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-saved-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentList = GM_getValue('saved_to_read_data', []); currentList = currentList.filter(x => x.pid !== item.pid); GM_setValue('saved_to_read_data', currentList); itemWrapper.remove(); updateBadgesAndCounters(); if (currentList.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; }); container.appendChild(itemWrapper); }); } // --- פופאפ סימניות שלי (נושאים) --- function openBookmarksPopup(anchorElement) { positionPopup(anchorElement); const savedTopics = GM_getValue('saved_topics_data', []); if (savedTopics.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">הסימניות שלי - נושאים (${savedTopics.length})</h4><div id="popup-topics-container"></div>`; const container = sharedPopup.querySelector('#popup-topics-container'); savedTopics.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/topic/${item.tid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#0284c7; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"><i class="fa fa-folder-open-o"></i> ${item.title}</a> <button class="delete-topic-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-topic-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentTopics = GM_getValue('saved_topics_data', []); currentTopics = currentTopics.filter(x => x.tid !== item.tid); GM_setValue('saved_topics_data', currentTopics); itemWrapper.remove(); updateBadgesAndCounters(); if (currentTopics.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; }); container.appendChild(itemWrapper); }); } // ========================================== // חלק ב': עדכון בועות מספרים (Badges) דינמי // ========================================== function updateBadgesAndCounters() { const readLaterCount = GM_getValue('saved_to_read_data', []).length; const bookmarksCount = GM_getValue('saved_topics_data', []).length; const rlBadge = document.getElementById('rl-count-badge'); if (rlBadge) { rlBadge.textContent = readLaterCount; rlBadge.style.display = readLaterCount > 0 ? 'inline-block' : 'none'; } const bmBadge = document.getElementById('bm-count-badge'); if (bmBadge) { bmBadge.textContent = bookmarksCount; bmBadge.style.display = bookmarksCount > 0 ? 'inline-block' : 'none'; } } // ========================================== // חלק ג': שילוב מושלם וחסין בסרגל השמאלי (מגרסה 3.4) // ========================================== function integrateIntoLeftSidebar() { const lists = document.querySelectorAll('#main-nav, .sidebar-nav, [component^="sidebar/"] ul, .nav-list, #menu, #user-control-list'); let leftSidebarNav = null; lists.forEach(el => { const rect = el.getBoundingClientRect(); if (rect.width > 0 && rect.left < window.innerWidth / 2) { leftSidebarNav = el; } }); if (!leftSidebarNav) return; if (!document.getElementById('custom-sidebar-styles')) { const style = document.createElement('style'); style.id = 'custom-sidebar-styles'; style.innerHTML = ` .custom-sidebar-item .nav-text { display: none; margin-right: 10px; } html.sidebar-left-open .custom-sidebar-item .nav-text, body.sidebar-left-open .custom-sidebar-item .nav-text, .sidebar-open .custom-sidebar-item .nav-text, .open .custom-sidebar-item .nav-text, #sidebar-left.open .custom-sidebar-item .nav-text { display: inline-block !important; } .custom-badge { position: absolute; top: 2px; left: 5px; background-color: #ef4444; color: white; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 10px; min-width: 18px; text-align: center; line-height: 1; box-shadow: 0 1px 3px rgba(0,0,0,0.2); } .custom-sidebar-item a { position: relative; } `; document.head.appendChild(style); } if (!document.getElementById('integrated-to-read-li')) { const li = document.createElement('li'); li.id = 'integrated-to-read-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="לקריאה בהמשך" style="cursor:pointer; display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-list-alt"></i> <span class="nav-text">לקריאה בהמשך</span> <span id="rl-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openReadLaterPopup(li); }, true); leftSidebarNav.appendChild(li); } if (!document.getElementById('integrated-bookmarks-li')) { const li = document.createElement('li'); li.id = 'integrated-bookmarks-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="הסימניות שלי" style="display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-bookmark"></i> <span class="nav-text">הסימניות שלי</span> <span id="bm-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openBookmarksPopup(li); }, true); leftSidebarNav.appendChild(li); } updateBadgesAndCounters(); } // ========================================== // חלק ד': הזרקת כפתור סימנייה לסרגל הכלים הראשי של הנושא // ========================================== function enhanceTopicHeaderTools() { if (document.getElementById('top-bar-save-topic-btn')) return; const currentTid = (unsafeWindow.ajaxify && unsafeWindow.ajaxify.data && unsafeWindow.ajaxify.data.tid) || null; if (!currentTid) return; const exportBtn = document.querySelector('.fa-download')?.closest('a, button'); if (!exportBtn) return; const parentContainer = exportBtn.parentElement; if (!parentContainer) return; const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; const topicBtn = document.createElement('button'); topicBtn.id = 'top-bar-save-topic-btn'; topicBtn.className = exportBtn.className || 'btn btn-sm btn-link text-secondary text-body'; topicBtn.style.cssText = 'cursor: pointer; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; background: none; border: none; margin-left: 12px;'; let savedTopics = GM_getValue('saved_topics_data', []); const isTopicSaved = savedTopics.some(x => x.tid === currentTid); topicBtn.innerHTML = `<i class="fa ${isTopicSaved ? 'fa-folder' : 'fa-folder-o'}"></i> <span>שמור כסימניה</span>`; topicBtn.addEventListener('click', (e) => { e.preventDefault(); let currentTopics = GM_getValue('saved_topics_data', []); const icon = topicBtn.querySelector('i'); if (currentTopics.some(x => x.tid === currentTid)) { currentTopics = currentTopics.filter(x => x.tid !== currentTid); icon.className = 'fa fa-folder-o'; } else { const firstPostEl = document.querySelector('[component="post"] .content, [component="post/content"]'); let snippet = firstPostEl ? firstPostEl.textContent.trim().substring(0, 120) : 'לחץ למעבר לצפייה בנושא המלא...'; if (snippet.length >= 120) snippet += '...'; currentTopics.push({ tid: currentTid, title: topicTitle, snippet: snippet }); icon.className = 'fa fa-folder'; } GM_setValue('saved_topics_data', currentTopics); updateBadgesAndCounters(); }); parentContainer.insertBefore(topicBtn, exportBtn); } // ========================================== // חלק ה': הזרקת כפתורים לפוסטים (צ'אט אוטומטי מלא) // ========================================== function enhancePosts() { const posts = document.querySelectorAll('[component="post"]:not(.enhanced-post)'); const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; posts.forEach(post => { post.classList.add('enhanced-post'); const tools = post.querySelector('.post-tools, [component="post/tools"], [component="post/actions"]'); if (!tools) return; const pid = post.getAttribute('data-pid'); const postUid = post.getAttribute('data-uid'); const authorName = post.getAttribute('data-username') || 'משתמש'; const currentUid = (unsafeWindow.app && unsafeWindow.app.user) ? unsafeWindow.app.user.uid : null; // 1. כפתור צ'אט אוטומטי חסין (הדמיית Mouseenter והזרקת קישור) if (postUid && currentUid && Array.of(0, currentUid).includes(Number(postUid)) === false && !tools.querySelector('.custom-chat-btn')) { const chatBtn = document.createElement('a'); chatBtn.className = 'btn btn-xs btn-link custom-chat-btn'; chatBtn.innerHTML = '<i class="fa fa-fw fa-comment-dots"></i> צ\'אט'; chatBtn.style.marginLeft = '8px'; chatBtn.style.cursor = 'pointer'; chatBtn.addEventListener('click', async function (e) { e.preventDefault(); e.stopPropagation(); const userLink = post.querySelector('a[data-uid]'); if (!userLink) return; userLink.dispatchEvent(new PointerEvent('pointerenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); const observer = new MutationObserver(() => { const popoverId = userLink.getAttribute('aria-describedby'); if (!popoverId) return; const popover = document.getElementById(popoverId); if (!popover) return; const btn = popover.querySelector('[component="account/new-chat"]') || popover.querySelector('[component="account/chat"]') || popover.querySelector('a[href*="/chats"]'); if (btn) { observer.disconnect(); const postUrl = pid ? `${getForumBaseUrl()}/post/${pid}` : window.location.href; const chatInputObserver = new MutationObserver(() => { const chatInput = document.querySelector('[component="chat/input"]') || document.querySelector('.chat-input'); if (chatInput) { chatInputObserver.disconnect(); if (!chatInput.value.includes(postUrl)) { chatInput.value = postUrl + '\n' + chatInput.value; chatInput.dispatchEvent(new Event('input', { bubbles: true })); chatInput.dispatchEvent(new Event('change', { bubbles: true })); chatInput.focus(); } } }); chatInputObserver.observe(document.body, { childList: true, subtree: true }); setTimeout(() => chatInputObserver.disconnect(), 5000); btn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), 5000); }); tools.appendChild(chatBtn); } // 2. כפתור שמור לקריאה (פוסטים) if (pid && !tools.querySelector('.custom-save-read-btn')) { const saveBtn = document.createElement('button'); saveBtn.className = 'btn btn-xs btn-link custom-save-read-btn'; saveBtn.style.marginLeft = '8px'; let savedList = GM_getValue('saved_to_read_data', []); const isSaved = savedList.some(x => x.pid === pid); saveBtn.innerHTML = `<i class="fa ${isSaved ? 'fa-bookmark' : 'fa-bookmark-o'}"></i> לקריאה בהמשך`; saveBtn.addEventListener('click', (e) => { e.preventDefault(); let currentList = GM_getValue('saved_to_read_data', []); if (currentList.some(x => x.pid === pid)) { currentList = currentList.filter(x => x.pid !== pid); saveBtn.querySelector('i').className = 'fa fa-bookmark-o'; } else { const contentEl = post.querySelector('.content') || post.querySelector('[component="post/content"]'); let snippet = contentEl ? contentEl.textContent.trim().substring(0, 120) : ''; if (snippet.length >= 120) snippet += '...'; currentList.push({ pid: pid, title: topicTitle, author: authorName, snippet: snippet }); saveBtn.querySelector('i').className = 'fa fa-bookmark'; } GM_setValue('saved_to_read_data', currentList); updateBadgesAndCounters(); }); tools.appendChild(saveBtn); } // 3. כפתור העתקת קישור מדויק לפוסט if (pid && !tools.querySelector('.custom-copy-link-btn')) { const copyBtn = document.createElement('button'); copyBtn.className = 'btn btn-xs btn-link custom-copy-link-btn'; copyBtn.style.marginLeft = '8px'; copyBtn.innerHTML = '<i class="fa fa-copy"></i> העתק קישור'; copyBtn.addEventListener('click', (e) => { e.preventDefault(); const postUrl = `${getForumBaseUrl()}/post/${pid}`; navigator.clipboard.writeText(postUrl); }); tools.appendChild(copyBtn); } }); } // ========================================== // חלק ו': תצוגה מקדימה של פוסטים באזורי צ'אט // ========================================== const previewPopup = document.createElement('div'); Object.assign(previewPopup.style, { position: 'absolute', backgroundColor: '#ffffff', border: '1px solid #dddddd', borderRadius: '8px', padding: '12px', boxShadow: '0 4px 15px rgba(0,0,0,0.15)', zIndex: '10000', display: 'none', maxWidth: '400px', maxHeight: '300px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.5', color: '#333333' }); document.body.appendChild(previewPopup); let activeRequest = null; let hideTimeout = null; previewPopup.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); }); previewPopup.addEventListener('mouseleave', () => { previewPopup.style.display = 'none'; }); function isInsideChat(link) { const path = window.location.pathname; if (path.includes('/chats') || /\/user\/[^/]+\/chats/.test(path)) return true; return !!link.closest('[component^="chat"]') || !!link.closest('.chat-window') || !!link.closest('.chat-modal') || !!link.closest('.chat-messages') || !!link.closest('.chat-content') || !!link.closest('.expanded-chat'); } function fetchPostContent(fullUrl, pid) { return new Promise((resolve) => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } activeRequest = GM_xmlhttpRequest({ method: "GET", url: fullUrl, onload: function(response) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, 'text/html'); const postContainer = doc.querySelector(`[data-pid="${pid}"]`); let contentEl = null; let authorEl = null; let avatarEl = null; if (postContainer) { contentEl = postContainer.querySelector('.content') || postContainer.querySelector('[component="post/content"]') || postContainer.querySelector('.post-content'); authorEl = postContainer.querySelector('[component="post/author"]') || postContainer.querySelector('.username') || postContainer.querySelector('[component="user/username"]') || postContainer.querySelector('.author-name') || postContainer.querySelector('[data-username]'); avatarEl = postContainer.querySelector('.avatar') || postContainer.querySelector('[component="user/picture"]') || postContainer.querySelector('.user-img') || postContainer.querySelector('.author-avatar') || postContainer.querySelector('.avatar-wrapper'); } else { contentEl = doc.querySelector('.content') || doc.querySelector('[component="post/content"]'); authorEl = doc.querySelector('.username') || doc.querySelector('[component="post/author"]'); avatarEl = doc.querySelector('.avatar') || doc.querySelector('[component="user/picture"]'); } let avatarHtml = ''; if (avatarEl) { const clone = avatarEl.cloneNode(true); clone.style.width = '24px'; clone.style.height = '24px'; clone.style.borderRadius = '50%'; clone.style.marginLeft = '8px'; clone.style.display = 'inline-block'; clone.style.verticalAlign = 'middle'; clone.style.objectFit = 'cover'; clone.style.lineHeight = '24px'; clone.style.fontSize = '11px'; avatarHtml = clone.outerHTML; } resolve({ content: contentEl ? contentEl.innerHTML : 'לא ניתן ליצור תצוגה מקדימה של הפוסט כרגע.', author: authorEl ? (authorEl.getAttribute('data-username') || authorEl.textContent.trim()) : 'משתמש', avatarHtml: avatarHtml }); } catch(e) { resolve({ content: 'שגיאה בפענוח התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }, onerror: function() { resolve({ content: 'שגיאה בטעינת התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }); }); } document.body.addEventListener('mouseover', async (e) => { const link = e.target.closest('a[href*="/post/"]'); if (!link || !isInsideChat(link)) return; const match = link.href.match(/(mitmachim\.top|otzaria\.org).*?\/post\/(\d+)/); if (!match) return; clearTimeout(hideTimeout); const pid = match[2]; const fullUrl = link.href; const rect = link.getBoundingClientRect(); previewPopup.style.left = `${rect.left + window.scrollX}px`; previewPopup.style.top = `${rect.bottom + window.scrollY + 8}px`; previewPopup.innerHTML = '<i class="fa fa-spinner fa-spin"></i> טוען תצוגה מקדימה...'; previewPopup.style.display = 'block'; const data = await fetchPostContent(fullUrl, pid); if (!data) return; previewPopup.innerHTML = ` <div style="font-weight: bold; color: #007bff; margin-bottom: 8px; display: flex; align-items: center;"> ${data.avatarHtml || '<i class="fa fa-user" style="margin-left: 8px;"></i>'} <span>${data.author}:</span> </div> <div class="post-preview-body">${data.content}</div> `; }); document.body.addEventListener('mouseout', (e) => { const link = e.target.closest('a[href*="/post/"]'); if (link && isInsideChat(link)) { hideTimeout = setTimeout(() => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } previewPopup.style.display = 'none'; }, 300); } }); // ========================================== // הפעלה מבוקרת ללא עומס DOM // ========================================== enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); let debounceTimer; const domObserver = new MutationObserver(() => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); }, 100); }); domObserver.observe(document.body, { childList: true, subtree: true }); })();עודכן לגרסה 4.9
@מחנה-ידידים באר פרט.
זה פותח צ'אט עם כותב הפוסט?
במקרה שכבר יש צאט ישן איתו, זה פותח חדש, או שזה פותח את הישן?
זה מביא אוטומטי קישור לתגובה דרכה נפחח הצאט? -
@מחנה-ידידים באר פרט.
זה פותח צ'אט עם כותב הפוסט?
במקרה שכבר יש צאט ישן איתו, זה פותח חדש, או שזה פותח את הישן?
זה מביא אוטומטי קישור לתגובה דרכה נפחח הצאט?@צדיק-וטוב-לו-0 אם יש כבר חדר צ'אט עם המשתמש זה פותח אותו (אם יש כמה - לא יודע, אולי את ההכי חדש?).
אם אין - חדר צ'אט חדש רגיל.
אין קישור לתגובה, @מחנה-ידידים ממליץ להוסיף. -
@צדיק-וטוב-לו-0 אם יש כבר חדר צ'אט עם המשתמש זה פותח אותו (אם יש כמה - לא יודע, אולי את ההכי חדש?).
אם אין - חדר צ'אט חדש רגיל.
אין קישור לתגובה, @מחנה-ידידים ממליץ להוסיף.@אברהם-גלסר תמיכה באוצריא גם לא תזיק (או שאתה רוצה שאעשה לבד).
-
@אברהם-גלסר תמיכה באוצריא גם לא תזיק (או שאתה רוצה שאעשה לבד).
@צדיק-וטוב-לו-0 , @מחנה-ידידים יצר את הסקריפט, לא אני.
-
@אברהם-גלסר תמיכה באוצריא גם לא תזיק (או שאתה רוצה שאעשה לבד).
@צדיק-וטוב-לו-0 @אברהם-גלסר
מחילה לא נכנסתי קצת זמן..
זו לא בעיה להוסיף תמיכה באוצריא - פשוט להוסיף match בסקריפט.
קישור לתגובה - אנסה.(אם יש כמה - לא יודע, אולי את ההכי חדש?)
בדיוק מה שנפתח בלחצן בדף הפרופיל.
-
@צדיק-וטוב-לו-0 @אברהם-גלסר
מחילה לא נכנסתי קצת זמן..
זו לא בעיה להוסיף תמיכה באוצריא - פשוט להוסיף match בסקריפט.
קישור לתגובה - אנסה.(אם יש כמה - לא יודע, אולי את ההכי חדש?)
בדיוק מה שנפתח בלחצן בדף הפרופיל.
@מחנה-ידידים אולי תוכל לעשות כזה סקריפט גם לפורום בני ברק,
זה יהיה מאוד שימושי. -
@מחנה-ידידים אולי תוכל לעשות כזה סקריפט גם לפורום בני ברק,
זה יהיה מאוד שימושי.@המתכנת-התותח זה לא בעיה:
// ==UserScript== // @name NodeBB Chat Button Injector // @namespace http://tampermonkey.net/ // @version 1.1 // @description הזרקת לחצן צ'אט מהיר ליד כל פוסט בפורומי NodeBB // @author אללוף // @match https://mitmachim.top/* // @match https://bnebrak.com/* // @grant unsafeWindow // @run-at document-end // ==/UserScript== (function() { 'use strict'; // פונקציה להזרקת הכפתור לפוסטים שעוד לא טופלו function injectChatButtons() { // בדיקה שפתח ה-API של הפורום זמין if (!unsafeWindow.app || !unsafeWindow.app.user) return; const currentUid = unsafeWindow.app.user.uid; // שליפת כל הפוסטים בעמוד שעוד לא קיבלו כפתור const posts = document.querySelectorAll('[component="post"]:not(.chat-btn-added)'); posts.forEach(post => { post.classList.add('chat-btn-added'); const postUid = post.getAttribute('data-uid'); // הגנה: שלא יוצג כפתור צ'אט של המשתמש עם עצמו, או אם אין uid תקין if (!postUid || Array.of(0, currentUid).includes(Number(postUid))) return; // איתור מיקום הלחצנים של הפוסט (תומך ברוב ערכות הנושא של NodeBB) const actionsContainer = post.querySelector('[component="post/actions"]') || post.querySelector('.post-tools'); if (actionsContainer) { const chatBtn = document.createElement('a'); chatBtn.className = 'btn btn-xs btn-link chat-quick-btn'; chatBtn.innerHTML = '<i class="fa fa-fw fa-comment-dots"></i> צ\'אט'; chatBtn.style.marginLeft = '8px'; chatBtn.style.cursor = 'pointer'; // אירוע לחיצה לפתיחת הצ'אט המובנה של המערכת chatBtn.addEventListener('click', async function (e) { e.preventDefault(); e.stopPropagation(); const userLink = post.querySelector('a[data-uid]'); if (!userLink) return; // ניסיון לפתוח את ה-popover המקורי userLink.dispatchEvent(new PointerEvent('pointerenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); const observer = new MutationObserver(() => { const popoverId = userLink.getAttribute('aria-describedby'); if (!popoverId) { return; } const popover = document.getElementById(popoverId); if (!popover) { return; } const btn = popover.querySelector('[component="account/new-chat"]') || popover.querySelector('[component="account/chat"]') || popover.querySelector('a[href*="/chats"]'); if (btn) { observer.disconnect(); btn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), 5000); }); // הזרקה לתחילת או סוף רשימת הלחצנים לפי הנוחיות actionsContainer.appendChild(chatBtn); } }); } // האזנה לשינויים ב-DOM לצורך תמיכה בגלילה אינסופית ומעברי עמודים דינמיים const observer = new MutationObserver(() => { injectChatButtons(); }); observer.observe(document.body, { childList: true, subtree: true }); // הרצה ראשונית בטעינת העמוד injectChatButtons(); })(); -
@צדיק-וטוב-לו-0 @אברהם-גלסר
מחילה לא נכנסתי קצת זמן..
זו לא בעיה להוסיף תמיכה באוצריא - פשוט להוסיף match בסקריפט.
קישור לתגובה - אנסה.(אם יש כמה - לא יודע, אולי את ההכי חדש?)
בדיוק מה שנפתח בלחצן בדף הפרופיל.
@מחנה-ידידים אתה יכול לפרוז את זה בגיט, ואז אפשר להתקין ממך בקלות, ואתה יכול לעדכן את הסקריפט.
ג'מיני ממש שמח להסביר לי את זה. -
אחרי הרבה עבודה...
// ==UserScript== // @name Mitmachim Forum Ultimate Enhancements // @namespace http://tampermonkey.net/ // @version 4.9 // @description החזרת מנגנון ההזרקה המדויק של גרסה 3.4, שילוב צ'אט אוטומטי ותצוגה מקדימה // @author ישראל מאיר שגיב & Gemini // @match https://mitmachim.top/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @connect mitmachim.top // @connect otzaria.org // @unsafeWindow // @run-at document-end // ==/UserScript== (function() { 'use strict'; function getForumBaseUrl() { const relativePath = (unsafeWindow.config && unsafeWindow.config.relative_path) || ''; return window.location.origin + relativePath; } // ========================================== // חלק א': יצירת הפופאפ המשותף // ========================================== const sharedPopup = document.createElement('div'); Object.assign(sharedPopup.style, { position: 'fixed', backgroundColor: '#ffffff', border: '1px solid #e2e8f0', borderRadius: '12px', padding: '16px', boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)', zIndex: '10005', display: 'none', width: '420px', maxHeight: '450px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.6', color: '#1e293b', fontFamily: 'system-ui, -apple-system, sans-serif' }); document.body.appendChild(sharedPopup); sharedPopup.addEventListener('click', (e) => e.stopPropagation()); document.addEventListener('click', () => { sharedPopup.style.display = 'none'; }); function positionPopup(anchorElement) { const rect = anchorElement.getBoundingClientRect(); sharedPopup.style.left = `${rect.right + 15}px`; sharedPopup.style.top = `${Math.min(rect.top, window.innerHeight - 460)}px`; sharedPopup.style.display = 'block'; } // --- פופאפ לקריאה בהמשך (פוסטים) --- function openReadLaterPopup(anchorElement) { positionPopup(anchorElement); const savedList = GM_getValue('saved_to_read_data', []); if (savedList.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">רשימת קריאה בהמשך (${savedList.length})</h4><div id="popup-items-container"></div>`; const container = sharedPopup.querySelector('#popup-items-container'); savedList.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/post/${item.pid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#2563eb; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${item.title}</a> <button class="delete-saved-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:11px; color:#64748b; margin-bottom:4px;">נכתב על ידי: <strong>${item.author}</strong></div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-saved-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentList = GM_getValue('saved_to_read_data', []); currentList = currentList.filter(x => x.pid !== item.pid); GM_setValue('saved_to_read_data', currentList); itemWrapper.remove(); updateBadgesAndCounters(); if (currentList.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין פוסטים שמורים לקריאה בהמשך.</div>'; }); container.appendChild(itemWrapper); }); } // --- פופאפ סימניות שלי (נושאים) --- function openBookmarksPopup(anchorElement) { positionPopup(anchorElement); const savedTopics = GM_getValue('saved_topics_data', []); if (savedTopics.length === 0) { sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; return; } sharedPopup.innerHTML = `<h4 style="margin: 0 0 12px 0; font-size: 16px; font-weight: bold; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a;">הסימניות שלי - נושאים (${savedTopics.length})</h4><div id="popup-topics-container"></div>`; const container = sharedPopup.querySelector('#popup-topics-container'); savedTopics.forEach(item => { const itemWrapper = document.createElement('div'); itemWrapper.style.cssText = 'padding: 10px; border-bottom: 1px solid #f1f5f9; margin-bottom: 8px; background: #f8fafc; border-radius: 6px; position: relative;'; const fullUrl = `${getForumBaseUrl()}/topic/${item.tid}`; itemWrapper.innerHTML = ` <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;"> <a href="${fullUrl}" target="_blank" style="font-weight:600; color:#0284c7; text-decoration:none; font-size:13px; max-width:80%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"><i class="fa fa-folder-open-o"></i> ${item.title}</a> <button class="delete-topic-btn" style="background:none; border:none; color:#ef4444; cursor:pointer; padding:2px 6px; font-size:12px;"><i class="fa fa-trash"></i></button> </div> <div style="font-size:12px; color:#334155; background:#ffffff; padding:6px; border-radius:4px; border:1px solid #e2e8f0; max-height:60px; overflow:hidden;">${item.snippet}</div> `; itemWrapper.querySelector('.delete-topic-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); let currentTopics = GM_getValue('saved_topics_data', []); currentTopics = currentTopics.filter(x => x.tid !== item.tid); GM_setValue('saved_topics_data', currentTopics); itemWrapper.remove(); updateBadgesAndCounters(); if (currentTopics.length === 0) sharedPopup.innerHTML = '<div style="text-align:center; padding:20px; color:#64748b;">אין נושאים שמורים בסימניות.</div>'; }); container.appendChild(itemWrapper); }); } // ========================================== // חלק ב': עדכון בועות מספרים (Badges) דינמי // ========================================== function updateBadgesAndCounters() { const readLaterCount = GM_getValue('saved_to_read_data', []).length; const bookmarksCount = GM_getValue('saved_topics_data', []).length; const rlBadge = document.getElementById('rl-count-badge'); if (rlBadge) { rlBadge.textContent = readLaterCount; rlBadge.style.display = readLaterCount > 0 ? 'inline-block' : 'none'; } const bmBadge = document.getElementById('bm-count-badge'); if (bmBadge) { bmBadge.textContent = bookmarksCount; bmBadge.style.display = bookmarksCount > 0 ? 'inline-block' : 'none'; } } // ========================================== // חלק ג': שילוב מושלם וחסין בסרגל השמאלי (מגרסה 3.4) // ========================================== function integrateIntoLeftSidebar() { const lists = document.querySelectorAll('#main-nav, .sidebar-nav, [component^="sidebar/"] ul, .nav-list, #menu, #user-control-list'); let leftSidebarNav = null; lists.forEach(el => { const rect = el.getBoundingClientRect(); if (rect.width > 0 && rect.left < window.innerWidth / 2) { leftSidebarNav = el; } }); if (!leftSidebarNav) return; if (!document.getElementById('custom-sidebar-styles')) { const style = document.createElement('style'); style.id = 'custom-sidebar-styles'; style.innerHTML = ` .custom-sidebar-item .nav-text { display: none; margin-right: 10px; } html.sidebar-left-open .custom-sidebar-item .nav-text, body.sidebar-left-open .custom-sidebar-item .nav-text, .sidebar-open .custom-sidebar-item .nav-text, .open .custom-sidebar-item .nav-text, #sidebar-left.open .custom-sidebar-item .nav-text { display: inline-block !important; } .custom-badge { position: absolute; top: 2px; left: 5px; background-color: #ef4444; color: white; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 10px; min-width: 18px; text-align: center; line-height: 1; box-shadow: 0 1px 3px rgba(0,0,0,0.2); } .custom-sidebar-item a { position: relative; } `; document.head.appendChild(style); } if (!document.getElementById('integrated-to-read-li')) { const li = document.createElement('li'); li.id = 'integrated-to-read-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="לקריאה בהמשך" style="cursor:pointer; display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-list-alt"></i> <span class="nav-text">לקריאה בהמשך</span> <span id="rl-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openReadLaterPopup(li); }, true); leftSidebarNav.appendChild(li); } if (!document.getElementById('integrated-bookmarks-li')) { const li = document.createElement('li'); li.id = 'integrated-bookmarks-li'; li.className = 'nav-item custom-sidebar-item'; li.innerHTML = ` <a class="nav-link" href="#" title="הסימניות שלי" style="display:flex; align-items:center; padding: 10px 15px;"> <i class="fa fa-fw fa-bookmark"></i> <span class="nav-text">הסימניות שלי</span> <span id="bm-count-badge" class="custom-badge unread-count badge" style="display:none;">0</span> </a> `; li.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openBookmarksPopup(li); }, true); leftSidebarNav.appendChild(li); } updateBadgesAndCounters(); } // ========================================== // חלק ד': הזרקת כפתור סימנייה לסרגל הכלים הראשי של הנושא // ========================================== function enhanceTopicHeaderTools() { if (document.getElementById('top-bar-save-topic-btn')) return; const currentTid = (unsafeWindow.ajaxify && unsafeWindow.ajaxify.data && unsafeWindow.ajaxify.data.tid) || null; if (!currentTid) return; const exportBtn = document.querySelector('.fa-download')?.closest('a, button'); if (!exportBtn) return; const parentContainer = exportBtn.parentElement; if (!parentContainer) return; const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; const topicBtn = document.createElement('button'); topicBtn.id = 'top-bar-save-topic-btn'; topicBtn.className = exportBtn.className || 'btn btn-sm btn-link text-secondary text-body'; topicBtn.style.cssText = 'cursor: pointer; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; background: none; border: none; margin-left: 12px;'; let savedTopics = GM_getValue('saved_topics_data', []); const isTopicSaved = savedTopics.some(x => x.tid === currentTid); topicBtn.innerHTML = `<i class="fa ${isTopicSaved ? 'fa-folder' : 'fa-folder-o'}"></i> <span>שמור כסימניה</span>`; topicBtn.addEventListener('click', (e) => { e.preventDefault(); let currentTopics = GM_getValue('saved_topics_data', []); const icon = topicBtn.querySelector('i'); if (currentTopics.some(x => x.tid === currentTid)) { currentTopics = currentTopics.filter(x => x.tid !== currentTid); icon.className = 'fa fa-folder-o'; } else { const firstPostEl = document.querySelector('[component="post"] .content, [component="post/content"]'); let snippet = firstPostEl ? firstPostEl.textContent.trim().substring(0, 120) : 'לחץ למעבר לצפייה בנושא המלא...'; if (snippet.length >= 120) snippet += '...'; currentTopics.push({ tid: currentTid, title: topicTitle, snippet: snippet }); icon.className = 'fa fa-folder'; } GM_setValue('saved_topics_data', currentTopics); updateBadgesAndCounters(); }); parentContainer.insertBefore(topicBtn, exportBtn); } // ========================================== // חלק ה': הזרקת כפתורים לפוסטים (צ'אט אוטומטי מלא) // ========================================== function enhancePosts() { const posts = document.querySelectorAll('[component="post"]:not(.enhanced-post)'); const topicTitle = document.querySelector('[component="topic/title"]')?.textContent.trim() || 'נושא בפורום'; posts.forEach(post => { post.classList.add('enhanced-post'); const tools = post.querySelector('.post-tools, [component="post/tools"], [component="post/actions"]'); if (!tools) return; const pid = post.getAttribute('data-pid'); const postUid = post.getAttribute('data-uid'); const authorName = post.getAttribute('data-username') || 'משתמש'; const currentUid = (unsafeWindow.app && unsafeWindow.app.user) ? unsafeWindow.app.user.uid : null; // 1. כפתור צ'אט אוטומטי חסין (הדמיית Mouseenter והזרקת קישור) if (postUid && currentUid && Array.of(0, currentUid).includes(Number(postUid)) === false && !tools.querySelector('.custom-chat-btn')) { const chatBtn = document.createElement('a'); chatBtn.className = 'btn btn-xs btn-link custom-chat-btn'; chatBtn.innerHTML = '<i class="fa fa-fw fa-comment-dots"></i> צ\'אט'; chatBtn.style.marginLeft = '8px'; chatBtn.style.cursor = 'pointer'; chatBtn.addEventListener('click', async function (e) { e.preventDefault(); e.stopPropagation(); const userLink = post.querySelector('a[data-uid]'); if (!userLink) return; userLink.dispatchEvent(new PointerEvent('pointerenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true })); userLink.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); const observer = new MutationObserver(() => { const popoverId = userLink.getAttribute('aria-describedby'); if (!popoverId) return; const popover = document.getElementById(popoverId); if (!popover) return; const btn = popover.querySelector('[component="account/new-chat"]') || popover.querySelector('[component="account/chat"]') || popover.querySelector('a[href*="/chats"]'); if (btn) { observer.disconnect(); const postUrl = pid ? `${getForumBaseUrl()}/post/${pid}` : window.location.href; const chatInputObserver = new MutationObserver(() => { const chatInput = document.querySelector('[component="chat/input"]') || document.querySelector('.chat-input'); if (chatInput) { chatInputObserver.disconnect(); if (!chatInput.value.includes(postUrl)) { chatInput.value = postUrl + '\n' + chatInput.value; chatInput.dispatchEvent(new Event('input', { bubbles: true })); chatInput.dispatchEvent(new Event('change', { bubbles: true })); chatInput.focus(); } } }); chatInputObserver.observe(document.body, { childList: true, subtree: true }); setTimeout(() => chatInputObserver.disconnect(), 5000); btn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => observer.disconnect(), 5000); }); tools.appendChild(chatBtn); } // 2. כפתור שמור לקריאה (פוסטים) if (pid && !tools.querySelector('.custom-save-read-btn')) { const saveBtn = document.createElement('button'); saveBtn.className = 'btn btn-xs btn-link custom-save-read-btn'; saveBtn.style.marginLeft = '8px'; let savedList = GM_getValue('saved_to_read_data', []); const isSaved = savedList.some(x => x.pid === pid); saveBtn.innerHTML = `<i class="fa ${isSaved ? 'fa-bookmark' : 'fa-bookmark-o'}"></i> לקריאה בהמשך`; saveBtn.addEventListener('click', (e) => { e.preventDefault(); let currentList = GM_getValue('saved_to_read_data', []); if (currentList.some(x => x.pid === pid)) { currentList = currentList.filter(x => x.pid !== pid); saveBtn.querySelector('i').className = 'fa fa-bookmark-o'; } else { const contentEl = post.querySelector('.content') || post.querySelector('[component="post/content"]'); let snippet = contentEl ? contentEl.textContent.trim().substring(0, 120) : ''; if (snippet.length >= 120) snippet += '...'; currentList.push({ pid: pid, title: topicTitle, author: authorName, snippet: snippet }); saveBtn.querySelector('i').className = 'fa fa-bookmark'; } GM_setValue('saved_to_read_data', currentList); updateBadgesAndCounters(); }); tools.appendChild(saveBtn); } // 3. כפתור העתקת קישור מדויק לפוסט if (pid && !tools.querySelector('.custom-copy-link-btn')) { const copyBtn = document.createElement('button'); copyBtn.className = 'btn btn-xs btn-link custom-copy-link-btn'; copyBtn.style.marginLeft = '8px'; copyBtn.innerHTML = '<i class="fa fa-copy"></i> העתק קישור'; copyBtn.addEventListener('click', (e) => { e.preventDefault(); const postUrl = `${getForumBaseUrl()}/post/${pid}`; navigator.clipboard.writeText(postUrl); }); tools.appendChild(copyBtn); } }); } // ========================================== // חלק ו': תצוגה מקדימה של פוסטים באזורי צ'אט // ========================================== const previewPopup = document.createElement('div'); Object.assign(previewPopup.style, { position: 'absolute', backgroundColor: '#ffffff', border: '1px solid #dddddd', borderRadius: '8px', padding: '12px', boxShadow: '0 4px 15px rgba(0,0,0,0.15)', zIndex: '10000', display: 'none', maxWidth: '400px', maxHeight: '300px', overflowY: 'auto', fontSize: '14px', direction: 'rtl', lineHeight: '1.5', color: '#333333' }); document.body.appendChild(previewPopup); let activeRequest = null; let hideTimeout = null; previewPopup.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); }); previewPopup.addEventListener('mouseleave', () => { previewPopup.style.display = 'none'; }); function isInsideChat(link) { const path = window.location.pathname; if (path.includes('/chats') || /\/user\/[^/]+\/chats/.test(path)) return true; return !!link.closest('[component^="chat"]') || !!link.closest('.chat-window') || !!link.closest('.chat-modal') || !!link.closest('.chat-messages') || !!link.closest('.chat-content') || !!link.closest('.expanded-chat'); } function fetchPostContent(fullUrl, pid) { return new Promise((resolve) => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } activeRequest = GM_xmlhttpRequest({ method: "GET", url: fullUrl, onload: function(response) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, 'text/html'); const postContainer = doc.querySelector(`[data-pid="${pid}"]`); let contentEl = null; let authorEl = null; let avatarEl = null; if (postContainer) { contentEl = postContainer.querySelector('.content') || postContainer.querySelector('[component="post/content"]') || postContainer.querySelector('.post-content'); authorEl = postContainer.querySelector('[component="post/author"]') || postContainer.querySelector('.username') || postContainer.querySelector('[component="user/username"]') || postContainer.querySelector('.author-name') || postContainer.querySelector('[data-username]'); avatarEl = postContainer.querySelector('.avatar') || postContainer.querySelector('[component="user/picture"]') || postContainer.querySelector('.user-img') || postContainer.querySelector('.author-avatar') || postContainer.querySelector('.avatar-wrapper'); } else { contentEl = doc.querySelector('.content') || doc.querySelector('[component="post/content"]'); authorEl = doc.querySelector('.username') || doc.querySelector('[component="post/author"]'); avatarEl = doc.querySelector('.avatar') || doc.querySelector('[component="user/picture"]'); } let avatarHtml = ''; if (avatarEl) { const clone = avatarEl.cloneNode(true); clone.style.width = '24px'; clone.style.height = '24px'; clone.style.borderRadius = '50%'; clone.style.marginLeft = '8px'; clone.style.display = 'inline-block'; clone.style.verticalAlign = 'middle'; clone.style.objectFit = 'cover'; clone.style.lineHeight = '24px'; clone.style.fontSize = '11px'; avatarHtml = clone.outerHTML; } resolve({ content: contentEl ? contentEl.innerHTML : 'לא ניתן ליצור תצוגה מקדימה של הפוסט כרגע.', author: authorEl ? (authorEl.getAttribute('data-username') || authorEl.textContent.trim()) : 'משתמש', avatarHtml: avatarHtml }); } catch(e) { resolve({ content: 'שגיאה בפענוח התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }, onerror: function() { resolve({ content: 'שגיאה בטעינת התצוגה המקדימה.', author: 'מערכת', avatarHtml: '' }); } }); }); } document.body.addEventListener('mouseover', async (e) => { const link = e.target.closest('a[href*="/post/"]'); if (!link || !isInsideChat(link)) return; const match = link.href.match(/(mitmachim\.top|otzaria\.org).*?\/post\/(\d+)/); if (!match) return; clearTimeout(hideTimeout); const pid = match[2]; const fullUrl = link.href; const rect = link.getBoundingClientRect(); previewPopup.style.left = `${rect.left + window.scrollX}px`; previewPopup.style.top = `${rect.bottom + window.scrollY + 8}px`; previewPopup.innerHTML = '<i class="fa fa-spinner fa-spin"></i> טוען תצוגה מקדימה...'; previewPopup.style.display = 'block'; const data = await fetchPostContent(fullUrl, pid); if (!data) return; previewPopup.innerHTML = ` <div style="font-weight: bold; color: #007bff; margin-bottom: 8px; display: flex; align-items: center;"> ${data.avatarHtml || '<i class="fa fa-user" style="margin-left: 8px;"></i>'} <span>${data.author}:</span> </div> <div class="post-preview-body">${data.content}</div> `; }); document.body.addEventListener('mouseout', (e) => { const link = e.target.closest('a[href*="/post/"]'); if (link && isInsideChat(link)) { hideTimeout = setTimeout(() => { if (activeRequest) { try { activeRequest.abort(); } catch(e){} } previewPopup.style.display = 'none'; }, 300); } }); // ========================================== // הפעלה מבוקרת ללא עומס DOM // ========================================== enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); let debounceTimer; const domObserver = new MutationObserver(() => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { enhancePosts(); enhanceTopicHeaderTools(); integrateIntoLeftSidebar(); }, 100); }); domObserver.observe(document.body, { childList: true, subtree: true }); })();עודכן לגרסה 4.9
@מחנה-ידידים עשיתי גירסה שכוללת קישור ישיר לפוסט המקור - על בסיס הסקריפט שלך.
מיועד כמובן עבור מי שיש לו את התוסף Tampermonkey בדפדפן.
פרסתי את זה בגיטאהב, כך שזה יאפשר עדכון אוטומטי במקרה הצורך.
להתקנה לחץ כאן - ולאשר התקנה.
ניתן לתת
בגיטאב של הסקריפט שלי כאן: https://github.com/Tzadikvtovlo/Mitmachim-QuickChat-Linker
-
@מחנה-ידידים יש מצב לזה גם לפורום רכוסניק
תודה רבה@Tיו_ תעשה העתק הדבק, ותחליף את הכתובת של מתמחים בפורום שאתה רוצה.
-
@Tיו_ תעשה העתק הדבק, ותחליף את הכתובת של מתמחים בפורום שאתה רוצה.
@צדיק-וטוב-לו-0 קודם זה לא הפורום שלי
אני ישלח למנהל שם
השאלה אם @מחנה-ידידים מאשר את זה -
@צדיק-וטוב-לו-0 קודם זה לא הפורום שלי
אני ישלח למנהל שם
השאלה אם @מחנה-ידידים מאשר את זה@Tיו_ זה לא קשור למנהל.
אתה מתקין את זה לעצמך, ורק לך מופיע הכפתור. -
@Tיו_ זה לא קשור למנהל.
אתה מתקין את זה לעצמך, ורק לך מופיע הכפתור.@צדיק-וטוב-לו-0 לא הצלחתי להבין איך אני מתקין את זה?
-
@צדיק-וטוב-לו-0 לא הצלחתי להבין איך אני מתקין את זה?
-
@מחנה-ידידים עשיתי גירסה שכוללת קישור ישיר לפוסט המקור - על בסיס הסקריפט שלך.
מיועד כמובן עבור מי שיש לו את התוסף Tampermonkey בדפדפן.
פרסתי את זה בגיטאהב, כך שזה יאפשר עדכון אוטומטי במקרה הצורך.
להתקנה לחץ כאן - ולאשר התקנה.
ניתן לתת
בגיטאב של הסקריפט שלי כאן: https://github.com/Tzadikvtovlo/Mitmachim-QuickChat-Linker
צדיק-וטוב-לו-0 כתב:
@מחנה-ידידים עשיתי גירסה שכוללת קישור ישיר לפוסט המקור - על בסיס הסקריפט שלך.
מיועד כמובן עבור מי שיש לו את התוסף Tampermonkey בדפדפן.
פרסתי את זה בגיטאהב, כך שזה יאפשר עדכון אוטומטי במקרה הצורך.
להתקנה לחץ כאן - ולאשר התקנה.
עודכן לגירסא 2.0
מעכשיו יש תצוגה מקדימה בתוך הצאט לקישורים בתוך הפורום (וכן לקישורים לפורום אוצריא).
ניתן לעדכן ידנית דרך ממשק המשתמש ב Tampermonkey.
(או לחכות לעדכון אוטומטי, בהנחה שלא בוטל בהגדרות) -
שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.
נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.
בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗
הרשמה התחברות

