您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
מעולם לא היה קל יותר לגלוש ב-FxP.
当前为
// ==UserScript== // @name BetterFxP for Tampermonkey // @namespace http://tampermonkey.net/ // @version 1.1 // @description מעולם לא היה קל יותר לגלוש ב-FxP. // @author You // @match https://www.fxp.co.il/* // @supportURL https://discord.gg/AW7CeG7 // @require https://update.greasyfork.org/scripts/439099/1203718/MonkeyConfig%20Modern%20Reloaded.js // @icon https://lh3.googleusercontent.com/j-CdJwaXX0eoqlMDLLYfbYTuuaFUM5Ep-Mph1UNktCZSYbm665WoIwGGw4d1iXxQWkLMDYior_xS8OKfWCBf1i4srw=s120 // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @grant GM_addElement // @grant GM_getResourceText // @grant GM_registerMenuCommand // @grant GM_addValueChangeListener // @run-at document-start // @resource pms https://update.greasyfork.org/scripts/476628/1259426/fxp%20anti-delete%20PMs.user.js // @license MIT // ==/UserScript== // @noframes const cfg = new MonkeyConfig({ title: 'הגדרות FxPlus+', menuCommand: true, params: { hideBigImages: { label: "הסתר את הכתבות הגדולות מדך הבית", type: 'checkbox', default: false }, hideGames: { label: "הסתר את אזור המשחקים מדף הבית", type: 'checkbox', default: false }, hideArticles: { label: "הסתר כתבות מדף הבית", type: 'checkbox', default: false }, resizeSignatures: { label: "חותך חתימות גדולות", type: 'checkbox', default: false }, hideAds: { label: "הסתר מודעות", type: 'checkbox', default: false }, hideNagish: { label: "הסתר את תפריט הנגישות", type: 'checkbox', default: false }, showFriends: { label: "הצג חברים באשכולת", type: 'checkbox', default: false }, showAutoPinned: { label: "הצג יותר משלושה אשכולות נעוצים", type: 'checkbox', default: false }, disableLiveTyping: { label: "אל תודיע שאני מקליד", type: 'checkbox', default: false }, showDeletedPost: { label: "הצג פוסט שנמחק", type: 'checkbox', default: false }, showLikeLimit: { label: "הצג מגבלת לייקים", type: 'checkbox', default: false }, connectedStaff: { label: "הצג צוות מחובר", type: 'checkbox', default: false }, audioChange: { // https://www.tzevaadom.co.il/static/sounds/calm.wav label: ":קישור לקובץ שמע עבור התראה", type: 'text', default: '' }, hideCategories: { // 4428, 13 label: ":רשימה של קטגוריות להסתרה", type: 'text', default: '' }, smiles: { // https://yoursmiles.org/tsmile/heart/t4524.gif label: ':רשימה של קישורים לסמיילים', type: 'text', default: '', long: 3 }, showCounts: { label: 'מציג את מספר הפוסטים ואת כמות המשתמשים המחוברים', type: 'checkbox', default: false, }, pms: { label: "מציג הודעות פרטיות שנמחקו", type: "checkbox", default: false }, showForumStats: { label: 'הצג סטטיסטיקות פורומים', type: "checkbox", default: false } } }); document.addEventListener('keydown', function (e) { if (e.ctrlKey && e.key.toLowerCase() === 'y') { e.preventDefault(); cfg.open("window", { windowFeatures: { width: 500, height: 500 } }); } }); /* CKEDITOR.tools.callFunction(41, this); //131,'almoni-dl' The system that automatically disables and enables the feature is currently not working in either version. TODO: - Implement audio file upload - Support multiple users - Like add http to check - disable/enable on the same page and prevent reload - Add features: - Auto night mode - Auto reader mode - BBCode support - Hide sticky posts */ const rawWindow = unsafeWindow; const queryParams = new URLSearchParams(location.search); function waitForObject(path) { return new Promise((resolve, reject) => { const timer = setInterval(() => { const obj = path.split('.').reduce((o, key) => (o && key in o ? o[key] : undefined), rawWindow); if (typeof obj !== "undefined") { clearInterval(timer); resolve(obj); } }, 100); }); } function onMatchIfLoggedIn(match, permissions, callback) { rawWindow.LOGGEDIN && onMatch(match, permissions, callback); } // window.addEventListener('storage', (e) => { // console.log('Storage changed!'); // console.log('Key:', e.key); // console.log('Old Value:', e.oldValue); // console.log('New Value:', e.newValue); // console.log('Storage Area:', e.storageArea); // console.log('URL:', e.url); // }); function onMatch(match, permission, callback) { const hasPermission = permission === "none" || cfg.get(permission); if (!shouldRun(match) || !hasPermission) return; const docReady = /complete|interactive/.test(document.readyState); const runImmediately = !callback.toString().includes("document"); let teardown = () => {}; const executeFeature = () => { teardown(); teardown = callback() || (() => {}); }; if (runImmediately || docReady) { executeFeature(); } else { document.addEventListener('DOMContentLoaded', executeFeature); } GM_addValueChangeListener(permission, (key, oldVal, newVal) => { const func = newVal ? executeFeature : teardown; func(); }); } function injectStyle(match, permissions, css) { onMatch(match, permissions, function() { console.log(css); const styleElement = GM_addStyle(css); return () => styleElement?.remove(); }); } function shouldRun(matchPattern) { const urlPath = '/' + location.href.split('/').pop(); const pattern = new RegExp(matchPattern.replace('*', '.*')); return pattern.test(urlPath); } function fetcher(url) { return fetch(url).then(response => response.text()); } // Author ID: 967488 injectStyle("forumdisplay", "showAutoPinned", "#stickies li.threadbit:nth-child(n+4) { display: list-item !important; } .morestick { display: none !important; }"); injectStyle("*", "hideAds", "#adfxp, #related_main, .trc_related_container, .trc_spotlight_widget, .videoyoudiv, .OUTBRAIN { display: none !important }"); injectStyle("*", "hideNagish", ".nagish-button { display: none; }"); injectStyle("/(?:index.php)?", "hideCategories", `${cfg.get("hideCategories").split(", ").map(cId => `.hp_category:has(a[href="forumdisplay.php?f=${cId}"])`).join(',')} { display: none }`) // #cat${cId}, .hi4 { height: 337px } injectStyle("/(?:index.php)?", "hideArticles", "#slide { height:auto !important; } .mainsik { display: none; }"); injectStyle("/(?:index.php)?", "hideBigImages", ".big-image-class { display: none; }"); injectStyle("/(?:index.php)?", "hideGames", "#slide ~ div h1, .fxp2021_Games { display: none !important;"); // חותך חתימות גדולות לגודל המותר וזה תלוי במשתמש במקום באתר לשנות את החתימה שתתאים injectStyle("show(post|thread)|member.php", "resizeSignatures", ".signaturecontainer { max-width: 500px; max-height: 295px; overflow: hidden; }"); onMatchIfLoggedIn("private_chat.php?do=showpm|show(post|thread)", "disableLiveTyping", function() { const originalSendTypingInThread = rawWindow?.sendUserIsTypingInShowthread; const originalTypingSend = rawWindow?.typeingsend; rawWindow.sendUserIsTypingInShowthread = () => {}; rawWindow.typeingsend = () => {}; return () => { rawWindow.sendUserIsTypingInShowthread = originalSendTypingInThread; rawWindow.typeingsend = originalTypingSend; } }); onMatchIfLoggedIn("signature", "none", function() { const publishedThreadUrl = "https://www.fxp.co.il/showthread.php?t=16859147"; GM_addStyle(` #creditAddon { padding: .5em; text-align: center; } .addCreditBtn { margin: .2em 1em; background: #fff; border-radius: .2em; font-weight: 700; color: #004b67; border: 1px solid #c5c5c5; cursor: pointer; padding: 0; position: relative; width: 60px; height: 60px; display: inline-flex; justify-content: center; align-items: center; overflow: hidden; } .addCreditBtn img { border: 0; height: 100%; } .addCreditBtn .addCreditDesc { position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; color: #fff; background: rgba(0,0,0,.4); opacity: 1; } .addCreditBtn .addCreditDesc:hover { opacity: 0; } .addCreditBtn#addTextCredit .addCreditDesc:hover { opacity: 1; } .addCreditBtn#addXLimg { width: 110px; } `); const creditAddon = GM_addElement('div', { id: 'creditAddon', }) creditAddon.innerHTML = ` <div>שתף את הכיף!™ והוסף קרדיט לתוסף +FxPlus בחתימה שלך:</div> <div class="addCreditBtn" id="addLimg"> <img src="https://i.imagesup.co/images2/b059514f80af8c5ec69afc73356a4dfa3b771343.png"> <span class="addCreditDesc">128x128</span> </div> <div class="addCreditBtn" id="addMimg"> <img src="https://i.imagesup.co/images2/7797f421f0e4895878e51d09266a35355b214d5a.png"> <span class="addCreditDesc">48x48</span> </div> <div class="addCreditBtn" id="addTextCredit"> <span class="addCreditDesc">טקסט</span> </div>` creditAddon.querySelectorAll('#addLimg, #addMimg, #addTextCredit').forEach(element => { element.addEventListener('click', (event) => { const imgElement = event.target.parentElement.querySelector('img'); const iframeBody = document.querySelector(".cke_contents iframe").contentDocument.body; const creditLink = document.createElement('a'); creditLink.href = publishedThreadUrl; creditLink.target = '_blank'; if (imgElement) { const img = document.createElement('img'); img.src = imgElement.src; creditLink.appendChild(img); } else { creditLink.textContent = '+FxPlus'; } iframeBody.appendChild(creditLink); }); }); const smilieBox = document.querySelector('form[action*="signature"] .editor_smiliebox'); smilieBox.parentNode.insertBefore(creditAddon, smilieBox); }); onMatchIfLoggedIn("show(post|thread)", "showFriends", function() { (async () => { const REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes in milliseconds const storageKey = "refreshFriends"; const storedTime = GM_getValue(storageKey); if (storedTime) { const timeSinceLastRefresh = new Date().getTime() - new Date(storedTime).getTime(); if (timeSinceLastRefresh < REFRESH_INTERVAL) { return console.log('Friends list is still fresh, skipping refresh.'); } } let allFriendIds = [], temp = [] let page = 1, match; const regex = /<h4><a href="member\.php\?u=(\d+)"/g; while (temp.size < 100) { temp = []; const url = `https://www.fxp.co.il/profile.php?do=buddylist&pp=100&page=${page}`; const html = await fetcher(url); while ((match = regex.exec(html)) !== null) { temp.push(match[1]); } allFriendIds = allFriendIds.concat(temp); console.log(`Page ${page}: Total friend IDs collected so far: ${allFriendIds.size}`); // If the response seems to be exhausted or doesn't bring in new friends, break. if (!match) break; page++; } console.log('Fetched friend IDs:', allFriendIds); GM_setValue('friendIds', JSON.stringify(allFriendIds)); GM_setValue(storageKey, Date.now()); })(); const friendIds = JSON.parse(GM_getValue("friendIds", '[]')); if (!friendIds) return; let css = friendIds.map(id => '.username[href$="' + id + '"]::after').join(', ') let styleElement = GM_addStyle(` ${css} { content: ""; display: inline-block; width: 20px; height: 20px; background-image: url('https://w7.pngwing.com/pngs/236/25/png-transparent-computer-icons-avatar-friends-love-text-logo-thumbnail.png'); background-size: cover; }`) return () => styleElement?.remove() }) onMatchIfLoggedIn("*", "audioChange", function() { let isFeatureEnabled = true; Object.defineProperty(HTMLAudioElement.prototype, 'src', { set: function(value) { if (isFeatureEnabled && value === "https://images4.fxp.co.il/nodejs/sound.mp3") { value = cfg.get("audioChange"); } this.setAttribute('src', value); }, get: () => this.getAttribute('src'), configurable: true, enumerable: true, }); return () => { isFeatureEnabled = false; } }) onMatchIfLoggedIn("show(post|thread)", "smiles", async function() { const images = cfg.get("smiles").trim().split('\n'); if (images.length < 1) return; const editor = await waitForObject("vB_Editor.vB_Editor_QR"); console.log("vB_Editor is available:", editor); let temp = editor.config.smiley_descriptions, tmp = editor.config.smiley_images; for (const image of images) { if (!image) continue; editor.config.smiley_descriptions.push(`[img]${image}[/img]`); editor.config.smiley_images.push(`https://wsrv.nl/?url=${image}&w=30`); } return () => { editor.config.smiley_descriptions = temp; editor.config.smiley_images = tmp; } }) onMatchIfLoggedIn("show(post|thread)", "showLikeLimit", function() { const db = 'likes' + (window.USER_ID_FXP || '0'); const likeLimit = 15; const selector = '.button-like-holder > span[onclick="makelike(this.id);"]'; let likes = JSON.parse(GM_getValue(db, '[]')); let styleElement; const updateLikeButton = () => { console.log(likes); if (likes.length >= likeLimit) { styleElement = GM_addStyle(`${selector} { background-image: url("https://em-content.zobj.net/source/google/387/broken-heart_1f494.png"); }`); } else { // styleElement?.remove() } }; const updateTimer = () => { const oldestLike = Math.min(...likes); if (Date.now() > oldestLike) { likes = likes.filter(like => like !== oldestLike); GM_setValue(db, JSON.stringify(likes)); if (likes.length === 0) { clearInterval(timer); } } }; const timer = setInterval(updateTimer, likeLimit * 3000); updateLikeButton(); updateTimer(); document.querySelectorAll(selector).forEach(element => { element.addEventListener('click', function() { if (likes.length >= likeLimit) return; likes.push(Date.now() + likeLimit * 60 * 1000); GM_setValue(db, JSON.stringify(likes)); updateLikeButton(); }) }) return () => styleElement?.remove(); }) // https://greasyfork.org/en/scripts/476628-fxp-anti-delete-pms onMatchIfLoggedIn("do=showpm&pmid=", "pms", async function() { await waitForObject("socket"); new Function(GM_getResourceText("pms")).apply(rawWindow); }) onMatch("show(post|thread)", "showDeletedPost", function() { const targetPostId = queryParams.get('p'); const isPostExist = document.contains(document.getElementById('post_' + targetPostId)); if (!targetPostId || isPostExist) { return; } const elements = Array.from(document.querySelectorAll('.postbit')); const postIds = elements.map(el => parseInt(el.id.replace('post_', ''))); const index = postIds.filter(pid => pid < targetPostId).length - 1; // if (index === 0) index = 1; //need to be test const newElement = GM_addElement("li", { textContent: 'התגובה שאתה מנסה לראות נמחקה.', id: 'post_' + targetPostId, className: 'postbit postbitim postcontainer', //test how this show (innerHTML) style: "background-color: #ffdddd; border: 1px solid #ff0000; padding: 10px 0; border-radius: 5px; color: #333; font-weight: bold; text-align: center;" }) const targetElement = elements.at(index); targetElement.parentNode.insertBefore(newElement, targetElement.nextSibling); if (!queryParams.has('t')) { setTimeout(() => targetElement.scrollIntoView(), 500); } return () => newElement?.remove(); }); onMatch("forumdisplay", "connectedStaff", function() { const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '10px'); svg.setAttribute('height', '10px'); svg.setAttribute('viewBox', '0 0 24 24'); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill', '#00FF00'); path.setAttribute('d', 'm2 12a10 10 0 1 1 10 10 10 10 0 0 1 -10-10z'); svg.appendChild(path); const usernameElements = document.querySelectorAll('.flo .username'); usernameElements.forEach(async usernameElement => { const username = usernameElement.innerText; const userLink = usernameElement.href; const html = await fetcher(userLink); if (html.includes(username + ' מחובר/ת')) { usernameElement.insertAdjacentHTML('beforeend', svg.outerHTML); } }); return () => { usernameElements.forEach(({ lastChild }) => lastChild.tagName === 'svg' && lastChild.remove()); } }); onMatch("*", "showCounts", function() { const scripts = document.querySelectorAll('script[type="text/javascript"]:not([src])'); const script = Array.from(scripts).find(e => e.innerText.includes("counts")); if (!script) return; const lines = script.innerText.split("\n"); const counts = {}; for (const line of lines) { const match = line.match(/counts\["(.+?)"\]\s*=\s*(\d+);/); if (match) counts[match[1]] = parseInt(match[2]); } const container = document.createElement("div"); container.style.position = "fixed"; container.style.bottom = "10px"; container.style.right = "10px"; container.style.background = "white"; container.style.border = "1px solid #ccc"; container.style.padding = "10px 15px"; container.style.boxShadow = "0 0 5px rgba(0,0,0,0.2)"; container.style.borderRadius = "8px"; container.style.zIndex = "9999"; container.style.fontFamily = "Arial, sans-serif"; container.style.fontSize = "14px"; container.style.transition = "opacity 1s"; container.innerHTML = ` <strong>סטטיסטיקה:</strong><br> מחוברים: ${counts["#total_online"]?.toLocaleString() ?? 'N/A'}<br> פוסטים: ${counts["#total_posts"]?.toLocaleString() ?? 'N/A'} `; document.body.appendChild(container); setTimeout(() => { container.style.opacity = "0"; container.addEventListener("transitionend", container.remove); }, 5000); }); /* the old messy code with all those functions maybe one day I'll have AI rewrite it in cleaner vanilla JavaScript with fewer indentations. */ onMatch("forumdisplay", "showForumStats", function() { GM_addStyle(` #forumStatsContainer { width: 100%; clear: both; background: #feffe5; border: 1px solid #C4C4C4; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; box-sizing: border-box; } #forumStats { padding: 1em; text-align: center; position: relative; padding-bottom: 1.5em; } .statTable { border: 1px solid #f1f1f1; margin: 0 0.5em; margin-bottom: 1em; border-top: 0; border-bottom: 0; } .statTable th { font-weight: bold; text-align: center; padding: 0.5em; } .statTable td { padding: 0.1em 0.5em; } #detailedStatsBtn { position: absolute; bottom: 0; left: 50%; border-bottom: none !important; border-bottom-left-radius: 0; border-bottom-right-radius: 0; transform: translateX(-50%); } .dimScreen { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.75); z-index: 111; display: none; } #popupBox { z-index: 1200; position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; pointer-events: none; } .popupContainer { pointer-events: all; animation: fadeInTop 0.3s; display: none; } .popupContainer.greenTopPopup .popupTop { background: #1d9655; } .popupContainer.orangeTopPopup .popupTop { background: #ea861c; } .popupContainer.alertTopPopup .popupTop { background: #ef1700; } .popupTop { background: #1CA4EA; color: #fff; font-size: 1.4em; border-top-left-radius: 0.2em; border-top-right-radius: 0.2em; padding: 0.5em 2em; text-align: center; } .popupTop .subtitle { font-size: 0.5em; color: rgba(255, 255, 255, 0.64); } .popupImg { width: 3em; height: 3em; background: inherit; padding: 0.2em; border-radius: 50%; margin: 0 auto; margin-top: -1.8em; } .popupBottom { background: #fff; border-bottom-left-radius: 0.2em; border-bottom-right-radius: 0.2em; padding: 1em 2em; text-align: center; max-height: calc(80vh - 3em); max-width: 90vw; box-sizing: border-box; overflow: auto; } `) function getDupeSortedDictionary(arr) { var counts = {}; //count each one for (var i = 0; i < arr.length; i++) { counts[arr[i]] = (counts[arr[i]] || 0) + 1; } var sortedArr = []; //add all properties to an array for (var prop in counts) { sortedArr.push({ value: prop, count: counts[prop] }); } sortedArr.sort(function(a, b) //sort the array according to the counts or alphabetically { if (b.count === a.count) { if (b.value < a.value) return 1; else if (b.value > a.value) return -1; else return 0; } else return b.count - a.count; }); return sortedArr; } //adds a window with a specific id and dims the background function openPopupWindow(id, img, title, content, additionalClass) { if ($("#popupBox").length === 0) { $("body").append($("<div>", { id: "popupBox" })); } //do not open a popup if one already exists if ($(".popupContainer").length === 0) { $("body").append($("<div>", { class: "dimScreen", id: "dim_" + id }).click(function() { removePopupWindow(id); })); var popup = $("<div>", { class: "popupContainer", id: id }).append( $("<div>", { class: "popupTop" }).append( $("<div>", { class: "popupImg" }).append( $("<img>", { src: img }) ) ).append( $("<div>", { class: "popupTitle" }).append(title) ) ).append( $("<div>", { class: "popupBottom" }).append(content) ); if (additionalClass) popup.addClass(additionalClass); $("#popupBox").append(popup); $("#dim_" + id).fadeIn(300, function() { $("#" + id).show(); }); } } //removes completely a popup window function removePopupWindow(id) { if ($("#" + id).length > 0) { $("#" + id).remove(); $("#dim_" + id).fadeOut(300, function() { $(this).remove(); }); return true; } return false; } const total = document.querySelectorAll('#threads .threadtitle').length; $(".threads_list_fxp").after( $("<div>", { id: "forumStatsContainer" }).append( $("<div>", { id: "forumStats" }).append( $("<i>").text(`נתונים סטטיסטיים של ${total} אשכולות:`) ) ) ); //PUBLISHERS var publishers = []; //array of all posters that posted in the forum $("#threads .threadinfo .username").each(function() { publishers.push($(this).text()); }); var publishersDict = getDupeSortedDictionary(publishers); console.log(publishers, publishersDict); line = $("<div>"); if (publishersDict.length > 1 && publishersDict[0].count > 1) { line.append($("<span>").text("המפרסם הדומיננטי ביותר הוא ")); //add names until the count is not the largest for (var i = 0; i < publishersDict.length && (publishersDict[i].count === publishersDict[0].count); i++) { if (i > 0) line.append($("<span>").text(" או ")); line.append($("<b>").text(publishersDict[i].value)); } line.append($("<span>").text(" עם " + publishersDict[0].count + " אשכולות.")); } else { line.append($("<span>").text("אין מפרסם דומיננטי במיוחד.")); } $("#forumStats").append(line); //COMMENTORS var commentors = []; //array of all commentors that last posted in threads $("#threads .threadlastpost .username").each(function() { commentors.push($(this).text()); }); var commentorsDict = getDupeSortedDictionary(commentors); line = $("<div>"); if (commentorsDict.length > 1 && commentorsDict[0].count > 1) { line.append($("<span>").text("המגיב האחרון הדומיננטי ביותר הוא ")); for (var i = 0; i < commentorsDict.length && (commentorsDict[i].count === commentorsDict[0].count); i++) { if (i > 0) line.append($("<span>").text(" או ")); line.append($("<b>").text(commentorsDict[i].value)); } line.append($("<span>").text(" עם " + commentorsDict[0].count + " תגובות אחרונות.")); } else { line.append($("<span>").text("אין מגיב אחרון דומיננטי במיוחד.")); } $("#forumStats").append(line); //WORDS var words = []; //array of all words in titles $("#threads .title").each(function() { var titleWords = $(this).text().match(/([^\s.,\/#?!$%\^&\*+;:{}|=\-_`~()]+)/g); //get words in title if (titleWords !== null) { titleWords.forEach(function(word) { if (word.length > 1) //push words to the array of all the words words.push(word); }); } }); var wordsDict = getDupeSortedDictionary(words); var line = $("<div>"); if (wordsDict.length > 1 && wordsDict[0].count > 1) { line.append($("<span>").text("המילה הנפוצה ביותר בכותרות היא ")); for (var i = 0; i < wordsDict.length && (wordsDict[i].count === wordsDict[0].count); i++) { if (i > 0) line.append($("<span>").text(" או ")); line.append($("<b>").text(wordsDict[i].value)); } line.append($("<span>").text(" עם " + wordsDict[0].count + " אזכורים.")); } else { line.append($("<span>").text("אין מילה נפוצה במיוחד בכותרות.")); } $("#forumStats").append(line); //PREFIXES var prefixes = []; //array of all prefixes of threads $("#threads .prefix").each(function() { var prefix = $(this).text().trim(); prefix = prefix.replace("|", ""); //remove | prefix = prefix.replace("סקר: ", "").trim(); //remove poll prefix prefixes.push(prefix); }); var prefixesDict = getDupeSortedDictionary(prefixes); line = $("<div>"); if (prefixesDict.length > 1 && prefixesDict[0].count > 1) { line.append($("<span>").text("התיוג הנפוץ ביותר הוא ")); for (var i = 0; i < prefixesDict.length && (prefixesDict[i].count === prefixesDict[0].count); i++) { if (i > 0) line.append($("<span>").text(" או ")); line.append($("<b>").text(prefixesDict[i].value)); } line.append($("<span>").text(" שנמצא ב-" + prefixesDict[0].count + " אשכולות.")); } else { line.append($("<span>").text("אין תיוג נפוץ במיוחד.")); } $("#forumStats").append(line); //VIEW COMMENT RATIO var commentsCount = 0; var viewsCount = 0; var cc, vc; $("#threads .threadstats").each(function() { cc = parseInt($(this).find("li:eq(0)").text().replace(",", "").replace(/^\D+/g, "")); vc = parseInt($(this).find("li:eq(1)").text().replace(",", "").replace(/^\D+/g, "")); if (!isNaN(cc)) commentsCount += cc; if (!isNaN(vc)) viewsCount += vc; }); var viewsCommentsRatio = Math.round(viewsCount / commentsCount); if (viewsCommentsRatio < 1) viewsCommentsRatio = 1; //make sure that it's not rounded to 0 if (isNaN(viewsCommentsRatio)) viewsCommentsRatio = "∞"; line = $("<div>"); line.append($("<span>").text("יחס הצפיות לתגובה הוא תגובה כל ")); line.append($("<b>").text(viewsCommentsRatio + " צפיות")); line.append($("<span>").text(".")); $("#forumStats").append(line); //shorten the words dictionary var shortWordsDict = []; for (var i = 0; i < wordsDict.length && wordsDict[i].count > 1; i++) { shortWordsDict.push(wordsDict[i]); } wordsDict = shortWordsDict; //button for detailed statistics $("#forumStats").append( $("<div>", { class: "smallPlusButton", id: "detailedStatsBtn" }).text("+").click(function() { var pContent = $("<div>"); pContent.append($("<div>").text("להלן פירוט הסטטיסטיקות לפורום זה:")); var flexTableContainer = $("<div>", { style: "display: flex; flex-wrap: wrap;" }); //add table skeleton flexTableContainer.append($("<table>", { class: "statTable", id: "publishersStatTable" }).append( $("<tr>").append( $("<th>").text("מפרסם") ).append( $("<th>").text("אשכולות") ))); flexTableContainer.append($("<table>", { class: "statTable", id: "commentorsStatTable" }).append( $("<tr>").append( $("<th>").text("מגיב") ).append( $("<th>").text("תגובות אחרונות") ))); flexTableContainer.append($("<table>", { class: "statTable", id: "wordsStatTable" }).append( $("<tr>").append( $("<th>").text("מילה") ).append( $("<th>").text("אזכורים") ))); flexTableContainer.append($("<table>", { class: "statTable", id: "prefixesStatTable" }).append( $("<tr>").append( $("<th>").text("תיוג") ).append( $("<th>").text("אשכולות") ))); //add table content for (var i = 0; i < publishersDict.length; i++) { flexTableContainer.find("#publishersStatTable").append( $("<tr>").append( $("<td>").text(publishersDict[i].value) ).append( $("<td>").text(publishersDict[i].count) ) ); } for (var i = 0; i < commentorsDict.length; i++) { flexTableContainer.find("#commentorsStatTable").append( $("<tr>").append( $("<td>").text(commentorsDict[i].value) ).append( $("<td>").text(commentorsDict[i].count) ) ); } for (var i = 0; i < wordsDict.length; i++) { flexTableContainer.find("#wordsStatTable").append( $("<tr>").append( $("<td>").text(wordsDict[i].value) ).append( $("<td>").text(wordsDict[i].count) ) ); } for (var i = 0; i < prefixesDict.length; i++) { flexTableContainer.find("#prefixesStatTable").append( $("<tr>").append( $("<td>").text(prefixesDict[i].value) ).append( $("<td>").text(prefixesDict[i].count) ) ); } pContent.append(flexTableContainer); pContent.append( $("<div>", { class: "closeBtn" }).text("סגור").click(function() { removePopupWindow("detailedStats"); }) ); openPopupWindow("detailedStats", "https://raw.githubusercontent.com/SilverTuxedo/FxPlusplus/refs/heads/master/chrome/images/graph.svg", "סטטיסטיקות מפורטות לפורום " + document.querySelector("[property=\"og:title\"]").content.replace("קהילת", "").trim(), pContent); })); return () => document.querySelectorAll("#forumStatsContainer, #popupBox").forEach(e => e.remove()) }) /* onMatchReady("*", "nightMode", function(hideBigImages, hideGames) { let styleElement; function toggleDarkMode(isEnabled) { const newValue = isEnabled ? "1" : "0"; const date = new Date(); date.setTime(new Date().getTime() + 172800000); document.cookie = `bb_darkmode=${newValue}; expires=${date.toUTCString()}` } function timeInMinutes(timeString) { if (!timeString) return 0; const [hours, minutes] = timeString.split(':').map(Number); return hours * 60 + minutes; } function isNightModeEnabled() { const cookies = document.cookie.split(';'); return cookies.some(cookie => cookie.trim().startsWith('bb_darkmode=1')); } const now = new Date(); const minutesCurrent = now.getHours() * 60 + now.getMinutes(); let rangeActive = false; const minutesStart = timeInMinutes('17:00'); //settings.autoNightmode.start const minutesEnd = timeInMinutes('23:50'); //TODO ADD setTimeout rangeActive = minutesEnd < minutesStart ? (minutesStart <= minutesCurrent || minutesCurrent < minutesEnd) : (minutesCurrent >= minutesStart && minutesCurrent < minutesEnd); if (!isNightModeEnabled() && !rangeActive) { toggleDarkMode(false); } else if (rangeActive) { toggleDarkMode(true); } return () => {}; }) // const nightModeEnabled = localStorage.getItem("nightmodeEnabled") === "true"; // const temp = nightModeEnabled && settings.customBg.night.length > 0 ? // name: 'הפעל את מצב הלילה אוטומטית משעה <input type="time" id="nightStartTime" value="17:05" /> עד שעה <input type="time" id="nightEndTime" value="23:30" />', // default: { // active: false, // start: "17:05", // end: "23:30" // } */