میڈیاویکی:Gadget-Extra-Editbuttons-Functions.js

آزاد دائرۃ المعارف، ویکیپیڈیا سے

تفصیل کے لیے کھولیں کے بٹن پر کلک کریں یاددہانی: محفوظ کرنے کے بعد تازہ ترین تبدیلیوں کو دیکھنے کے لیے آپ کو اپنے براؤزر کا کیش صاف کرنا ہوگا۔

  • فائرفاکس/ سفاری: جب Reload پر کلک کریں تو Shift دبا کر رکھیں، یا Ctrl-F5 یا Ctrl-R دبائیں (Mac پر R- )
  • گوگل کروم: Ctrl-Shift-R دبائیں (Mac پر Shift-R-⌘)
  • انٹرنیٹ ایکسپلورر: جب Refresh پر کلک کریں تو Ctrl یا Ctrl-F5 دبائیں
  • اوپیرا: Tools → Preferences میں جائیں اور کیش صاف کریں

var EE_urChrs = "ءاآأإئؤبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیةيک" + "ًٌٍَُِّْ";
var EE_urNums = "۰۱۲۳۴۵۶۷۸۹";
var EE_arNums = "٠١٢٣٤٥٦٧٨٩";
var EE_enNums = "0123456789";
 
 
/** applyOnSelection
 *
 *  Description: Applies the string functions defined below to the
 *  selected text in the edit box. If no text is selected, applies
 *  the function to the whole contents of edit box.
 *
 */
function applyOnSelection(callback) {
  if (document.getElementById("editform")){
    var txtarea = document.getElementById("wpTextbox1");
  } else if (document.getElementById("wpNewTitleMain")) {
    var txtarea = document.getElementById("wpNewTitleMain");
  } else {
    return;
  }
  var selText;
  if (document.selection && document.selection.createRange) { // IE/Opera
    // get current selection  
    txtarea.focus();
    var range = document.selection.createRange();
    selText = range.text;
    if (selText) {
      range.text = callback.apply(this, [selText]);
      range.select();
    } else {
      txtarea.value = callback.apply(this, [txtarea.value]);
    }
  } else if (txtarea.selectionStart || txtarea.selectionStart == '0') { // Mozilla
    // get current selection
    txtarea.focus();
    var startPos = txtarea.selectionStart;
    var endPos = txtarea.selectionEnd;
    selText = txtarea.value.substring(startPos, endPos);
    //insert tags
    if (selText) {
      txtarea.value = txtarea.value.substring(0, startPos) + callback.apply(this, [selText]) + txtarea.value.substring(endPos, txtarea.value.length);
      txtarea.selectionStart = startPos + selText.length;
      txtarea.selectionEnd = txtarea.selectionStart;
    } else {
      txtarea.value = callback.apply(this, [txtarea.value]);
    }
  }
}
 
 
/** toggleDir
 *
 *  Description: Toggles the directionality of the text in the edit
 *  box textarea. It is helpful when working on wikitext that contains
 *  mixed Persian and English content, or contains commands that are
 *  in English (e.g. untranslated parser functions, etc.)
 *
 */
function toggleDir(obj) {
  var isrtl = 0;
  if (obj) {
    isrtl = obj.style.direction != 'ltr';
    if (isrtl) {
      obj.style.textAlign = "left";
      obj.style.direction = "ltr";
    } else {
      obj.style.textAlign = "right";
      obj.style.direction = "rtl";
    }
  }
}
 
 
/** fromEntityToUtf8
 *
 *  Description: Takes an HTML entitiy like v and returns the
 *  Unicode equivalent of it (in this example, letter "v").
 *
 *  This is needed because older browsers sometimes turned in HTML
 *  entities instead of Unicode characters.
 *
 */
function fromEntityToUtf8(str) {
  return str.replace(/&#([0-9]+);/g, function (s, n, ofs, all) {
    return String.fromCharCode(n);
  });
}
 
 
/** fromUtf8ToEntity
 *
 *  Description: Takes a Unicode character like the letter "v" and
 *  returns the equivalent HTML entity (in this example, v).
 *
 *  This is not in use anymore and is only kept for historical
 *  purposes.
 *
 */
