اطلاعیه: از همه ایران دوستان عزیز دعوت می‌کنیم در ایجاد و به‌روزرسانی صفحات جاویدنامان همیاری نمایند. در حال حاضر میتوانید بدون عضویت در ثبت تاریخ کمک نمایید.

مدیاویکی:Common.js: تفاوت میان نسخه‌ها

از ویکی‌یاد
Adminwki (بحث | مشارکت‌ها)
بدون خلاصۀ ویرایش
برچسب: برگردانده‌شده
Adminwki (بحث | مشارکت‌ها)
بدون خلاصۀ ویرایش
 
(۷ نسخهٔ میانیِ ایجادشده توسط همین کاربر نشان داده نشد)
خط ۱: خط ۱:
/**
* Umami Analytics tracking (privacy-focused, self-hosted)
*/
(function() {
    // Create the script element
    var script = document.createElement('script');
   
    // Set attributes exactly as provided by Umami
    script.defer = true;
    script.src = 'https://cloud.umami.is/script.js';
    script.setAttribute('data-website-id', 'f5f75b33-a7ed-4d71-ac5a-7750a48efaa0');
   
    // Append to head (or body – head is preferred for earlier loading)
    document.head.appendChild(script);
})();
/**
/**
  * Gallery to background-cover: set img src as background on .thumb div + hide img
  * Gallery to background-cover: set img src as background on .thumb div + hide img
  * → ONLY on Category: pages (not articles or other namespaces)
  * → ONLY when the gallerybox is inside an element with class "javidnam"
  */
  */
(function () {
(function () {
     'use strict';
     'use strict';
    // Early exit if not on a category page
    if (mw.config.get('wgCanonicalNamespace') !== 'Category') {
        return;
    }


     function processGalleries() {
     function processGalleries() {
         document.querySelectorAll('li.gallerybox').forEach(function (box) {
         document.querySelectorAll('li.gallerybox').forEach(function (box) {
             // Find the .thumb div and the img inside it
             // Check if this gallerybox is inside a .javidnam container
            const container = box.closest('.javidnam');
            if (!container) {
                return; // skip if not inside .javidnam
            }
 
             const thumbDiv = box.querySelector('div.thumb');
             const thumbDiv = box.querySelector('div.thumb');
             const img = thumbDiv ? thumbDiv.querySelector('img.mw-file-element') : null;
             if (!thumbDiv) return;


             if (thumbDiv && img && img.src && !thumbDiv.dataset.backgroundApplied) {
             // Quick skip: if this thumb is a known broken/placeholder structure
                // Apply background to the .thumb div
            if (thumbDiv.querySelector('.mw-broken-media, .mw-file-element:not(img), span[typeof="mw:Error"]')) {
                thumbDiv.style.backgroundImage = 'url(' + img.src + ')';
                 return; // broken file link → leave untouched
                thumbDiv.style.backgroundSize = 'cover';
            }
                 thumbDiv.style.backgroundPosition = 'center center';
                thumbDiv.style.backgroundRepeat = 'no-repeat';


                 // Hide the original <img> tag
            const img = thumbDiv.querySelector('img.mw-file-element');
                 img.style.display = 'none';
            if (!img) return;
 
            const src = img.src && img.src.trim();
            if (!src || src === '' ||
                 src.includes('brokenimage') ||
                src.includes('noimage') ||
                src.includes('Special:Redirect/file/') ||
                 img.alt === '' || img.alt === null) {
                return;
            }


                // Mark as processed (prevents re-processing the same element)
            // Skip tiny/unloaded images (common for broken ones)
                thumbDiv.dataset.backgroundApplied = 'true';
            if (img.naturalWidth <= 4 || img.naturalHeight <= 4 || img.complete === false) {
                return;
            }


                console.log('Applied background to thumb div on category page:', img.src);
            // Already processed?
            if (thumbDiv.dataset.backgroundApplied) {
                return;
             }
             }
            // Apply background
            thumbDiv.style.backgroundImage = 'url(' + src + ')';
            thumbDiv.style.backgroundSize = 'cover';
            thumbDiv.style.backgroundPosition = 'center center';
            thumbDiv.style.backgroundRepeat = 'no-repeat';
            // Hide original img
            img.style.display = 'none';
            // Mark as processed
            thumbDiv.dataset.backgroundApplied = 'true';
         });
         });
     }
     }


     // Run once DOM is ready
     // Run when DOM is ready
     document.addEventListener('DOMContentLoaded', processGalleries);
     function init() {
        processGalleries();
    }
 
    if (document.readyState !== 'loading') {
        init();
    } else {
        document.addEventListener('DOMContentLoaded', init);
    }


     // Watch for dynamic content additions (very useful for DPL, CategoryTree, transclusions, AJAX-loaded galleries, etc.)
     // Mutation observer for dynamic content (DPL, AJAX loads, etc.)
     const observer = new MutationObserver(processGalleries);
     const observer = new MutationObserver(processGalleries);
     observer.observe(document.body, { childList: true, subtree: true });
     observer.observe(document.body, { childList: true, subtree: true });


     // Extra fallback runs (in case observer misses something or images load very late)
     // Extra delayed runs for late-loading thumbs / lazy images
     setTimeout(processGalleries, 1000);
     setTimeout(processGalleries, 600);
     setTimeout(processGalleries, 2500);
     setTimeout(processGalleries, 1500);
     setTimeout(processGalleries, 5000); // one more — harmless and helps on slow connections
     setTimeout(processGalleries, 3500);
})();
})();
// Persian digits → Latin digits converter for CAPTCHA inputs
// Works on edit, login, confirm-edit forms (MathCaptcha, FancyCaptcha, etc.)
// ==UserScript==
// @name        Persian → Latin digits for MediaWiki CAPTCHA
// @namespace    https://github.com/yourname
// @version      0.2
// @description  Converts Persian/Arabic digits to Latin in CAPTCHA fields
// @match        *://*.wikipedia.org/*
// @match        *://*.wiktionary.org/*
// @match        *://*.wikimedia.org/*
// @grant        none
// @run-at      document-start
// ==/UserScript==


