تضامنًا مع حق الشعب الفلسطيني |
ميدياويكي:Gadget-Numeral converter.js
ملاحظة: بعد الحفظ، قد يلزمك إفراغ الكاش لرؤية التغييرات.
//[[pnb:میڈیا وکی:Gadget-Numeral converter.js]]
(function (mw, $) {
"use strict";
// Private cache & utilities
var el, w, num,
/**
* @var {RegExp} Matcher for characters that can be mapped.
* @example matchers.urdu[0] matches urdu numeral for 0
* can be mapped with e.g. maps.arabic[0].
*/
matchers = {},
msgs = {
'option-default': {
en: 'الأصل'
},
'option-gharb': {
en: '123'
},
'option-sharq': {
en: '۱۲۳'
},
'label-url': {
en: '//www.mediawiki.org/wiki/MediaWiki_talk:Gadget-Numerakri.js'
},
'label-text': {
en: 'شكل الأعداد: '
},
'label-tooltip': {
en: '١٢٣<->123'
}
},
maps = {
// 0 to 9
sharq: [ '٠','١','٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩','٪'],
gharb: [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9','%' ]
},
compatCookie = {
'-1': 'default',
'0' : 'gharb',
'3': 'sharq'
},
// For consistency recreate these objects locally in older browsers so that
// we can use the same constants in fallback code as well.
NodeFilter = window.NodeFilter || {
FILTER_ACCEPT: 1,
FILTER_REJECT: 2,
FILTER_SKIP: 3
},
Node = window.Node || {
TEXT_NODE: 3
};
// Fallback for document.createTreeWalker for older browsers (IE6-8)
function walkTheDomFallback(node, filter, apply) {
var val = filter(node);
switch (val) {
case NodeFilter.FILTER_ACCEPT:
apply(node);
node = node.firstChild;
break;
case NodeFilter.FILTER_REJECT:
node = node.nextSibling;
break;
case NodeFilter.FILTER_SKIP:
node = node.firstChild;
break;
}
while (node) {
walkTheDomFallback(node, apply);
node = node.nextSibling;
}
}
function walkTheDom(filter, apply) {
if (document.createTreeWalker) {
w = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, filter, false);
while (el = w.nextNode()) {
apply(el);
}
} else {
walkTheDomFallback(document.body, filter, apply);
}
}
function msg(key) {
return msgs[key][mw.config.get('wgUserLanguage')] || msgs[key].en;
}
function getMatchers(target) {
var rChars;
if (!matchers[target]) {
rChars = { 0: [], 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [] };
$.each(maps, function (type, map) {
if (type !== target) {
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[target] = rChars;
}
return matchers[target];
}
/**
* @singleton
*/
num = window.Numerakri = {
matchers: matchers,
/**
* @property {string} One of 'default', 'arabic' or 'shahmukhi'.
* default leaves the page unchanged (default).
*/
type: 'default',
/**
* @property {jQuery|null} The HTML interface. May or may not be
* attached to the document yet.
*/
$int: null,
/**
* @param {HTMLElement|TextNode} el
*/
filterNode: function (el) {
var n = el.nodeName && el.nodeName.toLowerCase();
if (n === 'input' || n === 'textarea' || n === 'script' || n === 'style' || $(el).hasClass('mw-numerakri-skip')) {
return NodeFilter.FILTER_REJECT;
}
if (el.nodeType === Node.TEXT_NODE) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
},
/**
* @method
* @param {TextNode} el
*/
handleTextNode: function (el) {
var live = el.nodeValue,
fix = live,
matchers = getMatchers(num.type),
i = 0;
for (; i <= 10; i++) {
fix = fix.replace(matchers[i], maps[num.type][i]);
}
if (live !== fix) {
el.nodeValue = fix;
}
},
isValidType: function (type) {
return type === 'default' || !!maps[type];
},
/**
* Register an additional type.
*
* @example
* num.addType('arabic', { map: [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ] });
* @param {string} type ID
* @param {Object} data Contents:
* - {Object} map
* - {string|Object} msg [optional] Label for this type or translations of labels,
* keyed by language code. Defaults to ucFirst transformation of ID.
*/
addType: function (type, data) {
if (type && data && $.isArray(data.map)) {
// Map
maps[type] = data.map;
// Messages
if (data.msg) {
if ($.isPlainObject(data.msg)) {
if (!data.msg.en) {
data.msg.en = $.ucFirst(type);
}
} else {
data.msg = { en: String(data.msg) };
}
} else {
data.msg = { en: $.ucFirst(type) };
}
msgs['option-' + type] = data.msg;
if (this.$select) {
this.$select.append(
$('<option>').val(type)
.text(msg('option-' + type))
.prop('selected', this.getStoredType() === type)
);
}
return true;
}
return false;
},
/**
* @method
* @param {string} type One of 'arabic' or 'devanagari'.
* @throws Error
*/
setType: function (type) {
if (!this.isValidType(type)) {
mw.log('Unknown Numerakri type: ' + type);
return false;
}
this.type = type;
// Remember for 365 days
$.cookie('mw-numerakri-type', type, { expires: 365, path: '/' });
this.convertPage();
},
/**
* @return {string|undefined}
*/
getStoredType: function () {
// From cookie
var stored = $.cookie('mw-numerakri-type');
// From cookie (old version)
if (!stored) {
stored = compatCookie[$.cookie('numconvert')];
}
return stored;
},
/**
* Do the conversion.
* @method
*/
convertPage: function () {
if (this.type === 'default') {
// Type 'default' means "don't change the page".
return;
}
switch (this.type) {
case 'gharb':
$('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'decimal');
break;
case 'sharq':
$('ol:lang(ar) li, ol.references, li.references').css('list-style-type', 'arabic-indic');
break;
}
walkTheDom(this.filterNode, this.handleTextNode);
},
setupInterface: function () {
var $select, stored;
$select = $('<select>').addClass('mw-numerakri-skip').append(
$('<option>').val('default').text(msg('option-default')),
// $.map returns an array
$.map(maps, function (map, type) {
return $('<option>').val(type).text(msg('option-' + type));
})
);
stored = num.getStoredType();
if (stored) {
// Set initial value from storage
$select.val(stored);
num.setType(stored);
}
$select.change(function () {
num.setType(this.value);
});
if (num.$select) {
num.$select.replaceWith($select);
} else {
num.$select = $select;
}
},
attachInterface: function () {
var potlet, $menu;
if (num.$select === null) {
num.setupInterface();
}
$('#pt-numconvert').remove(); // Just in case
potlet = mw.util.addPortletLink(
'p-personal',
msg('label-url'),
msg('label-text'),
'pt-numconvert',
msg('label-tooltip'),
null,
mw.user.isAnon() ? '#pt-createaccount' : '#pt-userpage'
);
$menu = $('<span>').addClass('mw-numerakri-menu').append(num.$select);
$(potlet).append($menu);
}
};
num.setupInterface();
mw.loader.using('mediawiki.user', function () {
$(document).ready(num.attachInterface);
});
})(mediaWiki, jQuery);