function fromUtf8ToEntity(str) {
  return str.replace(/([^\x00-\x7f])/g, function (s, c, ofs, all) {
    c = String(c);
    return "&#" + c.charCodeAt(0) + ";";
  });
}
 
 
/** AtSignReplace
 *
 *  Description: Replaces the @ sign in the text with {{at}} to
 *  prevent spam bots from picking up email addresses. 
 *
 *  This function is not used by the default buttons.
 *
 */
function AtSignReplace(str) {
  return str.replace(/(\S+?)@(\S+?)/g, '$1{{at}}$2');
}
 
 
/** URLfix
 *
 *  Description: Finds all links to Wikipedia pages, strips the
 *  http(s) prefix (to ensure the user will not switch protocols
 *  by clicking on the link), and removes the unnecessary parts of
 *  the query string (such as the "title" attribute of a diff link)
 *  to make the URLs shorter and easier to maintain.
 *
 */
function URLfix(str) {
  // Replace every %20 with _ to protect them from decodeURI
  var old = "";
  while (old != str) {
    old = str;
    str = str.replace(/(http\S+?)\%20/g, '$1\u200c\u200c\u200c_\u200c\u200c\u200c');
  }
 
  // Decode URIs
  // NOTE: This would convert all %20's to _'s which could break some links
  // but we will undo that later on
  str = str.replace(/(http\S+)/g, function (s, p) {
    return decodeURI(p)
  });
 
  // Revive all instances of %20 to make sure no links is broken
  str = str.replace(/\u200c\u200c\u200c_\u200c\u200c\u200c/g, '%20');
 
  // Shorten Wikipedia diff URLs
  str = str.replace(/\[(https?\:|)\/\/([\w\-]+)\.wikipedia\.org\/w\/index\.php\?title=[^&\s]*&(diff=[^&\s]+&|)(oldid=\d+)/g, '[//$2.wikipedia.org/w/index.php?$3$4');
 
  // Strip the http(s) prefix
  str = str.replace(/\[(https?\:|)\/\/([\w\-]+)\.wikipedia\.org\/(\S*)/g, '[//$2.wikipedia.org/$3');
 
  return str;
}
 
 
/** YKarabic
 *
 *  Description: Replaces all instances of ي and ك withی and ک,
 *  respectively. It should not make any ch anges to Arabic text
 *  surrounded by appropriate templates, and to interwikis.
 *
 */
function YKarabic(str) {
  var old = "";
 
  // Do not touch the text inside links, images, categories or interwikis
  while (old != str) {
    old = str;
    str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ي(.*?)\]\]/g, '[[$1\u200c\u200c\u200cی\u200c\u200c\u200c$2]]');
    str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ك(.*?)\]\]/g, '[[$1\u200c\u200c\u200cک\u200c\u200c\u200c$2]]');
  }
 
  // Replace every ي and ك with ی and ک, respectively
  // NOTE: This WILL mess with images, links, categories and interwikis
  // but we will undo it later
  str = str.replace(/ي/g, 'ی');
  str = str.replace(/ك/g, 'ک');
 
  // Convert ى to ی (the latter is standard Persian Yeh)
  str = str.replace(/ى/g, 'ی');
 
  // Undo the changes to interwikis, links and images
  // NOTE: This will also undo changes to categories which is not good
  // but we will undo that later
  str = str.replace(/\u200c\u200c\u200cی\u200c\u200c\u200c/g, 'ي');
  str = str.replace(/\u200c\u200c\u200cک\u200c\u200c\u200c/g, 'ك');
 
  old = "";
  // Replace every ي and ك in categories with ی and ک, respectively
  while (old != str) {
    old = str;
    str = str.replace(/\[\[(رده|[Cc]ategory):(.*?)(ى|ي)(.*?)\]\]/g, '[[$1:$2ی$4]]');
    str = str.replace(/\[\[(رده|[Cc]ategory):(.*?)ك(.*?)\]\]/g, '[[$1:$2ک$3]]');
  }
 
  // Finally, replace every ی and ک in Arabic text with ي and ك, respectively
  old = "";
  while (old != str) {
    old = str;
    str = str.replace(/\{\{(عربی|شروع عربی|آغاز عربی)\}\}([^\}]*)ی([^\{]*)\{\{اختتام\sعربی\}\}/g, '{{$1}}$2ي$3{{اختتام عربی}}');
    str = str.replace(/\{\{(عربی|شروع عربی|آغاز عربی)\}\}([^\}]*)ک([^\{]*)\{\{پایان\sعربی\}\}/g, '{{$1}}$2ك$3{{اختتام عربی}}');
    str = str.replace(/\[\[(arz?):(.*?)ی(.*?)\]\]/g, '[[$1:$2ي$3]]');
    str = str.replace(/\[\[(arz?):(.*?)ک(.*?)\]\]/g, '[[$1:$2ك$3]]');
  }
 
  return str;
}
 
 
/** NonStandard
 *
 *  Description: Replaces all instances of non-standard characters
 *  used for heh+yeh, with the standard form of «هٔ».
 *
 */