(function () {
(function () {
  const map = {0:'۰',1:'۱',2:'۲',3:'۳',4:'۴',5:'۵',6:'۶',7:'۷',8:'۸',9:'۹'};
    'use strict';


  document.querySelectorAll('.mw-parser-output *').forEach(el => {
    const persianToLatin = {
    if (el.children.length === 0 && el.textContent.match(/\d/)) {
        '۰': '0', '۱': '1', '۲': '2', '۳': '3', '۴': '4',
      el.dataset.faText = el.textContent.replace(/\d/g, d => map[d]);
        '۵': '5', '۶': '6', '۷': '7', '۸': '8', '۹': '9',
        '٠': '0', '١': '1', '٢': '2', '٣': '3', '٤': '4',
        '٥': '5', '٦': '6', '٧': '7', '٨': '8', '٩': '9'
    };
 
    function normalizeDigits(str) {
        if (!str) return str;
        return str.replace(/[۰-۹٠-٩]/g, d => persianToLatin[d] || d);
     }
     }
   });
 
    function normalizeInput(input) {
        if (!input || !input.value) return;
 
        const oldValue = input.value;
        const newValue = normalizeDigits(oldValue);
 
        if (newValue !== oldValue) {
            const start = input.selectionStart;
            const end = input.selectionEnd;
 
            input.value = newValue;
 
            // Try to restore cursor position
            input.setSelectionRange(start, end);
 
            // Optional visual feedback
            input.style.setProperty('--border-color-temp', '#4CAF50', 'important');
            input.style.borderColor = 'var(--border-color-temp)';
            setTimeout(() => {
                input.style.borderColor = '';
                input.style.removeProperty('--border-color-temp');
            }, 1300);
        }
    }
 
    function tryAttachToCaptchaFields() {
        const selectors = [
            // OOUI modern confirm-edit / login captcha
            '.mw-confirmEdit-captchaInputWidget .oo-ui-inputWidget-input',
            '.mw-captcha .oo-ui-textInputWidget input',
            // FancyCaptcha / old ones
            '#mw-captcha-text',
            '#wpCaptchaWord',
            '#captchaWord',
            '#captchaInput',
            'input[name="wpCaptchaWord"]',
            'input[name="captchaWord"]',
            'input[name="fancycaptcha"]',
            // Generic fallbacks
            'input[type="text"][name*="captcha" i]',
            'input[type="text"][id*="captcha" i]',
            'input[type="text"].oo-ui-inputWidget-input'
        ];
 
        let attachedCount = 0;
 
        selectors.forEach(sel => {
            document.querySelectorAll(sel).forEach(input => {
                if (input.dataset.persianCaptchaFixed) return;
                input.dataset.persianCaptchaFixed = 'true';
                attachedCount++;
 
                // === Most important: convert BEFORE submit ===
                const form = input.closest('form');
                if (form) {
                    form.addEventListener('submit', () => {
                        normalizeInput(input);
                    }, { capture: true });
                }
 
                // Live conversion
                input.addEventListener('input', () => normalizeInput(input));
                input.addEventListener('change', () => normalizeInput(input));
                input.addEventListener('blur',   () => normalizeInput(input));
            });
        });
 
        // if (attachedCount > 0) {
        //    console.log(`[Persian Captcha Fix] Attached to ${attachedCount} input(s)`);
        // }
    }
 
    // Initial run
    tryAttachToCaptchaFields();
 
    // Watch for dynamically loaded CAPTCHA (AJAX login, edit dialog, etc.)
    const observer = new MutationObserver((mutations) => {
        // Only react when new nodes are added
        if (mutations.some(m => m.addedNodes.length > 0)) {
            tryAttachToCaptchaFields();
        }
    });
 
    observer.observe(document.documentElement || document.body, {
        childList: true,
        subtree: true
    });
 
    // Extra safety: one more run after ~1.5 seconds (in case of very late loading)
    setTimeout(tryAttachToCaptchaFields, 1500);
})();
})();

