مدیاویکی:Common.js: تفاوت میان نسخهها
از ویکییاد
بدون خلاصۀ ویرایش |
بدون خلاصۀ ویرایش |
||
| (۱۰ نسخهٔ میانیِ ایجادشده توسط همین کاربر نشان داده نشد) | |||
| خط ۱: | خط ۱: | ||
/** | /** | ||
* Gallery to background-cover: | * 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 () { | (function () { | ||
'use strict'; | |||
function processGalleries() { | function processGalleries() { | ||
document.querySelectorAll('li.gallerybox').forEach(function (box) { | document.querySelectorAll('li.gallerybox').forEach(function (box) { | ||
// | // Check if this gallerybox is inside a .javidnam container | ||
const | const container = box.closest('.javidnam'); | ||
if (!container) { | |||
if (img | 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 | // 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); | const observer = new MutationObserver(processGalleries); | ||
observer.observe(document.body, { childList: true, subtree: true }); | 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, 1500); | ||
setTimeout(processGalleries, | 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); | |||
})(); | })(); | ||
نسخهٔ کنونی تا ۱ مارس ۲۰۲۶، ساعت ۱۷:۳۳
/**
* 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);
})();