function NonStandard(str) {
  // The non-standard character ۀ is used in Urdu; we would like to
  // undo changes to Urdu interwikis
  var old = "";
  while (old != str) {
    old = str;
    str = str.replace(/\[\[(ur\:[^\]]*?)ۀ(.*?)\]\]/g, '[[$1\u200c\u200c\u200cهٔ\u200c\u200c\u200c$2]]');
  }
 
  // Replace ه followed by (space|ZWNJ|lrm) follow by ی with هٔ
  str = str.replace(/ه[\u200c\u200e\s]+ی([\s\n])/g, 'هٔ$1');
 
  // Replace ه followed by (space|ZWNJ|lrm|nothing) follow by ء or   ٔ with هٔ
  str = str.replace(/ه[\u200c\u200e\s]*[ءٔ]([\s\n])/g, 'هٔ$1');
 
  // Replace هٓ or single-character ۀ with the standard هٔ
  str = str.replace(/(ۀ|هٓ)/g, 'هٔ');
 
  // Replace ه followed by ئ or ی, and then by ی, with ه‌ای
  // example: خانهئی becomes خانه‌ای
  str = str.replace(/ه‌[ئی]ی/g, 'ه‌ای');
 
  // Revert the changes to the Urdu interwikis
  old = "";
  while (old != str) {
    old = str;
    str = str.replace(/\u200c\u200c\u200cهٔ\u200c\u200c\u200c/g, 'ۀ');
  }
 
  return str;
}
 
 
/** InterwikiSorter
 *
 *  Description: Finds all the interwiki links in the text and sorts
 *  them alphabetaically.
 *
 */
function InterwikiSorter(str) {
  var ref = /\[\[([A-Za-z][A-Za-z-]{1,20}?)\:(.*?)\]\]\r?\n?(\s*)/g
 
  //extract interwiki's and delete them temporarily from the string
  interwikis = str.match(ref);
  if (interwikis == null) return;
  str = str.replace(ref, "");
 
  //sort interwikis
  interwikis = interwikis.sort();
 
  //put interwiki's back
  str = str + interwikis.join("");
 
  return str;
}
 
 
/** SortText
 *
 *  Description: Takes a piece of text in Persian which contains
 *  several lines (separated by the newline character), and sorts
 *  the lines alphabetically, with respect to their first character.
 *
 */