نسخهٔ کنونی تا ۱ مارس ۲۰۲۶، ساعت ۱۷:۳۳

/**
 * Umami Analytics tracking (privacy-focused, self-hosted)
 */
(function() {
    // Create the script element
    var script = document.createElement('script');
    
    // Set attributes exactly as provided by Umami
    script.defer = true;
    script.src = 'https://cloud.umami.is/script.js';
    script.setAttribute('data-website-id', 'f5f75b33-a7ed-4d71-ac5a-7750a48efaa0');
    
    // Append to head (or body – head is preferred for earlier loading)
    document.head.appendChild(script);
})();

/**
 * Gallery to background-cover: set img src as background on .thumb div + hide img
 * → ONLY when the gallerybox is inside an element with class "javidnam"
 */
(function () {
    'use strict';

    function processGalleries() {
        document.querySelectorAll('li.gallerybox').forEach(function (box) {
            // Check if this gallerybox is inside a .javidnam container
            const container = box.closest('.javidnam');
            if (!container) {
                return; // skip if not inside .javidnam
            }

            const thumbDiv = box.querySelector('div.thumb');
            if (!thumbDiv) return;

            // Quick skip: if this thumb is a known broken/placeholder structure
            if (thumbDiv.querySelector('.mw-broken-media, .mw-file-element:not(img), span[typeof="mw:Error"]')) {
                return; // broken file link → leave untouched
            }

            const img = thumbDiv.querySelector('img.mw-file-element');
            if (!img) return;

            const src = img.src && img.src.trim();
            if (!src || src === '' ||
                src.includes('brokenimage') ||
                src.includes('noimage') ||
                src.includes('Special:Redirect/file/') ||
                img.alt === '' || img.alt === null) {
                return;
            }

            // Skip tiny/unloaded images (common for broken ones)
            if (img.naturalWidth <= 4 || img.naturalHeight <= 4 || img.complete === false) {
                return;
            }

            // Already processed?
            if (thumbDiv.dataset.backgroundApplied) {
                return;
            }

            // Apply background
            thumbDiv.style.backgroundImage = 'url(' + src + ')';
            thumbDiv.style.backgroundSize = 'cover';
            thumbDiv.style.backgroundPosition = 'center center';
            thumbDiv.style.backgroundRepeat = 'no-repeat';

            // Hide original img
            img.style.display = 'none';

            // Mark as processed
            thumbDiv.dataset.backgroundApplied = 'true';
        });
    }

    // Run when DOM is ready
    function init() {
        processGalleries();
    }

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

    // Mutation observer for dynamic content (DPL, AJAX loads, etc.)
    const observer = new MutationObserver(processGalleries);
    observer.observe(document.body, { childList: true, subtree: true });

    // Extra delayed runs for late-loading thumbs / lazy images
    setTimeout(processGalleries, 600);
    setTimeout(processGalleries, 1500);
    setTimeout(processGalleries, 3500);
})();

