بەکارھێنەر:Aram/Gadget-Extra-Editbuttons-Functions.js

تێبینی: دوای پاشەکەوتکردن، پێویستە کاشی وێبگەڕەکەت پاک بکەیتەوە تا گۆڕانکارییەکان ببینیت. بۆ گووگڵ کڕۆم، فایەرفۆکس، مایکرۆسۆفت ئێج و سافاری: پەنجە لەسەر دوگمەی ⇧ Shift ڕاگرە و کرتە لەسەر Reload بکە. بۆ وردەکاری و ڕێنمایییەکان لەسەر وێبگەڕەکانی تر، بڕوانە ئێرە.
/*




var EE_ckbChrs = "ءاآأإئؤبپتثجچحخدذرڕزژسشصضطظعغفڤقکگلڵمنوھەیةيکه" + "ًٌٍَُِّْ";
var EE_faNums = "۰۱۲۳۴۵۶۷۸۹";
var EE_ckbNums = "٠١٢٣٤٥٦٧٨٩";
var tupN = [];
var tupO = [];

/*
 * Javascript Diff Algorithm
 *  http://ejohn.org/projects/javascript-diff-algorithm/
 */

/*
function links_underline(str, rev_type) {
    //this function is used to have better results for Diff Algorithm in wikilinks
    var falinks = str.match(/\[\[.*?\]\]/g);
    if (falinks) {
        if (rev_type == 'Start') {
            for (var i = 0; i < falinks.length; i++) {
                var item_s = falinks[i];
                var intem_u = falinks[i].replace(/\s/g, '_');
                str = str.replace(item_s, intem_u);
            }
        } else {
            for (var i = 0; i < falinks.length; i++) {
                var item_s = falinks[i].replace(/\_/g, ' ');
                var intem_u = falinks[i];
                str = str.replace(intem_u, item_s);
            }
        }
    };
    return str;
}
window.links_underline = links_underline;

function escape(s) {
    //Diff Algorithm's functions
    var n = s;
    n = n.replace(/&/g, "&amp;");
    n = n.replace(/</g, "&lt;");
    n = n.replace(/>/g, "&gt;");
    n = n.replace(/"/g, "&quot;");

    return n;
};

function di_escape(s) {
    //Diff Algorithm's functions
    var n = s;
    n = n.replace(/&amp;/g, "&");
    n = n.replace(/&lt;/g, "<");
    n = n.replace(/&gt;/g, ">");
    n = n.replace(/&quot;/g, '"');

    return n;
};


function diffString(o, n) {
    //Diff Algorithm's functions
    tupN = [];
    tupO = [];
    o = o.replace(/\s+$/, '');
    n = n.replace(/\s+$/, '');
    var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
    var oSpace = o.match(/\s+/g);
    if (oSpace == null) {
        oSpace = ["\n"];
    } else {
        oSpace.push("\n");
    }
    var nSpace = n.match(/\s+/g);
    if (nSpace == null) {
        nSpace = ["\n"];
    } else {
        nSpace.push("\n");
    }
    if (out.n.length == 0) {
        for (var i = 0; i < out.o.length; i++) {
            tupO.push(escape(out.o[i]))
        }
    } else {
        if (out.n[0].text == null) {
            for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
                tupO.push(escape(out.o[n]));
            }
        }
        for (var i = 0; i < out.n.length; i++) {
            if (out.n[i].text == null) {
                tupN.push(escape(out.n[i]));
            } else {
                for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
                    tupO.push(escape(out.o[n]));
                }
            }
        }
    }
    o = '';
    n = '';
}

function diff(o, n) {
    //Diff Algorithm's functions
    var ns = new Object();
    var os = new Object();

    for (var i = 0; i < n.length; i++) {
        if (ns[n[i]] == null) ns[n[i]] = {
            rows: new Array(),
            o: null
        };
        ns[n[i]].rows.push(i);
    }

    for (var i = 0; i < o.length; i++) {
        if (os[o[i]] == null) os[o[i]] = {
            rows: new Array(),
            n: null
        };
        os[o[i]].rows.push(i);
    }

    for (var i in ns) {
        if (ns[i].rows.length == 1 && typeof (os[i]) != "undefined" && os[i].rows.length == 1) {
            n[ns[i].rows[0]] = {
                text: n[ns[i].rows[0]],
                row: os[i].rows[0]
            };
            o[os[i].rows[0]] = {
                text: o[os[i].rows[0]],
                row: ns[i].rows[0]
            };
        }
    }

    for (var i = 0; i < n.length - 1; i++) {
        if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) {
            n[i + 1] = {
                text: n[i + 1],
                row: n[i].row + 1
            };
            o[n[i].row + 1] = {
                text: o[n[i].row + 1],
                row: i + 1
            };
        }
    }

    for (var i = n.length - 1; i > 0; i--) {
        if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && n[i - 1] == o[n[i].row - 1]) {
            n[i - 1] = {
                text: n[i - 1],
                row: n[i].row - 1
            };
            o[n[i].row - 1] = {
                text: o[n[i].row - 1],
                row: i - 1
            };
        }
    }

    return {
        o: o,
        n: n
    };
};

function RevertBug(diffO, diffN, str) {
    //Diff Algorithm's functions + Reverting Bug's functions
    for (var i = 0; i < diffN.length; i++) {

        //Checking Interwikis' Links
        var diffN_di = di_escape(diffN[i])
        var diffO_di = di_escape(diffO[i])
        var item = diffN_di
        var regex = /\[\[([a-z]{2,3}|[a-z]{2,3}\-[a-z\-]{2,}|simple)(\s|_|)\:(.*?)(\s|_|\:.*|)\]\]/g
        var interwikis = item.match(regex);
        if (interwikis != null) {
            str = str.replace(diffN_di, diffO_di);
        };

        //Checking Files' Links
        if (item.replace(/\|/g, "") != item) {
            var regex = /\[\[ *(?:پەڕگە|میدیا|[Ff]ile|[Ii]mage)(\s|_|)\:(\s|_|)(.*?)\|/g
        } else {
            var regex = /\[\[ *(?:پەڕگە|میدیا|[Ff]ile|[Ii]mage)(\s|_|)\:(\s|_|)(.*?)\]\]/g
        };
        var filelinkN = diffN_di.match(regex);
        var filelinkO = diffO_di.match(regex);
        if (filelinkN != null) {
            str = str.replace(filelinkN, filelinkO);
        };

        //Checking User's Sign Link
        var regex = /\[\[(\s|_|)([Uu]ser|بەکارھێنەر|لێدوانی بەکارھێنەر|لێدوانی_بەکارھێنەر|تایبەت)(\s|_|)\:/g
        var UserSign = item.match(regex);
        if (UserSign != null) {
            str = str.replace(diffN_di, diffO_di);
        };

        //Checking URLs
        var regex = /(\[\/\/[\w\-]+?\.wiki|https?\:\/\/)(\S+)/g
        var URLlinkN = diffN_di.match(regex);
        var URLlinkO = diffO_di.match(regex);
        if (URLlinkN != null) {
            str = str.replace(URLlinkN, URLlinkO);
        };
    };
    diffO = '';
    diffN = '';
    return str;
}
window.RevertBug = RevertBug;

/** 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]);
        }
    }
}
window.applyOnSelection = applyOnSelection;


/** 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";
        }
    }
}
window.toggleDir = toggleDir;

/** hejiraYearFix
 *
 *  Description: It checks the hejira years and convert all to Gregorian. It is helpful when working on hejira years or you working on persian articles
 *
 */

