Forum.hr Mobile Friendly

Makes forum.hr easier to read on mobile

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Forum.hr Mobile Friendly
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Makes forum.hr easier to read on mobile
// @author       Riche
// @match        https://www.forum.hr/*
// @match        https://forum.hr/*
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==


(function() {
    'use strict';

    console.log('[Forum.hr Mobile] v6.1 starting...');

    // === 1. VIEWPORT ===
    if (!document.querySelector('meta[name="viewport"]')) {
        const meta = document.createElement('meta');
        meta.name = 'viewport';
        meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=5.0';
        (document.head || document.documentElement).appendChild(meta);
    }

    // === 2. BASE STYLES ===
    GM_addStyle(`
        html, body {
            margin: 0 !important;
            padding: 0 !important;
            min-width: 0 !important;
            overflow-x: hidden !important;
        }
        body {
            width: 100% !important;
            max-width: 100vw !important;
        }
        /* Constrain large media, but NEVER scale up small icons/smileys/buttons */
        iframe, video, embed, object {
            max-width: 100% !important;
            height: auto !important;
        }
        img:not([src*="buttons/"]):not([src*="icon_"]):not([src*="smilies/"]):not(.inlineimg):not([alt*="Edit"]):not([alt*="Reply"]):not([alt*="Multi"]):not([alt*="Thanks"]):not([alt*="Warn"]) {
            max-width: 100% !important;
            height: auto !important;
        }
        *, *::before, *::after {
            box-sizing: border-box !important;
        }
        * {
            white-space: normal !important;
            overflow-wrap: break-word !important;
            word-wrap: break-word !important;
            word-break: break-word !important;
        }
        pre, code, .code, .phpcode, .htmlcode {
            white-space: pre-wrap !important;
            word-break: break-all !important;
        }
        td.sidebar_column, td.sidebar_column_spacer, .sidebar_column {
            display: none !important;
            width: 0 !important;
            padding: 0 !important;
            margin: 0 !important;
        }
        /* Constrain ALL direct children of body */
        body > div, body > table, body > form {
            max-width: 100vw !important;
            width: 100% !important;
        }
        .page {
            width: 100% !important;
            max-width: 100vw !important;
            min-width: 0 !important;
            padding: 0 !important;
            margin: 0 !important;
            overflow: hidden !important;
        }
        .page > div {
            padding-left: 4px !important;
            padding-right: 4px !important;
            max-width: 100% !important;
        }
        #posts, #__xclaimwords_wrapper {
            width: 100% !important;
            max-width: 100vw !important;
            overflow: hidden !important;
        }
        /* CRITICAL: constrain xclaimwords and any wide widgets inside posts */
        #__xclaimwords_wrapper,
        #__xclaimwords_wrapper > div,
        #__xclaimwords_wrapper iframe,
        #__xclaimwords_wrapper img {
            max-width: 100% !important;
            width: 100% !important;
            overflow: hidden !important;
        }
        table {
            max-width: 100% !important;
        }
        /* Aggressive ad/iframe constraining */
        [id^="div-gpt-ad-"], #header_banner, [id^="google_ads_iframe"] {
            max-width: 100% !important;
            width: 100% !important;
            overflow: hidden !important;
        }
        [id^="google_ads_iframe"] iframe, [id^="google_ads_iframe"] div {
            max-width: 100% !important;
            width: 100% !important;
        }
        td.alt1 div[style*="margin:5px"], td.alt1 div[style*="margin: 5px"] {
            margin: 4px !important;
        }
        td.alt1 blockquote, td.alt1 .quote {
            margin: 4px !important;
            padding: 4px !important;
        }
        @media screen and (max-width: 768px) {
            /* Post tables - use table-layout fixed instead of flexbox */
            table[id^="post"] {
                table-layout: fixed !important;
                width: 100% !important;
                max-width: 100% !important;
            }
            table[id^="post"] > tbody > tr {
                width: 100% !important;
            }
            /* User column */
            table[id^="post"] td:first-child {
                width: 110px !important;
                min-width: 110px !important;
                max-width: 110px !important;
                padding: 4px !important;
                overflow: hidden !important;
            }
            /* Post content column */
            table[id^="post"] td:last-child {
                width: auto !important;
                min-width: 0 !important;
                padding: 4px !important;
                overflow: hidden !important;
            }
            /* Constrain nested media */
            table[id^="post"] td:last-child iframe,
            table[id^="post"] td:last-child video,
            table[id^="post"] td:last-child embed,
            table[id^="post"] td:last-child div {
                max-width: 100% !important;
            }
            /* User column */
            table[id^="post"] td.alt2 {
                font-size: 14px !important;
            }
            table[id^="post"] td.alt2 img {
                max-width: 100px !important;
                max-height: 100px !important;
            }
            /* Post content - MUCH larger font (compensates for viewport scale) */
            #posts table[id^="post"] td.alt1 {
                font-size: 26px !important;
                line-height: 1.5 !important;
                word-wrap: break-word !important;
                overflow-wrap: break-word !important;
            }
            /* Quotes and nested tables - keep as tables, just make wide */
            #posts table[id^="post"] td.alt1 table {
                width: 100% !important;
                max-width: 100% !important;
            }
            #posts table[id^="post"] td.alt1 table td {
                font-size: 26px !important;
                line-height: 1.5 !important;
                word-break: normal !important;
                overflow-wrap: normal !important;
            }
            /* Page nav tables - larger tappable font */
            .pagenav table {
                width: 100% !important;
                max-width: 100% !important;
            }
            .pagenav table tr {
                display: flex !important;
                flex-wrap: wrap !important;
                justify-content: center !important;
            }
            .pagenav table td {
                display: block !important;
                padding: 6px 10px !important;
                width: auto !important;
            }
            .pagenav .smallfont, .pagenav a.smallfont, .pagenav td.vbmenu_control {
                font-size: 22px !important;
            }
        }
    `);

    // === 3. MOBILE FIXES ===
    function applyFixes() {
        const vw = window.innerWidth;
        if (vw > 768) return;

        // Strip width attributes
        document.querySelectorAll('[width]').forEach(el => {
            if (!el.hasAttribute('data-fhm-width-removed')) {
                el.removeAttribute('width');
                el.setAttribute('data-fhm-width-removed', '1');
            }
        });
        document.querySelectorAll('[cellpadding]').forEach(el => {
            if (!el.hasAttribute('data-fhm-padding-removed')) {
                el.setAttribute('cellpadding', '0');
                el.setAttribute('data-fhm-padding-removed', '1');
            }
        });
        document.querySelectorAll('[cellspacing]').forEach(el => {
            if (!el.hasAttribute('data-fhm-spacing-removed')) {
                el.setAttribute('cellspacing', '0');
                el.setAttribute('data-fhm-spacing-removed', '1');
            }
        });
        document.querySelectorAll('[style*="min-width"]').forEach(el => {
            el.style.minWidth = '0';
        });
        document.querySelectorAll('[nowrap]').forEach(el => {
            el.removeAttribute('nowrap');
        });

        // Page container - strip inline styles and force fit
        document.querySelectorAll('.page').forEach(el => {
            el.removeAttribute('style'); // strip vBulletin inline width
            el.style.setProperty('width', '100%', 'important');
            el.style.setProperty('max-width', '100vw', 'important');
            el.style.setProperty('min-width', '0', 'important');
            el.style.setProperty('padding', '0', 'important');
            el.style.setProperty('margin', '0', 'important');
            el.style.setProperty('overflow', 'hidden', 'important');
        });
        // Constrain body wrapper divs
        document.querySelectorAll('body > div').forEach(el => {
            el.removeAttribute('style');
            el.style.setProperty('max-width', '100vw', 'important');
            el.style.setProperty('width', '100%', 'important');
            el.style.setProperty('overflow', 'hidden', 'important');
        });
        document.querySelectorAll('.page > div').forEach(el => {
            el.style.paddingLeft = '4px';
            el.style.paddingRight = '4px';
            el.style.maxWidth = '100%';
        });

        // Posts container + xclaimwords
        document.querySelectorAll('#posts, #__xclaimwords_wrapper').forEach(el => {
            el.style.width = '100%';
            el.style.maxWidth = '100vw';
            el.style.overflow = 'hidden';
        });
        // Force xclaimwords children to fit
        document.querySelectorAll('#__xclaimwords_wrapper *').forEach(el => {
            el.style.maxWidth = '100%';
        });

        // Header table
        document.querySelectorAll('body > table').forEach(table => {
            table.style.width = '100%';
            table.style.maxWidth = '100vw';
            table.style.tableLayout = 'fixed';
            table.querySelectorAll('td').forEach(td => {
                td.style.maxWidth = '50%';
                td.style.overflow = 'hidden';
            });
        });

        // Ad banners - VERY aggressive
        document.querySelectorAll('[id^="div-gpt-ad-"], #header_banner, [id^="google_ads_iframe"]').forEach(el => {
            el.style.maxWidth = '100%';
            el.style.width = '100%';
            el.style.overflow = 'hidden';
            el.querySelectorAll('iframe, div').forEach(child => {
                child.style.maxWidth = '100%';
                child.style.width = '100%';
            });
        });
        // Also constrain all iframes globally
        document.querySelectorAll('iframe').forEach(iframe => {
            iframe.style.maxWidth = '100%';
            iframe.style.width = '100%';
        });

        // Fix ALL images in posts aggressively
        document.querySelectorAll('table[id^="post"] img, .inlineimg, img[src*="buttons/"], img[src*="smilies/"]').forEach(img => {
            const src = (img.src || '').toLowerCase();
            const alt = (img.alt || '').toLowerCase();
            const isQuoteBtn = src.includes('quote.gif');
            const isSmallIcon = !isQuoteBtn && (src.includes('buttons/') || src.includes('icon_') || src.includes('smilies/') ||
                alt.includes('quote') || alt.includes('edit') || alt.includes('reply') ||
                alt.includes('multi') || alt.includes('thanks') || alt.includes('warn') ||
                img.classList.contains('inlineimg'));

            if (isQuoteBtn) {
                img.removeAttribute('width');
                img.removeAttribute('height');
                img.style.setProperty('max-width', '60px', 'important');
                img.style.setProperty('width', 'auto', 'important');
                img.style.setProperty('height', 'auto', 'important');
            } else if (isSmallIcon) {
                // Small icons: force tiny size with !important
                img.removeAttribute('width');
                img.removeAttribute('height');
                img.style.setProperty('max-width', '24px', 'important');
                img.style.setProperty('width', 'auto', 'important');
                img.style.setProperty('height', 'auto', 'important');
            }
        });

        // Fix post font sizes via JS
        document.querySelectorAll('table[id^="post"] td.alt1').forEach(td => {
            td.style.setProperty('font-size', '26px', 'important');
            td.style.setProperty('line-height', '1.5', 'important');
        });
        document.querySelectorAll('table[id^="post"] td.alt2').forEach(td => {
            td.style.setProperty('font-size', '14px', 'important');
        });

        // Fix quotes - keep as tables but ensure full width and font size
        document.querySelectorAll('table[id^="post"] td.alt1 table').forEach(innerTable => {
            innerTable.style.setProperty('width', '100%', 'important');
            innerTable.style.setProperty('max-width', '100%', 'important');
            innerTable.querySelectorAll('td').forEach(td => {
                td.style.setProperty('font-size', '26px', 'important');
                td.style.setProperty('line-height', '1.5', 'important');
                td.style.setProperty('word-break', 'normal', 'important');
                td.style.setProperty('overflow-wrap', 'normal', 'important');
            });
        });

        // Toolbar tables
        document.querySelectorAll('table.tborder').forEach(table => {
            const hasThreadTools = table.querySelector('#threadtools, #threadsearch, #displaymodes');
            if (!hasThreadTools) return;
            table.style.width = '100%';
            table.style.maxWidth = '100%';
            const row = table.querySelector('tr');
            if (row) {
                row.style.display = 'flex';
                row.style.flexWrap = 'wrap';
                row.querySelectorAll('td').forEach(td => {
                    td.style.display = 'block';
                    td.style.padding = '4px 8px';
                    td.style.width = 'auto';
                });
            }
        });

        // Forum listings
        document.querySelectorAll('table.tborder').forEach(table => {
            if (!table.querySelector('thead .column_moderator')) return;
            table.style.tableLayout = 'fixed';
            table.style.width = '100%';
            table.style.maxWidth = '100%';
            const headerRow = table.querySelector('thead tr');
            if (headerRow) headerRow.style.display = 'none';
            table.querySelectorAll('tbody > tr[align="center"]').forEach(row => {
                const titleCell = row.querySelector('td.field_title');
                if (!titleCell) return;
                row.style.borderBottom = '1px solid #555';
                row.querySelectorAll('td.field_spacer, td.field_threads, td.field_posts, td.field_moderator').forEach(el => {
                    el.style.display = 'none';
                });
                const lastPost = row.querySelector('td.field_last_post');
                if (titleCell) {
                    titleCell.style.display = 'table-cell';
                    titleCell.style.width = '55%';
                    titleCell.style.minWidth = '0';
                    titleCell.style.maxWidth = '55%';
                    titleCell.style.padding = '6px 4px';
                    titleCell.style.verticalAlign = 'top';
                    titleCell.style.overflow = 'hidden';
                }
                if (lastPost) {
                    lastPost.style.display = 'table-cell';
                    lastPost.style.width = '45%';
                    lastPost.style.minWidth = '0';
                    lastPost.style.maxWidth = '45%';
                    lastPost.style.padding = '6px 4px';
                    lastPost.style.verticalAlign = 'top';
                    lastPost.style.fontSize = '11px';
                    lastPost.style.overflow = 'hidden';
                }
            });
        });

        // Thread listings
        document.querySelectorAll('table#threadslist').forEach(table => {
            if (table.hasAttribute('data-fhm-processed')) return;
            table.setAttribute('data-fhm-processed', '1');
            console.log('[Forum.hr Mobile] Processing thread list');
            table.style.display = 'block';
            table.style.width = '100%';
            table.style.maxWidth = '100%';
            table.querySelectorAll('tr').forEach(row => {
                if (row.querySelector('.thead')) {
                    row.style.display = 'none';
                    return;
                }
                const titleCell = row.querySelector('td.field_title');
                if (!titleCell) return;
                const lastPost = row.querySelector('td.field_last_post');
                row.style.display = 'block';
                row.style.width = '100%';
                row.style.borderBottom = '1px solid #555';
                row.style.padding = '6px 4px';
                row.querySelectorAll('td').forEach(td => {
                    td.style.display = 'none';
                });
                if (titleCell) {
                    titleCell.style.display = 'block';
                    titleCell.style.width = '100%';
                    titleCell.style.padding = '2px 0';
                    const multipage = titleCell.querySelector('span.smallfont');
                    if (multipage) {
                        multipage.style.display = 'block';
                        multipage.style.fontSize = '10px';
                    }
                }
                if (lastPost) {
                    lastPost.style.display = 'block';
                    lastPost.style.width = '100%';
                    lastPost.style.padding = '2px 0';
                    lastPost.style.fontSize = '11px';
                    lastPost.style.color = '#888';
                }
            });
        });

        // Page nav - larger font for tappability
        document.querySelectorAll('.pagenav .smallfont, .pagenav a.smallfont').forEach(el => {
            el.style.setProperty('font-size', '22px', 'important');
        });

        // Nav buttons
        document.querySelectorAll('table.tborder').forEach(table => {
            const navRow = table.querySelector('tr[align="center"]');
            if (navRow && navRow.querySelector('.vbmenu_control')) {
                navRow.style.display = 'flex';
                navRow.style.flexWrap = 'wrap';
                navRow.style.justifyContent = 'center';
                navRow.querySelectorAll('td').forEach(td => {
                    td.style.display = 'block';
                    td.style.padding = '4px 8px';
                });
            }
        });

        // Whats going on
        const wgo = document.getElementById('whats_going_on');
        if (wgo) {
            wgo.style.display = 'block';
            wgo.style.width = '100%';
            wgo.style.maxWidth = '100%';
        }

        // NUCLEAR: use viewport meta to scale entire page
        if (vw <= 768 && !window.__fhm_scaled) {
            const page = document.querySelector('.page');
            if (page) {
                const pageW = page.scrollWidth;
                if (pageW > vw) {
                    const scale = (vw - 4) / pageW;
                    const meta = document.querySelector('meta[name="viewport"]');
                    if (meta) {
                        meta.content = 'width=' + pageW + ', initial-scale=' + scale.toFixed(4) + ', maximum-scale=5.0';
                        console.log('[Forum.hr Mobile] VIEWPORT: width=' + pageW + ' scale=' + scale.toFixed(4));
                        window.__fhm_scaled = true;
                    }
                }
            }
        }
    }

    // === 4. RUN ===
    function init() {
        applyFixes();
        fixThreadLinks();
        console.log('[Forum.hr Mobile] Initialized');
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    window.addEventListener('load', function() { applyFixes(); fixThreadLinks(); });

    let resizeTimer;
    window.addEventListener('resize', function() {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(applyFixes, 300);
    });

    let checkCount = 0;
    const interval = setInterval(function() {
        applyFixes();
        fixThreadLinks();
        if (++checkCount > 20) clearInterval(interval);
    }, 500);

    // === 5. THREAD LINKS: goto=newpost ===
    function fixThreadLinks() {
        document.querySelectorAll('a[href*="showthread.php?t="]').forEach(link => {
            const href = link.getAttribute('href') || '';
            // Only fix links that don't already have goto=newpost
            if (href.includes('goto=newpost')) return;
            // Only fix links that have ?t= (thread ID links)
            const match = href.match(/showthread\.php\?(\d+)?t=(\d+)/);
            if (!match) return;
            const threadId = match[2];
            const newHref = 'showthread.php?goto=newpost&t=' + threadId;
            link.setAttribute('href', newHref);
        });
        // Remove "go to first new post" icon since thread title now links there
        document.querySelectorAll('a[id^="thread_gotonew_"]').forEach(el => el.remove());
    }

    // Aggressive MutationObserver: re-fix images whenever anything changes
    const observer = new MutationObserver(function(mutations) {
        let shouldFix = false;
        mutations.forEach(function(mutation) {
            if (mutation.type === 'attributes') {
                const target = mutation.target;
                if (target.tagName === 'IMG') {
                    const src = (target.src || '').toLowerCase();
                    const isQuoteBtn = src.includes('quote.gif');
                    if (src.includes('buttons/') || src.includes('smilies/') || target.classList.contains('inlineimg')) {
                        // Force fix this specific image immediately
                        target.removeAttribute('width');
                        target.removeAttribute('height');
                        if (isQuoteBtn) {
                            target.style.setProperty('max-width', '60px', 'important');
                        } else {
                            target.style.setProperty('max-width', '24px', 'important');
                        }
                        target.style.setProperty('width', 'auto', 'important');
                        target.style.setProperty('height', 'auto', 'important');
                    }
                }
            }
            if (mutation.type === 'childList') {
                shouldFix = true;
            }
        });
        if (shouldFix) { applyFixes(); fixThreadLinks(); }
    });

    window.addEventListener('load', function() {
        observer.observe(document.body, {
            attributes: true,
            attributeFilter: ['style', 'width', 'height'],
            childList: true,
            subtree: true
        });
    });

    console.log('[Forum.hr Mobile] v6.1 loaded');
})();