// Persian digits → Latin digits converter for CAPTCHA inputs
// Works on edit, login, confirm-edit forms (MathCaptcha, FancyCaptcha, etc.)
// ==UserScript==
// @name         Persian → Latin digits for MediaWiki CAPTCHA
// @namespace    https://github.com/yourname
// @version      0.2
// @description  Converts Persian/Arabic digits to Latin in CAPTCHA fields
// @match        *://*.wikipedia.org/*
// @match        *://*.wiktionary.org/*
// @match        *://*.wikimedia.org/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    const persianToLatin = {
        '۰': '0', '۱': '1', '۲': '2', '۳': '3', '۴': '4',
        '۵': '5', '۶': '6', '۷': '7', '۸': '8', '۹': '9',
        '٠': '0', '١': '1', '٢': '2', '٣': '3', '٤': '4',
        '٥': '5', '٦': '6', '٧': '7', '٨': '8', '٩': '9'
    };

    function normalizeDigits(str) {
        if (!str) return str;
        return str.replace(/[۰-۹٠-٩]/g, d => persianToLatin[d] || d);
    }

    function normalizeInput(input) {
        if (!input || !input.value) return;

        const oldValue = input.value;
        const newValue = normalizeDigits(oldValue);

        if (newValue !== oldValue) {
            const start = input.selectionStart;
            const end = input.selectionEnd;

            input.value = newValue;

            // Try to restore cursor position
            input.setSelectionRange(start, end);

            // Optional visual feedback
            input.style.setProperty('--border-color-temp', '#4CAF50', 'important');
            input.style.borderColor = 'var(--border-color-temp)';
            setTimeout(() => {
                input.style.borderColor = '';
                input.style.removeProperty('--border-color-temp');
            }, 1300);
        }
    }

    function tryAttachToCaptchaFields() {
        const selectors = [
            // OOUI modern confirm-edit / login captcha
            '.mw-confirmEdit-captchaInputWidget .oo-ui-inputWidget-input',
            '.mw-captcha .oo-ui-textInputWidget input',
            // FancyCaptcha / old ones
            '#mw-captcha-text',
            '#wpCaptchaWord',
            '#captchaWord',
            '#captchaInput',
            'input[name="wpCaptchaWord"]',
            'input[name="captchaWord"]',
            'input[name="fancycaptcha"]',
            // Generic fallbacks
            'input[type="text"][name*="captcha" i]',
            'input[type="text"][id*="captcha" i]',
            'input[type="text"].oo-ui-inputWidget-input'
        ];

        let attachedCount = 0;

        selectors.forEach(sel => {
            document.querySelectorAll(sel).forEach(input => {
                if (input.dataset.persianCaptchaFixed) return;
                input.dataset.persianCaptchaFixed = 'true';
                attachedCount++;

                // === Most important: convert BEFORE submit ===
                const form = input.closest('form');
                if (form) {
                    form.addEventListener('submit', () => {
                        normalizeInput(input);
                    }, { capture: true });
                }

                // Live conversion
                input.addEventListener('input', () => normalizeInput(input));
                input.addEventListener('change', () => normalizeInput(input));
                input.addEventListener('blur',   () => normalizeInput(input));
            });
        });

        // if (attachedCount > 0) {
        //     console.log(`[Persian Captcha Fix] Attached to ${attachedCount} input(s)`);
        // }
    }

    // Initial run
    tryAttachToCaptchaFields();

    // Watch for dynamically loaded CAPTCHA (AJAX login, edit dialog, etc.)
    const observer = new MutationObserver((mutations) => {
        // Only react when new nodes are added
        if (mutations.some(m => m.addedNodes.length > 0)) {
            tryAttachToCaptchaFields();
        }
    });

    observer.observe(document.documentElement || document.body, {
        childList: true,
        subtree: true
    });

    // Extra safety: one more run after ~1.5 seconds (in case of very late loading)
    setTimeout(tryAttachToCaptchaFields, 1500);
})();