ميدياويكي:Gadget-Numeral converter.js
ملاحظة: بعد الحفظ، قد يلزمك إفراغ الكاش لرؤية التغييرات.
/**
* Numeral converter
* forked from [[mw:MediaWiki:Gadget-Numerakri.js]]
* maintainer حبيشان
*/
mw.loader.using(['mediawiki.cookie', 'mediawiki.util', 'mediawiki.user']).then(function () {
'use strict';
const settingkey = 'gadget-Numeral_converter',
skipclass = 'mwgadget-numconv-skip',
msgs = {
'option-1': {
ar: 'تلقائي'
},
'option-2': {
ar: '۱۲۳'
},
'option-3': {
ar: '123'
},
'label-text': {
ar: 'الأرقام: '
},
'label-tooltip': {
ar: '١٢٣<->123'
}
},
maps = {
'2': ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩', '٪'],
'3': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '%']
},
rejectedTags = ['input', 'textarea', 'style', 'script', 'pre'];
var currentType = '1',
otherType,
matchers = {},
walker,
styleTag;
function isValidType(type) {
return Number(type)>0 && Number(type)<4;
}
/** @return {Object.<RegExp>} */
function getMatchers(targetType) {
var rChars;
if (!matchers[targetType]) {
rChars = { 0: [], 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [] };
$.each(maps, function (type, map) {
if (type !== targetType) {
for (var i = 0; i <= 10; i++) {
rChars[i].push(map[i]);
}
}
});
rChars = $.map(rChars, function (chars) {
return new RegExp('(' + $.map(chars, mw.util.escapeRegExp).join('|') + ')', 'g');
});
matchers[targetType] = rChars;
}
return matchers[targetType];
}
function msg(key) {
return msgs[key][mw.config.get('wgUserLanguage')] || msgs[key].en;
}
/**
* @param {HTMLElement|TextNode} node
* @return {number} NodeFilter.FILTER_* constant
*/
function filterNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return NodeFilter.FILTER_ACCEPT;
}
var n = node.nodeName && node.nodeName.toLowerCase();
if ( rejectedTags.indexOf(n) > -1 ||
// node.hasAttribute('contenteditable') ||
$(node).hasClass(skipclass)
) {
// Skip this element and skip its children
return NodeFilter.FILTER_REJECT;
}
// Skip this element, but check its children
return NodeFilter.FILTER_SKIP;
}
/**
* @param {TextNode} node
*/
function handleTextNode(node) {
var original = node.nodeValue,
changed = original,
// matchers = getMatchers(currentType),
i = 0;
for (; i <= 10; i++) {
changed = changed.replaceAll(maps[otherType][i], maps[currentType][i]);
}
if (original !== changed) {
node.nodeValue = changed;
}
}
// https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw-method-requestIdleCallback
function idleWalker(deadline) {
var el;
if (!walker) {
return;
}
while (deadline.timeRemaining() > 0) {
el = walker.nextNode();
if (!el) {
// Reached the end
walker = null;
return;
}
handleTextNode(el);
}
// The user may interact with the page. We pause so the browser can process
// interaction. The text handler will continue after that.
if (walker) {
mw.requestIdleCallback(idleWalker);
}
}
/**
* Save a browser cookie for 30 days, or remove it.
* @param {string|null} value
*/
function saveType(value) {
mw.requestIdleCallback(function () {
if (mw.user.isAnon()) {
mw.cookie.set(settingkey, value, { expires: 30 * 86400 , path: '/' });
} else {
new mw.Api().saveOption(settingkey, value);
mw.user.options.set(settingkey, value);
}
mw.storage.session.set(settingkey, value);
});
}
/**
* @return {string}
*/
function getStoredType() {
var value = mw.user.isAnon() ? mw.cookie.get(settingkey, '1') : mw.user.options.get(settingkey) || '1';
var svalue = mw.storage.session.get(settingkey);
if (svalue && svalue !== value) {
value = svalue;
saveType(value);
} else if (value !== null && !isValidType(value)) {
// Remove bad cookie
saveType('1');
value = '1';
}
return value || '1';
}
function startPageConversion() {
if (styleTag) {
// Undo style for a previously selected type
$(styleTag).remove();
styleTag = null;
}
if (currentType === '1') {
// Don't change the page
return;
}
otherType = (currentType == '3')? '2': '3';
switch (currentType) {
case '2':
$('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'arabic-indic');
break;
case '3':
$('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'decimal');
break;
}
// If a walker is already active, replace it.
// If no walker is active yet, start it.
if (!walker) {
mw.requestIdleCallback(idleWalker);
}
walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, filterNode, false);
}
/** @return {HTMLElement} */
function createSelector() {
var $select = $('<select>').addClass(skipclass).append(
$('<option>').val('1').text(msg('option-1'))
);
Object.keys(maps).forEach(function (type) {
$select.append($('<option>').val(type).text(msg('option-' + type)));
});
$select.val(currentType);
$select.on('change', function () {
currentType = this.value;
startPageConversion();
saveType(currentType);
});
return $select[0];
}
function init() {
var potlet;
// Decide selected type
currentType = getStoredType();
startPageConversion();
potlet = mw.util.addPortletLink(
mw.user.isAnon() ? 'p-user-menu-anon-editor' : 'p-personal',
'#',
msg('label-text'),
'pt-numconvert',
msg('label-tooltip'),
null,
mw.user.isAnon() ?
'#pt-createaccount' :
mw.config.get('skin') === 'vector-2022' ?
'#pt-preferences' :
'#pt-userpage'
);
if (potlet) {
$(potlet).html(msg('label-text'))
potlet.appendChild(createSelector());
}
}
$(function () {
mw.requestIdleCallback(init);
});
});