המלצה | חדש בפורום! נושאים שנצפו לאחרונה!
-
אולי כדאי באמת לפתח תוסף עם שיפורים למתמחים טופ
כל ההצעות ייעול
כל הרעיונות יכנסו לתוסף אחד שיפותח ויתווסף, כשנודביבי יוסיפו את זה להגדרות שלהם אז יהיה ניתן להסיר. -
@צדיק-תמים כתב בהמלצה | חדש בפורום! נושאים שנצפו לאחרונה!:
@לאצי אתה מזהה מעבר בין עמודים על ידי MutationObserver במקום הhooks ש nodebb פולט, מחלץ מידע על הנושא הנוכחי עם טריקים במקום לקחת מajaxify.data, וכן הלאה
אני רואה שאתה מבין, אז אולי תכתוב את זה אתה בנודביבי בדרך הנכונה? (או שפשוט תנחה את AI איך לכתוב את זה לנודביבי... יותר קל...)
-
@יוסף-אלחנן כתב בהמלצה | חדש בפורום! נושאים שנצפו לאחרונה!:
אגב, @צדיק-תמים כמה שאני יודע, אין גרסאות חדשות לזה והוא לא בטוח מבחינת אבטחה וכדו'
שמעת על זה?מעניין לא שמעתי
הם מציעים חלופה (חלקית לדעתי) כאן: https://github.com/kiwibrowser/src.next#kiwi-browser -
@צדיק-תמים אוקיי, אבל הוא מעדכן שלא יצאו עוד עידכונים...
-
היי, שימו לב! בפורום נודביבי זה קיים בפרופיל המשתמש!
(אצלי זה בקישור https://community.nodebb.org/me/read)
מעניין למה פה זה לא קיים.
עריכה: זה מה שענו לי בנודביבי - הם כנראה צריכים לשדרג את ה-nodebb שלהם לגרסה העדכנית ביותר.אז @שמואל , בבקשה.
אגב, עברתי קצת על פורום נודביבי וראיתי שהרבה דברים שם שונים לגמרי מכאן. כלומר, הרבה מהצעות הייעול שישנם כאן בפורום כבר מיושמות מזמן בנודביבי -
יפה מאוד! יעיל בהחלט!
@לאצי כתב בהמלצה | חדש בפורום! נושאים שנצפו לאחרונה!:
וכאן המקום להודות ל @עדלאידע שבהשראת הסקריפט שלו יצרתי את הסקריפט הזה.
תהיה בריא...
ההשראה גרמה לך גם לחפש את האלמנט "פוסטים אחרונים" ולשים את הכפתור שלך מתחתיו...
עכשיו מי שמשתמש בסקריפט שלי ושלך - הכפתורים שלנו רבים בינהם מי יהיה מתחת ל"פוסטים אחרונים"
אתה יכול לראות כשאתה עושה כמה ריענונים קשיחים שכל פעם כפתור אחר נמצא מתחת ל"פוסטים אחרונים"
שיניתי את הסקריפט שלך כך שהכפתור יחפש את "נושאים שלא נפתרו" ויהיה מעליו.חוץ מזה, עצבן אותי שהטולטיפ מאוד שונה מהטולטיפ המקורי
אז עצבתי את זה כמו הטולטיפ המקורי
ואז נזכרתי שבסקריפט שלי בכלל אין טולטיפ...
וגם הגדרתי שכשהסרגל כפתורים במצב מורחב, אז:
- הטולטיפ לא יהיה מוצג
- יהיה כתוב "נצפו לאחרונה"
וגם הסרתי קטעים מיותרים בקוד (והיה קצת יותר מידי...)
אז תהנה:// ==UserScript== // @name Mitmachim Top - נצפו לאחרונה (v2.0.4 - Syntax Check) // @namespace http://tampermonkey.net/ // @version 2.0.4 // @description בדיקה מחודשת של תחביר ותפיסת שגיאות מוקדמות. // @author לאצי&AI // @match https://mitmachim.top/* // @icon https://mitmachim.top/assets/uploads/files/1744298283200-font_awesome_5_solid_history.svg.png // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @run-at document-idle // ==/UserScript== (function() { 'use strict'; function ensureDependencies(callback) { let checks = 0; const MAX_CHECKS = 120; const CHECK_INTERVAL = 100; console.log("[LastViewed] Starting dependency check..."); const interval = setInterval(function() { const jQueryReady = typeof $ === 'function'; // More robust check for jQuery const $navList = jQueryReady ? $('nav[component="sidebar/left"] ul#main-nav') : null; const navListReady = $navList && $navList.length > 0; if (navListReady) { clearInterval(interval); console.log(`[LastViewed] Dependencies ($) AND Nav List found after ${checks + 1} checks.`); try { callback(); // Run the main script logic } catch(e) { console.error("[LastViewed] Error executing initialize callback:", e); } } else { checks++; if (checks >= MAX_CHECKS) { clearInterval(interval); console.error(`[LastViewed] Dependency check FAILED after ${MAX_CHECKS} checks (Timeout).`); // Provide detailed status on failure console.error(`[LastViewed] Final Status: jQuery=${typeof $ === 'function'}, NavList Element Found=${jQueryReady ? $('nav[component="sidebar/left"] ul#main-nav').length : 'N/A (jQuery missing)'}`); } } }, CHECK_INTERVAL); } const STORAGE_KEY = 'mitmachim_last_viewed_topics'; const MAX_HISTORY_ITEMS = 20; const TOPIC_URL_PREFIX = 'https://mitmachim.top/topic/'; const DEBOUNCE_DELAY = 300; const styles = ` /* Popup Styles */ #last-viewed-popup { display: flex; flex-direction: column; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 550px; max-height: 80vh; overflow-y: auto; background-color: var(--bs-body-bg, #ffffff); color: var(--bs-body-color, #212529); border: 1px solid var(--bs-border-color, #dee2e6); box-shadow: 0 5px 15px rgba(0,0,0,0.2); padding: 20px; z-index: 1060; direction: rtl; font-family: "Assistant", sans-serif; font-size: 14px; border-radius: var(--bs-border-radius, 0.375rem); } #last-viewed-popup h2 { flex-shrink: 0; margin-top: 0; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--bs-border-color-translucent, rgba(0,0,0,0.175)); color: var(--bs-heading-color, inherit); text-align: right; font-size: 1.25rem; font-weight: 600; } #last-viewed-popup ul#last-viewed-list { flex-grow: 1; list-style: none; padding: 0; margin: 0; overflow-y: auto; } #last-viewed-popup li { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px dashed var(--bs-border-color-translucent, rgba(0,0,0,0.1)); text-align: right; line-height: 1.5; } #last-viewed-popup li:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } #last-viewed-popup a { text-decoration: none; color: var(--bs-link-color, #0d6efd); font-weight: 600; } #last-viewed-popup a:hover { text-decoration: underline; color: var(--bs-link-hover-color, #0a58ca); } #last-viewed-popup .popup-controls { flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; margin-top: 15px; padding-top: 10px; border-top: 1px solid var(--bs-border-color-translucent, rgba(0,0,0,0.175)); } #last-viewed-popup .close-popup-btn, #last-viewed-popup #clear-last-viewed { padding: 0.375rem 0.75rem; font-size: 0.9rem; border-radius: var(--bs-border-radius-sm, 0.25rem); cursor: pointer; text-align: center; vertical-align: middle; user-select: none; border: 1px solid transparent; transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; } #last-viewed-popup .close-popup-btn { color: var(--bs-secondary-color, #6c757d); background-color: var(--bs-secondary-bg, #e9ecef); border-color: var(--bs-secondary-border, #dee2e6); } #last-viewed-popup .close-popup-btn:hover { background-color: var(--bs-secondary-active-bg, #ced4da); } #last-viewed-popup #clear-last-viewed { color: var(--bs-danger-color, #dc3545); background-color: var(--bs-danger-bg, #f8d7da); border-color: var(--bs-danger-border, #f5c2c7); } #last-viewed-popup #clear-last-viewed:hover { background-color: var(--bs-danger-active-bg, #f1aeb5); } #last-viewed-popup::-webkit-scrollbar { width: 7px; height: 7px; background-color: #e6f9ff; border-radius: 4px; } #last-viewed-popup::-webkit-scrollbar-thumb { background: #99ceff; border-radius: 100px; } #last-viewed-popup::-webkit-scrollbar:hover { width: 12px; } /* Search box styles */ #last-viewed-search-container { flex-shrink: 0; margin-bottom: 15px; } #last-viewed-search { width: 100%; padding: 0.375rem 0.75rem; font-size: 1rem; font-weight: 400; line-height: 1.5; color: var(--bs-body-color); background-color: var(--bs-body-bg); background-clip: padding-box; border: 1px solid var(--bs-border-color); appearance: none; border-radius: var(--bs-border-radius); transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; } #last-viewed-search:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13,110,253,.25); } #last-viewed-search::placeholder { color: #6c757d; opacity: 1; } #last-viewed-no-results { text-align: center; color: #6c757d; margin-top: 1rem; display: none; } /* Dynamic Tooltip Styles */ #last-viewed-dynamic-tooltip{position:fixed;background-color:#212529;color:#fff;padding:2px 10px;border-radius:6px;font-size:16px;font-weight:150;font-family:"Assistant",sans-serif;white-space:nowrap;z-index:1100;pointer-events:none;--arrow-size:6px;} #last-viewed-dynamic-tooltip::before{content:"";position:absolute;top:50%;left:100%;margin-top:calc(-1*var(--arrow-size));border-width:var(--arrow-size);border-style:solid;border-color:transparent transparent transparent #212529;} `; GM_addStyle(styles); function getLastViewed() { const data = GM_getValue(STORAGE_KEY, '[]'); try { return JSON.parse(data); } catch (e) { console.error("[LastViewed] Error parsing stored data:", e); return []; } } function setLastViewed(items) { const limitedItems = items.slice(-MAX_HISTORY_ITEMS); GM_setValue(STORAGE_KEY, JSON.stringify(limitedItems)); } function addTopicToHistory(topicTitle, topicUrl) { if (!topicTitle || !topicUrl) return; topicTitle = topicTitle.trim(); const normalizedUrl = topicUrl.split('?')[0].split('#')[0]; let items = getLastViewed(); const existingIndex = items.findIndex(item => item && item.url === normalizedUrl && item.title === topicTitle); if (existingIndex !== -1) { items[existingIndex].timestamp = Date.now(); } else { items = items.filter(item => item && item.url !== normalizedUrl || item.title !== topicTitle); items.push({ title: topicTitle, url: normalizedUrl, timestamp: Date.now() }); } setLastViewed(items); } function getTopicDetailsFromPage() { const currentUrl = window.location.href; if (!currentUrl.startsWith(TOPIC_URL_PREFIX)) { return null; } let title = ''; let $titleSpan = $('h1[component="post/header"] span[component="topic/title"]'); if ($titleSpan.length > 0) { let $tempSpan = $titleSpan.clone(); $tempSpan.find('span[style*="font-size: 10px"]').remove(); title = $tempSpan.text().replace(/\s+/g, ' ').trim(); } if (!title) { title = document.title.replace(/ \| מתמחים טופ.*/, '').trim(); } const normalizedUrl = currentUrl.split('?')[0].split('#')[0]; return { title: title, url: normalizedUrl }; } let debounceTimer; function debounce(func, delay) { return function(...args) { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { if (typeof func === 'function') { func.apply(this, args); } else { console.error("[LastViewed] Debounced function is not valid at time of execution."); } }, delay); }; } const saveCurrentTopicDebounced = debounce(function() { const currentTopic = getTopicDetailsFromPage(); if (currentTopic && currentTopic.title) { addTopicToHistory(currentTopic.title, currentTopic.url); } }, DEBOUNCE_DELAY); function closePopupAndRemoveListener() { const $popup = $('#last-viewed-popup'); if ($popup.length) { $(document).off('click.closeLastViewed'); $popup.remove(); } } function addClosePopupListener() { $(document).off('click.closeLastViewed'); $(document).on('click.closeLastViewed', function(event) { if (!$('#last-viewed-popup').length) { $(document).off('click.closeLastViewed'); return; } if (!$(event.target).closest('#last-viewed-popup').length && !$(event.target).closest('#last-viewed-btn-li').length) { closePopupAndRemoveListener(); } }); } function filterLastViewedList() { const searchTerm = $('#last-viewed-search').val().toLowerCase().trim(); const $listItems = $('#last-viewed-list li'); let visibleCount = 0; $listItems.each(function() { const $item = $(this); const itemText = $item.find('a').text().toLowerCase(); if (itemText.includes(searchTerm)) { $item.show(); visibleCount++; } else { $item.hide(); } }); if (visibleCount === 0 && $listItems.length > 0) { $('#last-viewed-no-results').show(); } else { $('#last-viewed-no-results').hide(); } } function showLastViewedPopup() { if ($('#last-viewed-popup').length) return; closePopupAndRemoveListener(); console.log("[LastViewed] Opening popup."); let items = getLastViewed(); const uniqueItems = []; const seenTitles = new Set(); for (let i = items.length - 1; i >= 0; i--) { const item = items[i]; if (!seenTitles.has(item.title)) { uniqueItems.push(item); seenTitles.add(item.title); } } items = uniqueItems; const popup = document.createElement('div'); popup.id = 'last-viewed-popup'; const searchContainer = document.createElement('div'); searchContainer.id = 'last-viewed-search-container'; const searchInput = document.createElement('input'); searchInput.type = 'search'; searchInput.id = 'last-viewed-search'; searchInput.placeholder = 'חיפוש בנצפו לאחרונה...'; searchInput.className = 'form-control'; searchContainer.appendChild(searchInput); popup.appendChild(searchContainer); const title = document.createElement('h2'); title.textContent = 'שרשורים שנצפו לאחרונה'; popup.appendChild(title); if (items.length === 0) { const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'לא נצפו שרשורים לאחרונה.'; popup.appendChild(emptyMsg); } else { const list = document.createElement('ul'); list.id = 'last-viewed-list'; for (let i = 0; i < items.length; i++) { const item = items[i]; const listItem = document.createElement('li'); const link = document.createElement('a'); link.href = item.url; link.textContent = item.title || 'ללא כותרת'; link.target = '_blank'; listItem.appendChild(link); list.appendChild(listItem); } popup.appendChild(list); const noResultsMsg = document.createElement('p'); noResultsMsg.id = 'last-viewed-no-results'; noResultsMsg.textContent = 'לא נמצאו שרשורים תואמים.'; popup.appendChild(noResultsMsg); } const controlsDiv = document.createElement('div'); controlsDiv.className = 'popup-controls'; const clearButton = document.createElement('button'); clearButton.textContent = 'נקה היסטוריה'; clearButton.id = 'clear-last-viewed'; controlsDiv.appendChild(clearButton); const closeButton = document.createElement('button'); closeButton.textContent = 'סגור'; closeButton.className = 'close-popup-btn'; controlsDiv.appendChild(closeButton); popup.appendChild(controlsDiv); document.body.appendChild(popup); $('#clear-last-viewed').on('click', function(e) { e.stopPropagation(); if (confirm('האם אתה בטוח שברצונך למחוק את היסטוריית הצפייה?')) { GM_deleteValue(STORAGE_KEY); closePopupAndRemoveListener(); console.log("[LastViewed] History cleared."); } }); $('.close-popup-btn').on('click', function(e) { e.stopPropagation(); closePopupAndRemoveListener(); }); $('#last-viewed-search').on('input', filterLastViewedList); setTimeout(addClosePopupListener, 50); $('#last-viewed-search').trigger('focus'); } let currentTooltip = null; const TOOLTIP_TEXT = "נצפו לאחרונה"; const TOOLTIP_GAP = -88.5; function showDynamicTooltip(targetElement) { const sidebar = document.querySelector('nav[component="sidebar/left"]'); if (sidebar && sidebar.classList.contains('open')) { return; } removeDynamicTooltip(); currentTooltip = document.createElement('div'); currentTooltip.id = 'last-viewed-dynamic-tooltip'; currentTooltip.textContent = TOOLTIP_TEXT; document.body.appendChild(currentTooltip); const rect = targetElement.getBoundingClientRect(); const tooltipRect = currentTooltip.getBoundingClientRect(); let top = rect.top + (rect.height / 2) - (tooltipRect.height / 2); let left = rect.left + rect.width + TOOLTIP_GAP - 58; if (top < 5) top = 5; if (top + tooltipRect.height > window.innerHeight - 5) top = window.innerHeight - tooltipRect.height - 5; if (left + tooltipRect.width > window.innerWidth - 5) left = window.innerWidth - tooltipRect.width - 5; currentTooltip.style.top = `${top}px`; currentTooltip.style.left = `${left}px`; currentTooltip.style.right = 'auto'; } function removeDynamicTooltip() { if (currentTooltip) { currentTooltip.remove(); currentTooltip = null; } } function createSidebarButton() { console.log("[LastViewed] Attempting createSidebarButton execution..."); if ($('#last-viewed-btn-li').length > 0) { console.log("[LastViewed] Button LI already exists."); return; } console.log("[LastViewed] Selecting navList..."); const $navList = $('nav[component="sidebar/left"] ul#main-nav'); console.log(`[LastViewed] $navList length: ${$navList.length}`); if ($navList.length === 0) { console.error("[LastViewed] FAILED to find $navList."); return; } // Exit if navList not found console.log("[LastViewed] Selecting recentPostsItem..."); const $recentPostsItem = $navList.find('li a[href="/recent"]').closest('li'); console.log(`[LastViewed] $recentPostsItem length: ${$recentPostsItem.length}`); if ($recentPostsItem.length === 0) { console.error("[LastViewed] FAILED to find $recentPostsItem."); return; } // Exit if recent post item not found console.log("[LastViewed] Creating $newItem element..."); const $newItem = $(` <li class="nav-item mx-2" id="last-viewed-btn-li" data-bs-original-title="נצפו לאחרונה"> <a class="nav-link navigation-link d-flex gap-2 justify-content-between align-items-center" href="#" role="button" id="last-viewed-btn" aria-label="נצפו לאחרונה"> <span class="d-flex gap-2 align-items-center text-nowrap truncate-open"> <span class="position-relative"> <i class="fa fa-fw fa-history" data-content=""></i> <span component="navigation/count" class="visible-closed position-absolute top-0 start-100 translate-middle badge rounded-1 bg-primary hidden"></span> </span> <span class="nav-text small visible-open fw-semibold text-truncate">נצפו לאחרונה</span> </span> <span component="navigation/count" class="visible-open badge rounded-1 bg-primary hidden"></span> </a> </li> `); console.log("[LastViewed] Attaching listeners to $newItem..."); $newItem.find('a#last-viewed-btn').on('click', function(event) { event.preventDefault(); event.stopPropagation(); removeDynamicTooltip(); showLastViewedPopup(); }); $newItem.on('mouseenter', function(event) { showDynamicTooltip(event.currentTarget); }).on('mouseleave', function() { removeDynamicTooltip(); }); try { console.log("[LastViewed] Attempting insertBefore..."); $newItem.insertBefore($('li[data-bs-original-title="נושאים שלא נפתרו"]')); setTimeout(() => { if ($('#last-viewed-btn-li').length > 0) { console.log("[LastViewed] Button inserted successfully (verified)."); } else { console.error("[LastViewed] Button insertion failed silently (not found after insertBefore)."); } }, 50); } catch (e) { console.error("[LastViewed] Error during button insertion:", e); } } let observer = null; function setupMutationObserver() { const targetNode = document.getElementById('content'); if (!targetNode) { console.error("[LastViewed] Cannot find target node '#content'. Retrying..."); setTimeout(setupMutationObserver, 1000); return; } const config = { childList: true, subtree: true }; const callback = function(mutationsList, observer) { let titleSpanFound = false; for(const mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if ($(node).find('span[component="topic/title"]').length > 0 || $(node).is('span[component="topic/title"]')) { titleSpanFound = true; } } }); } if (titleSpanFound) break; } if (titleSpanFound) { saveCurrentTopicDebounced(); } }; observer = new MutationObserver(callback); observer.observe(targetNode, config); const parentObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.removedNodes.forEach(removedNode => { if (removedNode.id === 'content') { console.warn("[LastViewed] Target node #content was removed. Re-initializing observer."); if(observer) observer.disconnect(); setTimeout(setupMutationObserver, 50); } }); }); }); if (targetNode.parentNode) { parentObserver.observe(targetNode.parentNode, { childList: true }); } } function initialize() { console.log("[LastViewed] Initializing script v2.0.1 (Increased Timeout)..."); if (typeof createSidebarButton !== 'function' || typeof saveCurrentTopicDebounced !== 'function' || typeof setupMutationObserver !== 'function') { console.error("[LastViewed] CRITICAL: One or more core functions not defined!"); return; } console.log("[LastViewed] Calling createSidebarButton..."); createSidebarButton(); console.log("[LastViewed] Calling saveCurrentTopicDebounced (initial)..."); saveCurrentTopicDebounced(); console.log("[LastViewed] Calling setupMutationObserver..."); setupMutationObserver(); console.log("[LastViewed] Initialization complete."); } ensureDependencies(initialize); })();
-
למה לא לאחד אותם לסקריפט אחד?
או שזה מה שעשיתם? -
@עדלאידע אני לא אשם בכלום, זה הכל AI... ובקשר לטוטליפ בהתחלה הוא אמנם יצר לי טוטליפ זהה לזה של הפורום אך בשל בעיות שונות ומשונות שצצו בהמשך הוא העניק לי הסברים לרוב (שאת חלקם לא הבנתי או לא ניסיתי להבין...) מדוע עליו לשנות את הטוטליפ. אז תודה על הכל.
עריכה: יש לך באג רציני ששרשורים מופיעים כמה פעמים. זה נוגד את מה שכתבתי בתכונות הסקריפט. אה, וזה גם מעצבן...
אצלי זה גם היה בהתחלה, על אף שכן אמרתי לAI למנוע זאת, והתבר שזה קורה כי הוא קרא את כל הURL של השרשור, ואז כשעוברים לפוסט אחר באותו שרשור אז הURL משתנה וזה מה שגרם לו להוסיף את אותו שרשור כמה פעמים, כל פעם בגלל פוסט אחר. אז פשוט הגדרתי לו שיקרא רק את החלק הראשון של הURL שכולל רק את זהות השרשור.ותודה שהשארת לי את הקרדיט בקוד... -
@לאצי כתב בהמלצה | חדש בפורום! נושאים שנצפו לאחרונה!:
בקשר לטוטליפ בהתחלה הוא אמנם יצר לי טוטליפ זהה לזה של הפורום אך בשל בעיות שונות ומשונות שצצו בהמשך הוא העניק לי הסברים לרוב (שאת חלקם לא הבנתי או לא ניסיתי להבין...) מדוע עליו לשנות את הטוטליפ.
איך הוא יודע לחרטט דברים ואז לנמק אותם בצורה כ"כ משכנעת...
יש לך באג רציני ששרשורים מופיעים כמה פעמים. זה נוגד את מה שכתבתי בתכונות הסקריפט. אה, וזה גם מעצבן...
תוקן.
אצלי זה גם היה בהתחלה, על אף שכן אמרתי לAI למנוע זאת, והתבר שזה קורה כי הוא קרא את כל הURL של השרשור, ואז כשעוברים לפוסט אחר באותו שרשור אז הURL משתנה וזה מה שגרם לו להוסיף את אותו שרשור כמה פעמים, כל פעם בגלל פוסט אחר. אז פשוט הגדרתי לו שיקרא רק את החלק הראשון של הURL שכולל רק את זהות השרשור.
אני פשוט עשיתי שהוא יקרא את כל הרשימה של הנושאים האחרונים שנצפו, ואם יש כותרת כפולה הוא ישמור רק את הנושא האחרון שנצפה, הרבה יותר פשוט.
עדכנתי את הסקריפט.