/*
function hejiraYearFix(){

    var txt = document.getElementById("wpTextbox1").value;

    
    var res = txt.replace(/\b\d{4}\b/g,function(m){
        return parseInt(m)+621});
    
    document.getElementById("wpTextbox1").innerHTML = res;
}
window.hejiraYearFix = hejiraYearFix;


/** fromEntityToUtf8
 *
 *  Description: Takes an HTML entitiy like &#118; 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);
    });
}
window.fromEntityToUtf8 = fromEntityToUtf8;


/** fromUtf8ToEntity
 *
 *  Description: Takes a Unicode character like the letter "v" and
 *  returns the equivalent HTML entity (in this example, &#118;).
 *
 *  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) + ";";
    });
}
window.fromUtf8ToEntity = fromUtf8ToEntity;


/** 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');
}
window.AtSignReplace = AtSignReplace;


/** 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;
}
window.URLfix = URLfix;


/** 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|$2\u200b\u200b\u200bی\u200b\u200b\u200b$3}}');
        str = str.replace(/\{\{(بە سیندی)\|(.*?)ه(.*?)\}\}/g, '{{$1|$2\u200f\u200f\u200fھ\u200f\u200f\u200f$3}}');
        str = str.replace(/\{\{(بە پەشتۆ)\|(.*?)ي(.*?)\}\}/g, '{{$1|$2\u200b\u200b\u200bی\u200b\u200b\u200b$3}}');
        str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ي(.*?)\]\]/g, '[[$1\u200f\u200f\u200fی\u200f\u200f\u200f$2]]');
        str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ى(.*?)\]\]/g, '[[$1\u200b\u200b\u200bی\u200b\u200b\u200b$2]]');
        str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ك(.*?)\]\]/g, '[[$1\u200f\u200f\u200fک\u200f\u200f\u200f$2]]');
        str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ه‌(.*?)\]\]/g, '[[$1\u200f\u200f\u200fە\u200f\u200f\u200f$2]]');
        str = str.replace(/\[\[([^\]]*?\:[^\]]*?)ه(.*?)\]\]/g, '[[$1\u200f\u200f\u200fھ\u200f\u200f\u200f$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, 'ک');
    str = str.replace(/ى/g, 'ی');
    str = str.replace(new RegExp('ه($|[^ء-يٱ-ە])', 'g'), 'ە$1');
    str = str.replace(/ە‌/g, 'ە');
    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(/\u200f\u200f\u200fی\u200f\u200f\u200f/g, 'ي');
    str = str.replace(/\u200b\u200b\u200bی\u200b\u200b\u200b/g, 'ى');
    str = str.replace(/\u200f\u200f\u200fک\u200f\u200f\u200f/g, 'ك');
    str = str.replace(/\u200f\u200f\u200fه\u200f\u200f\u200f/g, 'ه‌');
    str = str.replace(/\u200f\u200f\u200fھ\u200f\u200f\u200f/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]]');
        str = str.replace(/\[\[(پۆل|[Cc]ategory):(.*?)ه‌(.*?)\]\]/g, '[[$1:$2$3ە]]');
        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(/\{\{(عەرەبی|سەرەتای عەرەبی)\}\}([^\}]*)ە([^\{]*)\{\{کۆتایی\sعەرەبی\}\}/g, '{{$1}}$2ه$3{{کۆتایی عەرەبی}}');
        str = str.replace(/\{\{(عەرەبی|سەرەتای عەرەبی)\}\}([^\}]*)ھ([^\{]*)\{\{کۆتایی\sعەرەبی\}\}/g, '{{$1}}$2ه$3{{کۆتایی عەرەبی}}');
        str = str.replace(/\{\{(بە پەشتۆ)\|(.*?)ى(.*?)\}\}/g, '{{$1|$2ي$3}}');
        str = str.replace(/\{\{(عەرەبی|بە عەرەبی|بە سیندی|بە ئویغوری)\|(.*?)ی(.*?)\}\}/g, '{{$1|$2ي$3}}');
        str = str.replace(/\{\{(عەرەبی|بە عەرەبی|بە ئویغوری)\|(.*?)ک(.*?)\}\}/g, '{{$1|$2ك$3}}');
        str = str.replace(/\{\{(عەرەبی|بە عەرەبی|فارسی|بە فارسی|ن.فارسی|بە پەشتۆ)\|(.*?)ە(.*?)\}\}/g, '{{$1|$2ه$3}}');
        str = str.replace(/\{\{(عەرەبی|بە عەرەبی|فارسی|بە فارسی|ن.فارسی|بە پەشتۆ)\|(.*?)ھ(.*?)\}\}/g, '{{$1|$2ه$3}}');
    }

    return str;
}
window.YKarabic = YKarabic;

/** 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,"ری")
            .replace(/ژ/g,"زی")
            .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;
}
window.SortText = SortText;


/** 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_ckbNums[i]);
    }

    return str;
}
window.digitsEnToFa = digitsEnToFa;


/** 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_ckbNums[i]);
        str = str.replace(reFaToEn, i);
    }

    return str;
}
window.digitsFaToEn = digitsFaToEn;


/** 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_faNums[i]);
        str = str.replace(reArToFa, EE_ckbNums[i]);
    }

    return str;
}
window.digitsArToFa = digitsArToFa;


/** 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("[0-9]+");
        str = str.replace(re, digitsEnToFa);
    }

    old = "";
    // Convert all Arabic digits to Persian digits
    while (old != str) {
        old = str;
        re = new RegExp("[" + EE_faNums + "]+");
        str = str.replace(re, digitsArToFa);
    }

    return (str);
}
window.digits_move = digits_move;


function digits(str) {
    // Disabled for Template namespace, due to recurring problems
    if (mw.config.get('wgNamespaceNumber') == 10) {
        return str;
    } else {
        //These two lines are for reverting link's bugs!
        str = links_underline(str, 'Start')
        var old_text = str;
        // end
        str = fromEntityToUtf8(str, true);
        var old = str;
        // کوردی بۆ ئینگلیزی
        while (1 == 1) {
            for (var i = 0; i < 10; i++) {
                var reFaToEn = new RegExp("([A-Za-z0-9][^" + EE_ckbChrs + EE_ckbNums + "\\n\\{\\}\\|=]*)" + EE_ckbNums[i] + "([^" + EE_ckbNums + "\\n\\{\\}\\|=]*?[A-Za-z0-9])", "g");
                old = old.replace(reFaToEn, "$1¬!¬" + i + "$2");
                old = old.replace(/¬!¬/g, "");
                var reFaToEn = new RegExp("(^|[\\n=>])([^" + EE_ckbChrs + EE_ckbNums + "\\n\\{\\}\\|=]*)" + EE_ckbNums[i] + "([^" + EE_ckbNums + "\\n\\{\\}\\|=]*?[A-Za-z0-9])", "g");
                old = old.replace(reFaToEn, "$1$2¬!¬" + i + "$3");
                old = old.replace(/¬!¬/g, "");
                var reFaToEn = new RegExp("([A-Za-z0-9][^" + EE_ckbChrs + EE_ckbNums + "\\n\\{\\}\\|=]*)" + EE_ckbNums[i] + "([^" + EE_ckbNums + "\\n\\{\\}\\|=]*?[\\n\\{\\}\\|<$])", "g");
                old = old.replace(reFaToEn, "$1¬!¬" + i + "$2");
                old = old.replace(/¬!¬/g, "");
            }
            if (old == str) break;
            str = old;
        }
        // ئینگلیزی بۆ کوردی
        while (1 == 1) {
            for (var i = 0; i < 10; i++) {
                var reEnToFa = new RegExp("([" + EE_ckbChrs + ">][^A-Za-z0-9\\n\\{\\}\\|=]*)" + i + "([^A-Za-z\\n\\{\\}\\|=]*?[<" + EE_ckbChrs + EE_ckbNums + "])", "g");
                old = old.replace(reEnToFa, "$1" + EE_ckbNums[i] + "$2");
                var reEnToFa = new RegExp("(^|[=\\n\\{\\}\\|>])([^A-Za-z0-9\\n\\{\\}\\|=]*)" + i + "([^A-Za-z\\n\\{\\}\\|=]*?[\\n\\{\\}\\|<$])", "g");
                old = old.replace(reEnToFa, "$1$2" + EE_ckbNums[i] + "$3");
            }
            if (old == str) break;
            str = old;
        }
        // کوردی بۆ ئینگلیزی (ئەوانەی حەتمەن دەبێ ببن بە ئینگلیزی )
        while (1 == 1) {
            for (var i = 0; i < 10; i++) {
                var reFaToEn = new RegExp('(style|colspan|rowspan|isbn|oclc|cellspacing|width|size|border|وتاری ھەڵبژێردراو|thumbtime)( *= *[^\\|\\n]*?)' + EE_ckbNums[i] + '(.*?\\|)', 'g');
                old = old.replace(reFaToEn, "$1$2¬!¬" + i + "$3");
                old = old.replace(/¬!¬/g, "");
                var reFaToEn = new RegExp('(<math>[^<]*?)' + EE_ckbNums[i] + '([^<]*<\\/math>)', 'g');
                old = old.replace(reFaToEn, "$1¬!¬" + i + "$2");
                old = old.replace(/¬!¬/g, "");
                var reFaToEn = new RegExp('(https?://[^\\s\\r\\n\\|\\}]*?)' + EE_ckbNums[i], 'g');
                old = old.replace(reFaToEn, "$1¬!¬" + i);
                old = old.replace(/¬!¬/g, "");
                var reFaToEn = new RegExp('(' + EE_ckbNums[i] + ')پیکسێل', 'g');
                old = old.replace(reFaToEn, "$1¬!¬پیکسێل" + i);
                old = old.replace(/¬!¬/g, "");
            }
            if (old == str) break;
            str = old;
        }

        // فارسی بۆ کوردی
        for (var i = 0; i < 10; i++) {
            str = str.replace(new RegExp(EE_faNums[i], 'g'), EE_ckbNums[i]);
        }

        //These three lines are for reverting link's bugs!
        diffString(old_text, str);
        str = RevertBug(tupO, tupN, str);
        str = links_underline(str, 'End')
        //end 

        // Decimal point, and thousands' separator
        str = str.replace(/([١٢٣٤٥٦٧٨٩٠])\.([١٢٣٤٥٦٧٨٩٠])/g, '$1٫$2');
        str = str.replace(/([١٢٣٤٥٦٧٨٩٠]),([١٢٣٤٥٦٧٨٩٠])/g, '$1٬$2');

        return str;
    }
};
window.digits = digits;


function Punctuation(str) {
    // برای حذف فاصله‌های اضافی در پیوندها
    str = str.replace(/\[\[\s*(.*?)\s*]]/g, "[[$1]]");

    // تبدیل به نویسه / یکی‌کردن فاصله‌های مجازی پشت‌سرهم
    str = str.replace(/(\{\{فم\}\}|\&zwnj\;|\u200c+)/g, '\u200c');

    // اول و آخر هم خط اگر فاصلهٔ مجازی باشد، حذف شود
    str = str.replace(/(^\u200c|\u200c$)/mg, '');

    // موارد جزئی دیگر و بی‌ربط به فاصلهٔ مجازی، باید منتقل شود
    str = str.replace(/ا\sً/g, 'اً');

    // Remove ZWNJ after characters that don't conncet to the next letter
    re = new RegExp("([" + EE_ckbNums +
        "0-9" +
        "إأةؤورزژاآدذ" +
        "،؛,\\:" +
        "«»\\/@#$٪×\\*\\(\\)ـ\\-=\\|" +
        "])" + "\u200c");
    str = str.replace(re, "$1");

    // Remove ZWNJ before characters that don't conncet to the previous letter
    re = new RegExp("([" + EE_ckbNums +
        "0-9" +
        "،؛,\\:" +
        "«»\\/@#$٪×\\*\\(\\)ـ\\-=\\|" +
        "])" + "\u200c");
    str = str.replace(re, "$1");

    //These two lines are for reverting link's bugs!
    str = links_underline(str, 'Start')
    var old_text = str;
    // end

    //حذف فاصلهٔ مجازی پیش از حروف لاتین 
    //سجاوندی را از بخش واگردانی باگ خارج کردم
    str = str.replace(/\u200c([\w])/g, '$1');
    str = str.replace(/([\w])\u200c/g, '$1');

    //These three lines are for reverting link's bugs!
    diffString(old_text, str);
    str = RevertBug(tupO, tupN, str);
    str = links_underline(str, 'End')
    //end

/*
    //حذف فاصلهٔ مجازی قبل و بعد از سجاوندی 
    str = str.replace(/\u200c([\n\s\[\]\.،«»\:\(\)\؛\؟\?\;\$\!\@\-\=\+\\])/g, '$1');
    str = str.replace(/([\n\s\[\]\.،«»\:\(\)\؛\؟\?\;\$\!\@\-\=\+\\])\u200c/g, '$1');

    str = str.replace(/ *(\<\/? ?br ?\/?\>|\{\{بر\}\}) g, "<br/>");

    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 the REDIRECT part, and one space after it but
    // before the link
    str = str.replace(/^#\s*(REDIRECT)/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?)\}\}\sg, "{{•$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_ckbChrs + "]+)\\s*\\(\\s*([" + EE_ckbChrs + "]+)", "g");
    str = str.replace(re, "$1 ($2");
    re = new RegExp("([" + EE_ckbChrs + "]+)\\s*\\)\\s*([" + EE_ckbChrs + "]+)", "g");
    str = str.replace(re, "$1) $2");

    // Full stop and comma should be before citation.
    old = "";
    while (old != str) {
        old = str;
        str = str.replace(/\.? ?(<ref>[^<]*<\/ref>) ?\./g, '.$1');
        str = str.replace(/\،? ?(<ref>[^<]*<\/ref>) ?\،/g, '،$1');
    }

    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_ckbChrs + "]+),([ " + EE_ckbChrs + "]+)", "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_ckbChrs + "]+)([؟،؛!\.])([" + EE_ckbChrs + "]+)", "g");
        str = str.replace(re, "$1$2 $3");
    }

    // Remove unnecessary space caused by last line in category links (it had bug for پرونده:)
    re = new RegExp("\\[\\[(پۆل|داڕێژە|ویکیپیدیا)\\:\\s+", "g");
    str = str.replace(re, "[[$1\:");

    str = str.trim(); //Removing \n and \r from first and end of pages
    return str;
};
window.Punctuation = Punctuation;
 
/** Dictation Tool
 *
 *  Description: Correcting diction mistakes
 *  it uses [[میدیاویکی:Gadget-Extra-Editbuttons-Dictionary.js]] as dictionary.
 *
 */
