MediaWiki:Gadget-Numerakri.js

/** * Convert Arabic numerals to Devanagari and vice-versa. * * @revision 2.1-2012-12-19 * @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-Numerakri.js * @author Daniel Friesen, 2012 * @author Timo Tijhof, 2012 * @author Siddhartha Ghai, 2012 * @license CC-BY-SA 3.0 * @license MIT */ /*jshint browser:true, boss:true, white:true */ /*globals jQuery */ (function (mw, $) {	"use strict";	// Private cache & utilities	var el, w, num,		/**		 * @var {RegExp} Matcher for characters that need to be mapped.		 */		matchers = {			devanagari: /[0-9]/g,			arabic: /(१|२|३|४|५|६|७|८|९|०)/g		},		msgs = {			'option-default': {				en: 'Default',				hi: 'डिफ़ॉल्ट'			},			'option-arabic': {				en: '123'			},			'option-devanagari': {				en: 'Devanagari',				hi: '१२३'			},			'label-url': {				en: '//www.mediawiki.org/wiki/MediaWiki_talk:Gadget-Numerakri.js',				hi: '//hi.wikipedia.org/wiki/विकिपीडिया:अंक_परिवर्तक'			},			'label-text': {				en: 'Convert numerals',				hi: 'अंक परिवर्तन'			},			'label-tooltip': {				en: 'Convert between Arabic and Devanagari numerals',				hi: 'नागरी और अरबी अंकों में परिवर्तन करें'			}		},		maps = {			devanagari: {				'0': '०',				'1': '१',				'2': '२',				'3': '३',				'4': '४',				'5': '५',				'6': '६',				'7': '७',				'8': '८', '9': '९'			},			arabic: { '०': '0',				'१': '1',				'२': '2',				'३': '3',				'४': '4',				'५': '5',				'६': '6',				'७': '7',				'८': '8',				'९': '9'			}		},		compatCookie = { '-1': 'default', '0' : 'arabic', '1': 'devanagari' },		// 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; }

/**	 * @constructor */	function Numerakri { /**		 * @property {string} One of 'default', 'arabic' or 'devanagari'. * default leaves the page unchanged (default). */		this.type = 'default'; }

Numerakri.prototype = { constructor: Numerakri,

/**		 * Handle matches from the regexp. * @method */		convertMatch: function (match) { return maps[this.type][match]; },

/**		 * @param {HTMLElement|TextNode} el		 */ filterNode: function (el) { var n = el.nodeName && el.nodeName.toLowerCase; if (n === 'input' || n === 'textarea' || $(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) { el.nodeValue = el.nodeValue.replace(matchers[this.type], $.proxy(this.convertMatch, this)); },

isValidType: function (type) { return type === 'default' || (matchers[type] && maps[type]); },

/**		 * @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 30 days $.cookie('mw-numerakri-type', type, { expires: 30, 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 'undefined' means "don't change the page". return; }

switch (this.type) { case 'arabic': $('ol:lang(hi) li, ol.references, li.references').css('list-style-type', 'decimal'); break; case 'devanagari': $('ol:lang(hi) li, ol.references, li.references').css('list-style-type', 'devanagari'); break; }

walkTheDom($.proxy(this.filterNode, this), $.proxy(this.handleTextNode, this)); },

setupInterface: function { var potlet, stored, $menu, $select, num = this;

switch (mw.config.get('skin')) { case 'vector': case 'chick': case 'myskin': case 'simple': case 'monobook': case 'modern': $('#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'				); break; default: // Skin unsupported return; }

$select = $(' ').addClass('mw-numerakri-skip').append(				$(' ').val('default').text(msg('option-default')),				$(' ').val('arabic').text(msg('option-arabic')),				$(' ').val('devanagari').text(msg('option-devanagari'))			);

stored = this.getStoredType; if (stored) { // Set initial value from storage $select.val(stored); this.setType(stored); }

$select.change(function {				num.setType(this.value);			});

$menu = $(' ').addClass('mw-numerakri-menu').append($select);

$(potlet).append($menu); }

};

num = new Numerakri;

mw.loader.using('mediawiki.user', function {		$(document).ready(function  { num.setupInterface; });	});

})(mediaWiki, jQuery);