function SortText(str) {
  function sortPreparation(instr){      // solve persian problem on sorting by replace characters in strings
    return instr.replace(/ی/g,"ي")
                .replace(/ک/g,"ك")
                .replace(/گ/g,"كی")
                .replace(/ژ/g,"زی")
                .replace(/چ/g,"جی")
                .replace(/پ/g,"بی");
  }
  temp = str.split('\n');
  temp.sort(function(a,b){ 
    var keyA = sortPreparation(a);
    var keyB = sortPreparation(b);
    if (keyA < keyB) return -1;
    if (keyA > keyB) return 1;
    return 0;
  });
  var result = temp.join('\n');
  return result;
}
 
 
function FM(str) {
  //بن‌های ماضی
  var verbs = "(آراست|آرامید|آزرد|آزمود|آسود|آشامید|آشفت|آغازید|آغشت|آفرید|آگند|آلود|آمد|آمرزید"
       + "|آموخت|آمیخت|آورد|آویخت|آهیخت|ارزید|افتاد|افراشت|افروخت|افزود|افسرد|افشاند|افگند"
       + "|انباشت|انجامید|انداخت|اندوخت|اندود|اندیشید|انگاشت|انگیخت|اوباشت|ایستاد|باخت"
       + "|بارید|بافت|بالید|بایست|بخشود|بخشید|برازید|برد|برید|بست|بسود|بسیجید|بلعید|بود"
       + "|بوسید|بویید|بیخت|پاشید|پالود|پخت|پذیرفت|پراکند|پرداخت|پرستید|پرسید|پرورد|پرید"
       + "|پژمرد|پژوهید|پسندید|پلاسید|پلکید|پناهید|پنداشت|پوسید|پوشید|پویید|پیچید|پیراست"
       + "|پیمود|پیوست|تاخت|تافت|تپید|تراشید|تراوید|ترسید|ترشید|ترکید|تکاند|تکانید|تنید|توانست"
       + "|جست|جُست|جَست|جنبید|جنگید|جوشید|جوید|جهید|چاپید|چایید|چپید|چربید|چرخید|چرید|چسبید|چشید"
       + "|چکید|چلاند|چلانید|چمید|چید|خارید|خاست|خایید|خراشید|خرامید|خروشید|خرید|خزید|خست"
       + "|خشکید|خلید|خمید|خوابید|خواست|خواند|خورد|خوفید|خیسید|داد|داشت|دانست|درخشید|دروید"
       + "|درید|دزدید|دمید|دوخت|دوشید|دوید|دیدم|ربود|رخشید|رسید|رست|رَست|رُست|رشت|رفت|رُفت|روفت"
       + "|رقصید|رمید|رنجید|رندید|رویید|ریخت|رید|زارید|زایید|زد|زدود|زیست|ساخت|سپرد|سپوخت"
       + "|ستد|سترد|ستود|ستیزید|سرود|سرشت|سرید|سزید|سفت|سگالید|سنجید|سوخت|سود|شاشید|شایست"
       + "|شتافت|شد|شست|شکافت|شکست|شکفت|شکیفت|شگفت|شمرد|شناخت|شنید|شورید|طلبید|طوفید|غارتید"
       + "|غرید|غلطید|غنود|فرستاد|فرسود|فرمود|فروخت|فریفت|فشرد|فهمید|قاپید|قبولاند|کاست"
       + "|کاشت|کاوید|کرد|کشت|کشید|مکشید|کفت|کفید|کند|کوچید|کوشید|کوفت|گایید|گداخت|گذاشت"
       + "|گذشت|گرازید|گرایید|گردید|گرفت|گروید|گریخت|گریست|گزارد|گزید|گُزید|گَزید|گسارد|گسترد|گسست"
       + "|گشت|گشود|گفت|گماشت|گنجید|گندید|گوارید|گوزید|لرزید|لغزید|لمدنی|لندید|لنگید|لهید"
       + "|لیسید|ماسید|مالید|ماند|مرد|مکید|مولید|مویید|نازید|نالید|نامید|نشست|نکوهید|نگاشت"
       + "|نگریست|نمود|نواخت|نوردید|نوشت|نوشید|نهاد|نهفت|نیوشید|ورزید|وزید|هراسید|هشت"
       + "|یارست|یازید|یافت)";
 
  var re = new RegExp("(^|[^"+EE_faChrs+"])(می|نمی)\\s?" + verbs + "(م|ی|یم|ید|ند|)($|[^"+EE_faChrs+"])", "g");
  str = str.replace(re, "$1$2\u200c$3$4$5");
 
  //بن‌های مضارع
  verbs = "(آرای|آرام|آزار|آزمای|آسای|آشام|آشوب|آغاز|آغار|آفرین|آگن|آلای|آی|آمرز"
        + "|آموز|آمیز|آور|آویز|آهنج|ارز|افت|افراز|افروز|افزای|افسر|افشان|افگن"
        + "|انبار|انجام|انداز|اندوز|اندای|اندیش|انگار|انگیز|اوبار|ایست|باز"
        + "|بار|باش|باف|بال|بای|بخشای|بخش|براز|بر|بُر|بَر|بند|بساو|بسیج|بلع|بو"
        + "|بوس|بوی|بیز|پاش|پالای|پز|پذیر|پراکن|پرداز|پرست|پرس|پرور|پر"
        + "|پژمر|پژوه|پسند|پلاس|پلک|پناه|پندار|پوس|پوش|پوی|پیچ|پیرای"
        + "|پیمای|پیوند|تاز|تاب|تپ|توپ|تراش|تراو|ترس|ترش|ترک|تکان|تن|توان"
        + "|جه|جوی|جنب|جنگ|جوش|جو|چاپ|چای|چپ|چرب|چرخ|چر|چسب|چش"
        + "|چک|چلان|چم|چین|خار|خیز|خای|خراش|خرام|خروش|خر|خز|خست"
        + "|خشک|خل|خم|خواب|خواه|خوان|خور|خوف|خیس|ده|دار|درخش|درو"
        + "|در|دزد|دم|دوز|دوش|دو|بین|ربای|رخش|رس|ره|روی|رشت|رو|روب"
        + "|رقص|رم|رنج|رند|روی|ریز|رین|زار|زای|زن|زدای|زی|ساز|سپر|سپوز"
        + "|ستان|ستر|ستان|ستیز|سرای|سرشت|سر|سز|سنب|سگال|سنج|سوز|سای|شاش|شای"
        + "|شتاب|شو|شوی|شکاف|شکن|شکوف|شکیب|شمر|شناس|شنو|شور|طلب|طوف|غارت"
        + "|غر|غلط|غنو|فرست|فرسای|فرمای|فروش|فریب|فشر|فهم|قاپ|قبولان|کاه"
        + "|کار|کاو|کن|کار|کُش|کش|کِش|کَش|کف|کن|کوچ|کوش|کوب|گای|گداز|گذار"
        + "|گذر|گراز|گرای|گرد|گیر|گرو|گریز|گری|گزار|گز|گزین|گسار|گستر|گسل"
        + "|گشای|گو|گمار|گنج|گند|گوار|گوز|لرز|لغز|لم|لند|لنگ|له"
        + "|لیس|ماس|مال|مان|میر|مک|مول|موی|ناز|نال|نام|نشین|نکوه|نگار"
        + "|نگر|نمای|نواز|نورد|نویس|نوش|نه|نهنب|نیوش|ورز|وز|هراس|هل"
        + "|یار|یاز|یاب)";
 
  var re = new RegExp("(^|[^"+EE_faChrs+"])(می|نمی)\\s?" + verbs + "(م|ی|د|یم|ید|ند)($|[^"+EE_faChrs+"])", "g");
  str = str.replace(re, "$1$2\u200c$3$4$5");
 
  // ای «توان» ناقلا!
  str = str.replace(/(می|نمی) ?توان/g, "$1\u200cتوان");
 
  // برای حذف علامت ستاره اضافی قبل از عنوان‌ها
  str = str.replace(/\n\*\s*(\=+.+?\=+\n)/g, "\n$1");
 
  // برای حذف فاصله‌های اضافی در پیوندها
  str = str.replace(/\[\[\s*(.*?)\s*]]/g, "[[$1]]");
 
  // عضو علامت‌های نقل قول تکی از عنوان‌ها
  str = str.replace(/(\n=+)(.*?)(?:'+)(.*?)(?:'+)(.*?)(=+\n)/g, "$1$2$3$4$5");
 
  // تبدیل به نویسه / یکی‌کردن فاصله‌های مجازی پشت‌سرهم
  str = str.replace(/(\{\{فم\}\}|\&zwnj\;|\u200c+)/g, '\u200c');
 
  // اول و آخر هم خط اگر فاصلهٔ مجازی باشد، حذف شود
  str = str.replace(/(^\u200c|\u200c$)/mg, '');
 
  //حذف فاصلهٔ مجازی پیش از حروف لاتین و نیز نشانه‌های سجاوندی
  str = str.replace(/\u200c([\w\[\]\n\s\.،«»\:؛])/g, '$1');
 
  //شناسه‌ها
  //توجه: «است» تعدماً از شناسه ها حذف شده چون به عنوان فعل مستقل هم کاربرد دارد و در آن موارد باید جدا نوشته شود
  // مثال: «این یک خانه است» که است در آن باید از خانه جدا نوشته شود
  str = str.replace(new RegExp("ه\\s+(ام|ای|ایم|اید|اند)($|[^"+EE_faChrs+"])", "g"), 'ه\u200c$1$2');
 
  // چسباندن تمام «ها»ها با فاصلهٔ مجازی
  str = str.replace(/\sها([\]\.،\:»\)\s])/g, '\u200cها$1');
  str = str.replace(/\sها(ی|یی|یم|یت|یش|مان|تان|شان)([\]\.،\:»\)\s])/g, '\u200cها$1$2');
 
  // ویکی پدیا و ویکیپدیا به ویکی‌پدیا، و موارد مشابهش
  str = str.replace(/ویکی\s?(پدیا|مدیا|انبار|واژه|نبشته|خبر|نسک)/g, 'ویکی\u200c$1');
 
  // ریشه شناسی و ریشه‌شناسی
  str = str.replace(/ریشه\s{0,3}شناسی/g, 'ریشه\u200cشناسی');
 
  // موارد جزئی دیگر و بی‌ربط به فاصلهٔ مجازی، باید منتقل شود
  str = str.replace(/ا\sً/g, 'اً');
 
  // Remove ZWNJ after characters that don't conncet to the next letter
  re = new RegExp("([" + EE_faNums + EE_enNums +
       "إأةؤورزژاآدذ" + 
       "،؛,\\:" +
       "«»\\/@#$٪×\\*\\(\\)ـ\\-=\\|" + 
       "])" + "\u200c");
  str = str.replace(re, "$1");
 
  // Remove ZWNJ before characters that don't conncet to the previous letter
  re = new RegExp("([" + EE_faNums + EE_enNums +
       "،؛,\\:" +
       "«»\\/@#$٪×\\*\\(\\)ـ\\-=\\|" + 
       "])" + "\u200c");
  str = str.replace(re, "$1");
 
  return str;
}
 
 
/** digitsEnToFa
 *
 *  Description: Takes a string made of English digits only, and
 *  returns a string that represents the same number but with
 *  Persian digits
 *
 */