/*
function Regex_Replace(W1, W2, Extensions, str) {
    var regex = new RegExp("(^|[^" + EE_ckbChrs + "])(\\s|\u200c|\_|)(" + W1 + ")(\\s|\_)(" + W2 + ")(\\s|\u200c|\_|)(" + Extensions + ")($|[^" + EE_ckbChrs + "])", "g");
    str = str.replace(regex, "$1$2$3\u200c$5$6$7$8");
    return str;
};
window.Regex_Replace = Regex_Replace;
*/
/*
function Dictation(str) {
 
    //These two lines are for reverting link's bugs!
    str = links_underline(str, 'Start')
    var old_text = str;
    // end
    
    //wrong dictation
    for (var word in ForReplace) {
        var W1 = word;
        var W2 = ForReplace[word];
        var regex = new RegExp("(^|[^" + EE_ckbChrs + "])(\\s|\u200c|_|)(" + W1 + ")(\\s|\u200c|_|)($|[^" + EE_ckbChrs + "])", "g");
        str = str.replace(regex, "$1$2" + W2 + "$4$5");
    };
 
    //These three lines are for reverting link's bugs!
    diffString(old_text, str);
    str = RevertBug(tupO, tupN, str);
    str = links_underline(str, 'End')
    //end 
 
    return str;
};
window.Dictation = Dictation;

*/
/** SuperTool
 *
 *  Description: Applies all of YKarabic, FM and digits
 *  functions to the text.
 *
 */

/*
function SuperTool(str) {
    str = YKarabic(str);
    str = digits(str);
    str = Punctuation(str);
    str = Dictation(str);
    str = URLfix(str);
    return str;
};
window.SuperTool = SuperTool;
*/

/** 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 = digits_move(str);
    str = Punctuation(str);
    str = Dictation(str);
    return str;
};
window.SuperTool_move = SuperTool_move;
*/