function digitsEnToFa(str) {
  for (var i = 0; i < 10; i++) {
    reEnToFa = new RegExp("" + i);
    str = str.replace(reEnToFa, EE_faNums[i]);
  }
 
  return str;
}
 
 
/** digitsFaToEn
 *
 *  Description: Takes a string made of English digits only, and
 *  returns a string that represents the same number but with
 *  Persian digits
 *
 */
function digitsFaToEn(str) {
  for (var i = 0; i < 10; i++) {
    reFaToEn = new RegExp(EE_faNums[i]);
    str = str.replace(reFaToEn, i);
  }
 
  return str;
}
 
 
/** digitsArToFa
 *
 *  Description: Takes a string that contains digits, and
 *  replaces all Arabic digits with the corresponding Persian
 *  digits
 *
 */
function digitsArToFa(str) {
  for (var i = 0; i < 10; i++) {
    reArToFa = new RegExp(EE_arNums[i]);
    str = str.replace(reArToFa, EE_faNums[i]);
  }
 
  return str;
}
 
 
/** digits_move
 *
 *  Description: A special flavor of digits() function that is
 *  to be used only on the move page. It is more simplistic than
 *  the digits() function itself.
 *
 */
function digits_move(str) {
  str = fromEntityToUtf8(str, true);
 
  old = "";
  // Convert all English digits to Persian digits
  while (old != str) {
    old = str;
    re = new RegExp("[" + EE_enNums + "]+");
    str = str.replace(re, digitsEnToFa);
  }
 
  old = "";
  // Convert all Arabic digits to Persian digits
  while (old != str) {
    old = str;
    re = new RegExp("[" + EE_arNums + "]+");
    str = str.replace(re, digitsArToFa);
  }
 
  return(str);
}
 
 
function digits(str) {
  // Disabled for Template namespace, due to recurring problems
  if (mw.config.get('wgNamespaceNumber') == 10) {
    return str;
  } else {
    str = fromEntityToUtf8(str, true);
 
    old = "";
 
    // Convert all English digits to Persian digits if preceded by Persian text
    while (old != str) {
      old = str;
      re = new RegExp("([" + EE_faChrs + EE_faNums
         + "][^A-Za-z0-9\\n\\{\\}\\|=]*)([" + EE_enNums + "])"
         + "([^A-Za-z\\n\\{\\}\\|=]*?)");
      str = str.replace(re, function(v1,v2,v3,v4){return v2 + digitsEnToFa(v3) + v4});
    }
 
    old = "";
    // Convert all Arabic digits to Persian digits
    while (old != str) {
      old = str;
      re = new RegExp("[" + EE_arNums + "]+");
      str = str.replace(re, digitsArToFa);
    }
 
    // OLD CODE:
    // فارسی به انگلیسی (آن‌هایی که حتماً باید انگلیسی شوند)
    while (true) {
      for (var i = 0; i < 10; i++) {
         var reFaToEn = new RegExp("(style|colspan|rowspan|cellspacing|width|size|border|thumbtime)"
                                   + "( *= *[^\\|\\n]*?)" + EE_faNums[i] + "(.*?\\|)", "g");
         old = old.replace(reFaToEn, "$1$2¬!¬" + i + "$3")
                  .replace(/¬!¬/, "");
         var reFaToEn = new RegExp("(<math>[^<]*?)" + EE_faNums[i] + "([^<]*<\\/math>)", "g");
         old = old.replace(reFaToEn, "$1¬!¬" + i + "$2")
                  .replace(/¬!¬/, "");
         var reFaToEn = new RegExp("(https?://[^\\s\\r\\n\\|\\}]*?)" + EE_faNums[i], "g");
         old = old.replace(reFaToEn, "$1¬!¬" + i)
                  .replace(/¬!¬/, "");
         var reFaToEn = new RegExp(EE_faNums[i] + "([0-9" + EE_faNums
                                   + "]*)(عکصر|px)\\s*([\\|\\]])", "g");
         old = old.replace(reFaToEn, i + "$1$2$3");
      }
      if (old == str) break;
      str = old;
    }
 
    // Decimal point, and thousands' separator
    str = str.replace(/([۱۲۳۴۵۶۷۸۹۰])\.([۱۲۳۴۵۶۷۸۹۰])/g, '$1٫$2');
    str = str.replace(/([۱۲۳۴۵۶۷۸۹۰]),([۱۲۳۴۵۶۷۸۹۰])/g, '$1٬$2');
    return str;
  }
}
 
 
function Punctuation(str) {
  str = str.replace(/ *(\<\/? ?br ?\/?\>|\{\{بر\}\}) */g, "{{سخ}}");
 
  str = str.replace(/([،\.])([^\s\.\(\)«»\"\[\]\<\>\d\w\{\}\|۰-۹])/g, "$1 $2");
 
  str = str.replace(/([\(«])\s/g, '$1');
  str = str.replace(/\s([\)»])/g, '$1');
  str = str.replace(/٬\s/g, "، ");
 
  str = str.replace(/(\<\/ref\>)\s+(\<ref)/g, "$1$2");
 
  // Format headings level 2 and above
  str = str.replace(/(\={2,})\s*([^\=]*?)\s*(\={2,})/g, "$1 $2 $3");
  // TODO: remove extra lines AFTER this part
 
  // تغییرات جزئی که برای ربات‌ها تعریف شده بود
  str = str.replace(/[\r\n]{3,}/g, "\n\n");
  str = str.replace(/[\r\n]\s{1,}[\r\n]/g, "\n\n");
  str = str.replace(/([^=])[\r\n]+(\=.*?\=[\r\n]+)/g, "$1\n\n$2");
  str = str.replace(/[\s\r\n]+\<ref/g, "<ref");
  str = str.replace(/([\r\n]?)[\s\r\n]+?\<\/ref\>/g, "$1</ref>");
 
  // Add a space after the # or * for lists
  str = str.replace(/^([*#]+)([^*#:\s])/mg, "$1 $2");
 
  // Remove extra newlines between two list lines
  old = "";
  while(str!=old){
    old = str;
    str = str.replace(/(^|\n)(#+[^\n]*)\n\n+([#])/mg, "$1$2\n$3");
    str = str.replace(/(^|\n)(\*+[^\n]*)\n\n+([\*])/mg, "$1$2\n$3");
  }
 
  //برداشتن حروف نالازم در ابتدا و انتهای عنوان زیر بخش‌های سطح ۲ به بالا
  var notneededs=":,;'<>»«&^#@•→←↔↑↓—–…~٫،؛ٔ"
  for (var i = 0; i < 27; i++) {
    str = str.replace(new RegExp('((\=+){2,}) '+notneededs[i], 'g'),"== ");
    str = str.replace(new RegExp(notneededs[i]+' ((\=+){2,})', 'g')," $1");
  }
 
  // Redirect pages must start with #REDIRECT with no extra spaces
  // before or inside the تغییرمسیر part, and one space after it but
  // before the link
  str = str.replace(/^#\s*(REDIRECT|تغییر\s*مسیر)/ig, '#REDIRECT');
  str = str.replace(/^#REDIRECT(\S)/g, '#REDIRECT $1');
 
  // Remove extra newline between two lines both starting with a *
  str = str.replace(/(\n\*.*?)\n+(?=\n\*)/g, '$1');
 
  // فاصله را از آخر خط پاک می‌کند
  str = str.replace(/([^=]) *$/mg, "$1");
 
 
  // اصلاح {{•}}
  str = str.replace(/[\n\s]*\{\{[•·ن](w?)\}\}\s*/g, "{{•$1}} ");
 
  // برای گذاشتن گیومه برای خاصیت‌های برچسب طبق اکس‌ام‌ال
  // اشکال مشخصی که دارد این است که همهٔ نویسه‌های قابل قبول برای اکس‌ام‌ال را نمی‌پذیرد، چه نویسه‌هایی لازم است؟
  var old = "";
  while (old != str) {
    old = str;
    str = str.replace(/(\<\w*(?:\s\w*=['"\w\d]+)*\s+\w*=)([\w\d_]+)((?:\s\w*=['"\w\d]+)*\s?\/?\>)/g, "$1\"$2\"$3")
    // first version: .replace(/\<(\w*\s+\w*=)(\w+[\w\d]*)\>/, "<$1\"$2\">");
  }
 
  // Remove spaces preceding the }} closing tag for templates
  str = str.replace(/\s+\}\}/g, '}}');
 
  // Remove space after ( and before ) if there are Persian characters
  // on both sides; also, add a space before ( and after ) in the same
  // situation
  re = new RegExp("([" + EE_faChrs + "]+)\\s*\\(\\s*([" + EE_faChrs + "]+)", "g");
  str = str.replace(re, "$1 ($2");
  re = new RegExp("([" + EE_faChrs + "]+)\\s*\\)\\s*([" + EE_faChrs + "]+)", "g");
  str = str.replace(re, "$1) $2");
 
  old = "";
  while (old != str) {
    old = str;
    // Convert , to ، if there are Persian characters on both sides of it
    // and also remove any spaces between the words on each side and the
    // Persian comma itself.
    // NOTE: we will add a space after the comma later on
    var re = new RegExp(" ([ "+EE_faChrs+"]+),([ "+EE_faChrs+"]+)", "g");
    str = str.replace(re, "$1،$2");
 
    // Remove space preceding puncations
    str = str.replace(/ ([؟،:؛!\.])/g, "$1");
 
    // Add space after punctuations
    // NOTE: Adds a space after :, which affects internal links (categories, images, etc)
    re = new RegExp("(["+EE_faChrs+"]+)([؟،:؛!\.])(["+EE_faChrs+"]+)", "g");
    str = str.replace(re, "$1$2 $3");
 
    // Remove unnecessary space caused by last line in category links
    re = new RegExp("\\[\\[([" + EE_faChrs + "]+)\\:\\s+", "g");
    str = str.replace(re, "[[$1\:");
  }
 
  return str;
}
 
 
/** SuperTool
 *
 *  Description: Applies all of YKarabic, FM, NonStandard and digits
 *  functions to the text.
 *
 */
function SuperTool(str) {
  str = YKarabic(str);
  str = FM(str);
  str = NonStandard(str);
  str = digits(str);
  str = Punctuation(str);
 
  return str;
}
 
 
 
/** SuperTool_move
 *
 *  Description: A special flavor of the SuperTool() function
 *  that should only be used on the move page.
 *
 */
function SuperTool_move(str) {
  str = YKarabic(str);
  str = FM(str);
  str = NonStandard(str);
  str = digits_move(str);
  str = Punctuation(str);
 
  return str;
}