مدیاویکی:Gadget-Extra-Editbuttons-persianwikitools.js

از پژوهشکده امر به معروف
نسخهٔ تاریخ ‏۱۱ اسفند ۱۳۹۴، ساعت ۱۰:۱۹ توسط Admin (نظرات | مشارکت‌ها) (صفحه‌ای تازه حاوی «// <nowiki> // DO NOT REMOVE THIS LINE EVER /** * Wikipedia specific Persian text style improvement tools * Tests: [[مدیاویکی:Gad...» ایجاد کرد)

(تفاوت) → نسخهٔ قدیمی‌تر | نمایش نسخهٔ فعلی (تفاوت) | نسخهٔ جدیدتر ← (تفاوت)
پرش به: ناوبری، جستجو

نکته: پس از ذخیره‌کردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.

  • فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلید‌های Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-R)
  • گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-Shift-R)
  • اینترنت اکسپلورر: کلید Ctrl را نگه‌دارید و روی دکمهٔ Refresh کلیک کنید، یا کلید‌های Ctrl-F5 را با هم فشار دهید
  • اپرا: حافظهٔ نهانی مرورگر را از طریق منوی Tools → Preferences پاک کنید
// <nowiki> // DO NOT REMOVE THIS LINE EVER
/**
 * Wikipedia specific Persian text style improvement tools
 * Tests: [[مدیاویکی:Gadget-Extra-Editbuttons-tests.js]] [[وپ:تست]]
 * See also: [[مدیاویکی:Gadget-Extra-Editbuttons-persiantools.js]]
 */
/*global persianTools, persianToolsDictionary, autoEd*/
var persianWikiTools = (function () {
    'use strict';

    function descendingFromComparetor(x, y) {
        return x.from - y.from;
    }

    function replaceExcept(text, callback, excepts) {
        var match, result = [], i, ranges, minRange, to, min, max;
        while (text !== '') {
            ranges = [];

            for (i in excepts) {
                if (excepts.hasOwnProperty(i)) {
                    // a global regex should be reset before calls
                    excepts[i].lastIndex = 0;
                    match = excepts[i].exec(text);
                    if (match !== null) {
                        ranges.push({
                            from: match.index,
                            to: match.index + match[0].length
                        });
                    }
                }
            }

            // so nothing is matched
            if (ranges.length === 0) {
                result.push(callback(text));
                break;
            }

            minRange = ranges.sort(descendingFromComparetor)[0];
            min = minRange.from;

            to = [];
            for (i in ranges) {
                if (ranges.hasOwnProperty(i)) {
                    if (ranges[i].from <= minRange.to) {
                        to.push(ranges[i].to);
                    }
                }
            }
            max = Math.max.apply(null, to);

            result.push(callback(text.substr(0, min)));
            result.push(text.substr(min, max - min));
            // console.log('Excepted: "' + text.substr(min, max - min) + '"');
            text = text.substr(max);
        }
        return result.join('');
    }

    var patterns = {
        arabicDigitsEnglishContext: /[a-z][a-z %"'\._:\;,\-\\\/\(\)\#\^\+\d><–\[\]&?{}]*\d|(\d|[a-z])[a-z %"'\._:\;\|,\-\\\/\(\)\#\^\+\d><–\[\]&?{}]*[a-z]\d*/gi,
        arabicTagEnclosed: /\{\{(?:عربی|شروع عربی|آغاز عربی)\}\}([\s\S]*?)\{\{(?:پایان عربی)\}\}/g,
        argumentsBlacklist: /(?:accessdate|namespace|image|تصویر|doi|style|شابک|عرض|bibcode|isbn|pmid|arxiv|upright|upleft)\s*\=\s*[^\|\}\]]*/gi,
        color: /#(?:[abcdef0-9]{8}|[abcdef0-9]{6}|[abcdef0-9]{3})/gi,
        //colorAsParameter: /\=\s*(?:[abcdef0-9]{8}|[abcdef0-9]{6}|[abcdef0-9]{3})(?:[\s\|\}]|$)/gi,
        // space, ", \t, \n, {, |, }, ... they will interfere with wiki markup
        decodeUriBlacklist: /(?:%20|%5C|%5E|%60|%23|%25|%3C|%3E|%5B|%5D|%22|%09|%0A|%7B|%7C|%7D)/gi,
        diffLink: /\[\[(?:ویژه|Special):(?:تفاوت|Diff)\/[^\|\]]*/gi,
        englishDate: /\d{1,2},? [a-z]{3,} \d{2,4}/gi, // 3, May 2013
        fileNames: /(?:پرونده|File|تصویر|Image)\:.*?(?=\||\]|\n|$)/gi, // don't capture | after
        fileParameter: /\|\s*(image|تصویر)\s*\=\s*.*/g,
        ipSign: /\[\[ویژه:مشارکت\u200cها.*?\]\]/g,
        isbn: /ISBN [\d\-]*/gi,
        galleryTag: /<gallery.*?>[\s\S]*?<\/gallery>/g,
        htmlAttributes: /(?:style|perrow|colspan|color|rowspan|cellpadding|cellspacing|height|width|size|border|thumbtime|name|perrow|upright|upleft)\s*[\=\:]\s*(?:['\"].*?['\"]|[\da-z]+)/gi,
        htmlEntity: /&#\d+;/,
        imagePixelSize: /[\|=] *[x\d]+?(px|پیکسل)[\]\|\s]/g, // means it will capture |10px| and |10x10px|
        insideQuote: /[^ا]".*?"/g,
        wikilinkTargets: /\[[^\[|\]]+/g,
        nowikiTag:/<nowiki>.+?<\/nowiki>/g,
        preTag:/<pre.*?>.*?<\/pre>/g,
        insideHtmlComment: /<\!\-\-[\s\S]*?\-\->/g,
        linksOnEnglishContext: /[a-z][\:\,\. ]*\[\[[\da-z\-\, ]*/gi,
        mathTag: /<math.*?>[\s\S]*?<\/math>/g,
        otherLanguagesInline: /\{\{(?:به .+?|به انگلیسی|انگلیسی|عربی|حدیث|به عربی)[\s\S]*?\}\}/g,
        parameter: /\{\{\{\d+/gi,
        parenthesesAfterDigits: /\w\s?\([\w\s\.\-]*?\)/g,
        parenthesesHa: /\)ها/g,
        ref: /(?:<ref[^\/]*?>[\s\S]*?<\/ref>|<ref[^\/]*?\/>)/g, // inside <ref></ref> and <ref/>
        citation:/\{\{\s*(?:[Cc]it|یادکرد).*?[_\s]*(?:\{\{.*?\}\}|[^\}])*\}\}/g,
        signatures: /\[\[(?:کاربر|User|بحث[ _]کاربر|User[_ ]talk)\:.*?\]\]/gi,
        sourceTag: /(<source.*?>[\s\S]*?<\/source>|<syntaxhighlight.*?>[\s\S]*?<\/syntaxhighlight>|<code.*?>[\s\S]*?<\/code>|<timeline.*?>[\s\S]*?<\/timeline>)/g,
        tagNames: /<\/?[a-zA-Z\d]*/g,
        templateEnglishName: /(الگو|Template):[a-z][a-z\d\-\+_]+/gi,
        templateParameterName: /\|\s*(?=[a-z_]*\d)[a-z_\d]*\s*\=/gi,
        translatedUrl: /.(کام|نت|آی‌آر)/g,
        url: /\/\/.*?(?=[\s\n\|\}\]<]|$)/gi     // بدون https?: هم ممکن است
    };

    function wikiConvertToPersianCharacters(text) {
        return replaceExcept(
            text,
            persianTools.toStandardPersianCharacters,
            [patterns.otherLanguagesInline, patterns.arabicTagEnclosed, patterns.fileNames, patterns.signatures, patterns.url]
        );
    }

    if (!String.prototype.trim) { // if is not available currently
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }
    function quotation(text) {
        // این تابع زمانی گیومه را به فارسی تیدیل می‌کند که در پاراگراف مورد نظر تعداد گیومهٔ لاتین زوج باشد.
        var lines = text.split(/\n\n/);
        var result = [];
        for (var i = 0; i < lines.length; ++i) {
            var line = lines[i];
            if ((line.match(/"/g) || []).length % 2 === 0) { // count of quote marks
                // تبدیل گیومهٔ لاتین به فارسی
                // این دستور در ابتدا باشد تا فاصله‌های قبل و بعد گیومه هم اصلاح شود
                line = line.replace(
                    new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.\\)]+)"((?:\\[\\[|).*?[' + persianTools.persianCharacters + '؛\\n،]+?(?:\\]\\]|\\.|\\<|\\:|))"([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{\\(]|$)', 'g'),
                    '$1«$2»$3'
                );
                // if some of quote marks are remained from conversion, something might wrong, revert
                if (line.match(/"/g)) {
                    line = lines[i];
                }
            }
            // رفع مشکل استفاده از ـً به جای گیومه لاتین در متن فارسی
            line=line.replace(new RegExp('ا\\"([ ]*[' +persianTools.persianCharacters + '])', 'g'), 'اً$1')
            // ”“ تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)“((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))”([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            //وارونه ”“ تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)”((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))“([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            // ‘’ تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)‘((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))’([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            //وارونه ‘’ تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)’((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))‘([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            // ‚’ تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)‚((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|\\{|\\[|))’([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            // „” تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)„((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))”([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            // << >> تبدیل 
            line = line.replace(
                new RegExp('(^|[' + persianTools.persianCharacters + '\\:>،»؛\\s\\n\\}\\]\\.]+)\\<\\<((?:\\[\\[|).*?[' + persianTools.persianCharacters + '\\n]+?(?:\\]\\]|\\.|\\<|\\:|))\\>\\>([' + persianTools.persianCharacters + '،«؛\\s\\n\\.\\[\\{]|$)', 'g'),
                '$1«$2»$3'
            );
            result.push(line);
        }
        return result.join('\n\n');
    }
    /**
     * افزودن ستون به الگوی پانویس
     * @param {string} text محتوا
    */
    function addColumnToRefTemplate(text) {
        if ((text.match(/<ref>/gi) || []).length >= 6) {
            var refTemplate = /\{{2}پانویس([^\}\{]+)?\}{2}/i.exec(text), needChange = false;
            if (refTemplate) {
                if (refTemplate[1] !== undefined) {
                    var refParams = refTemplate[1].split('|');
                    for (var i = refParams.length - 1; i >= 0; i--) {
                        // اگر از پیش ستون یا پارامتر عرض تعریف شده‌باشد تغییری ایجاد نمی‌شود.
                        if (refParams[i].length == 1 || refParams[i].indexOf('عرض') > -1) {
                            needChange = true;
                            break;
                        }
                    }
                }
                if (refTemplate[1] === undefined || !needChange) {
                    return text.replace(refTemplate[0], refTemplate[0].replace('}}', '|۲}}'));
                }
            }
        }
        
        return text;
    }
    
    /**
     * اصلاح پیوندها
     * @param  {string} text محتوا
     * @return {string}
     */
    function fixBadLinks(text) {
        // حذف متن جایگزین پیوند اگر با نشانی پیوند برابر باشد؛ مانند [[سلام|سلام]]
        text = text.replace(/\[{2}([^\|]+)\|\1\]{2}/gi, '[[$1]]');

        // حذف پیوند سال و روز ماه
        text = text.replace(/\[{2}([۰-۹]+|[۰-۹]+ [\u0621-\u0655\u067E\u0686\u0698\u06AF\u06A9\u0643\u06AA\uFED9\uFEDA\u06CC\uFEF1\uFEF2]+)(?:\|(.+))?\]{2}/g, function (match, p1, p2) {
        // اگر فقط سال پیوند شده‌باشد یا به شکل [[سال|همان سال]] باشد فقط سال را می‌گرداند.
        if (p2 === undefined || p1 === p2) {
            // اگر پیوند به روز و ماه بود، برای جلوگیری از اشتباه و تداخل، بررسی می‌شوند که حتما یکی از ماه‌ها داخل رشته باشد.
            if (p1.indexOf(" ") > -1) {
                var
                    months = ["فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند",
    "ژانویه", "فوریه", "مارس", "آوریل", "مه", "ژوئن", "ژوئیه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "دسامبر",
    "محرم", "صفر", "ربیع‌الاول", "ربیع‌الثانی", "جمادی‌الاول", "جمادی‌الثانی", "رجب", "شعبان", "رمضان", "شوال", "ذیقعده", "ذیحجه"],
                    i;
                for (i = months.length - 1; i >= 0; i--) {
                    if (p1.indexOf(months[i]) > -1) {
                        return p1;
                    }
                }
                return "[[" + p1 + "]]";
            }
            return p1;
        }
        // اگر متن جایگزین پیوند مخالف پیوند سال بود، متن جایگزین را برمی‌گرداند.
        return p2;
    });

    return text;
}

    function wikiPunctuation(text) {
        text = quotation(text);
        if (mw.config.get('wgNamespaceNumber') === 0){
            var old_text=text.replace(/\=\=/g, '')
            if (old_text==text){//در صورتی که در مقاله بخش‌بندی وجود نداشته باشد
                text=text.replace(/(\n\{\{سخ\}\}|\n\n)(\s|_|)\'\'\'(.*?)\'\'\'(\s|_|)(\{\{سخ\}\}|\n)([\n\#\*])/g, '\n\n== $3 ==\n$6')
            }
        }
        text = replaceExcept(
            text,
            function (text) {
                text = text.replace(
                    new RegExp('([' + persianTools.persianCharactersNoVowels + '])ـ+([' + persianTools.persianCharactersNoVowels + '])', 'g'),
                    '$1$2'
                );
                return text.replace(new RegExp('([' + persianTools.persianCharacters + '])(\\]\\]|), (\\[\\[|)?(?=[' + persianTools.persianCharacters + "])", 'g'), '$1$2، $3');
            },
            [patterns.fileNames, patterns.url, patterns.galleryTag, patterns.sourceTag, patterns.translatedUrl, patterns.parenthesesHa]
        );
        text = replaceExcept(
            text,
            function (text) {
                return text.replace(/(<\/ref>)\s+(<ref)/g, '$1$2').replace(/([^=])\s+<ref(?!erences)/g, '$1<ref');
            },
            [/\{\{(پانویس|پانویس‌ها|پی‌نوشت)\s*\|[\s\S]*/]
        );
        return replaceExcept(
            text,
            function (text) {
                return persianTools.punctuation(text)
                    .replace(/^([*#]+)([^*#\:\s])/mg, '$1 $2') // Adds a space after the # or * for lists
                    .replace(/^([*#]+) {2,}([^*#\:\s])/mg, '$1 $2'); // Trim more that one space after the # or * for lists
            },
            [patterns.fileNames, patterns.url, patterns.wikilinkTargets, patterns.galleryTag, patterns.sourceTag, patterns.translatedUrl, patterns.parenthesesHa]
        )
            .replace(/\u00A0/g, ' ') // convert implicit nbsp to space, probably is being added by some bug on ContentTranslation
            .replace(/٬ /g, '، ')
            .replace(new RegExp('([' + persianTools.persianCharacters + '\]])٬', 'g'), '$1،')
            .replace(new RegExp('([' + persianTools.persianCharacters + '])(\]\]|»|)[ ]*[,]', 'g'), '$1$2، ')
            .replace(/\[\[(رده|الگو|ویکی\u200cپدیا)\: +/g, '[[$1:')
            .replace(/[\n\s]*\{\{[•·ن](w?)\}\}\s*/g, '{{•$1}} ')
            .replace(/\=\{\{[•·ن](w?)\}\}\s*/g, '=\n{{•$1}} ')//رفع باگ [[Special:Diff/14799178/16387261]] در خط بالا 
            .replace(/ *(<\/? ?br ?\/?>|\{\{بر\}\}) */g, '{{سخ}}')
            .replace(/\{\{سخ\}\}\n\n/g, '\n\n')
            .replace(/\n\n\{\{سخ\}\}/g, '\n\n')
            .replace(/\n\n(\*|\#)/g,'\n$1')
            .replace(/\n(\#|\*)( |)\n/g,'\n$1')
            .replace(/\n(\*|\#)( |)(\={2,})/g,'\n$3')
            .replace(/(\n?)\s+?<\/ref>/g, '$1</ref>')
            .replace(/([^=])\n+(\=.*?\=\n+)/g, '$1\n\n$2')
            .replace(/^(=+([^=].*?)=+)[\t\s]{1,}\n/g, '$1\n')
            .replace(/^(\={2,}) +[\:,;>&\^#@•→←↔↑↓—–…~٫،؛ٔ]/mg, '$1') // Cleanup headers
            .replace(/[\:,;<&\^#@•→←↔↑↓—–…~٫،؛ٔ] +(\={2,})$/mg, '$1')
            .replace(/^(\={2,}\s*)(«)([^\n«»]*?)(»)(\s*\={2,})/mg, '$1 $3 $5')
            .replace(/^(\={2,}) *'+(.*?)'+ *(\={2,})/mg, '$1 $2 $3')
            .replace(/^[•●⚫⬤]/mg, '*') // Wikify bullets in start of lines
            .replace(/^#\s*(REDIRECT|تغییر[ _]?مسیر)/gi, '#تغییرمسیر')
            .replace(/^#تغییرمسیر(?=\S)/g, '#تغییرمسیر ') // Adds a space after #REDIRECT
            .replace(/(\={2,}) *([^\n\r]*?) *(\={2,})/g, '$1 $2 $3') // Format headings level 2 and above
            // فاصله‌های اضافی را از داخل پیوند به بیرون منتقل کند تا اگر اضافه بودند در کدهای دیگر حذف شوند
            .replace(/\[\[(\s*)(.*?)(\s*)\]\]/g, '$1[[$2]]$3')
//حذف فاصلهٔ اضافی درون {{}}
            .replace(/\{\{(\s*)(.*?)(\s*)\}\}/g, '{{$2}}')
            // تبدیل به نویسه / یکی کردن فاصله های مجازی پشت سرهم
            .replace(/(\{\{فم\}\}|\&zwnj\;|\u200c+)/g, '\u200c')
            // Full stop and comma should be before citation. See en:WP:REFPUNC
            .replace(/ *((?:<ref[^\/]*?>.*?<\/ref>)+)([\.،,:])?/g, '$2$1')
            .replace(/([^.])([\.،,:]){2}((?:<ref[^\/]*?>.*?<\/ref>)+)/g, '$1$2$3')
            .replace(/ *((?:<ref[^\/]*?\/>)+)([\.،,:])/g, '$2$1')
            .replace(/([^.])([\.،,:]){2}(((?:<ref[^\/]*?\/>)+)+)/g, '$1$2$3')
            .replace(/\{\{(?:DEFAULTSORT|[Dd]efaultsort|ترتیب|ترتیب[‌ ]پیش[‌ ]?فرض) *[|:] *(?=.*?}})/g, '{{ترتیب‌پیش‌فرض:')
            .replace(/\{\{(ترتیب‌پیش‌فرض|DEFAULTSORT)\:[-\w,\s\(\)]+\}\}\n?/g, '')
            .replace(/(\{\{ترتیب‌پیش‌فرض\:)\s/g, '$1')
            //نچسبیدن و+فاصله به براکت که محصول اشتباه در تایپ کردن است
            .replace(']]و ', ']] و ')
            .replace(/(\s|^)\'\'\'(\s|)(.*?)(\s|)\'\'\'(\s)/g, "$1'''$3'''$5") // حذف فاصلهٔ اضافی درون ویکی کد
            .replace(/'''\{\{به /g, "''' {{به ")
            .replace(/\*(\s+|\n)?\{\{پانویس/g, "{{پانویس")
            .replace(/((?:^|\n\s)\=+\s+\=+(?:\s+|)\n)/g, "\n\n")
            .replace(/\n{3,}/g, '\n\n')
            .trim();
    }

    function wikiSubsection(text) {
        return text.replace(/\<(?:\s*)references?(?:\s*\/|\s*\/\s*)\>/g, '{{پانویس}}')
               .replace(/\{\{(?:[Rr]eflist|[Rr]eferences?|پانویس[‌ ]?ها)(?=\||\})/g, '{{پانویس')
               .replace(/\{\{راست(| |‌)چین\}\}\s*\{\{پانویس(.*?)\}\}\s*\{\{(پایان راست(| |‌)چین|پایان)\}\}/g, '{{پانویس$2}}')
               .replace(/\{\{چپ(| |‌)چین\}\}\s*\{\{پانویس(.*?)\}\}\s*\{\{(پایان چپ(| |‌)چین|پایان)\}\}/g, '{{پانویس$2|چپ‌چین=بله}}')
               .replace(/\<small\>\s*\{\{پانویس(.*?)\}\}\s*\<\/small\>/g, '{{پانویس$1|اندازه=کوچک}}')
               .replace(/\=\s*لیست\s*\=/g, '= فهرست =')
               .replace(/\=\s*(?:[gG]allery|نگارستان|گالری (تصویر|عکس|))\s*\=/g, '= نگارخانه =')
               .replace(/\=\s*(?:بیوگرافی|زندگینامه)\s*\=/g, '= زندگی‌نامه =')
               .replace(/\=\s*(?:[eE]xternal links|لینک‌?های بیرونی|پیوندهای خارجی|لینک‌?های خارجی|پیوندهای بیرونی)\s*\=/g, '= پیوند به بیرون =')
               .replace(/\=\s*(?:[nN]otes|[fF]ootnotes?|پاورقی|پاورقی‌ها|پانویس‌ها)\s*\=/g, '= پانویس =')
               .replace(/\=\s*(?:[Ss]ee [Aa]lso|همچنین ببینید|بیشتر ببینید|بیشتر بخوانید|همچنین نگاه کنید|بیشتر بدانید|مراجعات مرتبط|جستار وابسته|مطلب مرتبط|مطالب مرتبط|مطالعه بیشتر|جستارهای مشابه)\s*\=/g, '= جستارهای وابسته =')
               .replace(/\=\s*(?:منبع|منبع[‌ ]?ها|رفرنس|رفرنس[‌ ]?ها|ارجاع[‌ ]?ها|ارجاع|مرجع[‌ ]?ها|رفرنس|برگرفته از|مراجع|منابع و یادداشت[‌ ]?ها|منبع|مرجع|ماخذ|منابع و ماخذ|منابع و پانویس‌ها|فهرست مراجع|لیست مراجع|فهرست ارجاع[‌ ]?ها|فهرست ارجاع|[rR]eferences)\s*\=/g, '= منابع =');
    }
    function wikiUrlMinifier(text) {
        return text
            .replace(patterns.url, function (x) {
                return replaceExcept(
                    x,
                    function (x) {
                        try {
                            x = decodeURI(x);
                        } catch (e) { mw.notify(e); }
                        return x;
                    },
                    [patterns.decodeUriBlacklist]
                );
            })

            // Strip the http(s) prefix
            .replace(/\[(https?\:)(?=\/\/(?:[\w\-]+)\.(wiki(pedia|media|data|source|news|oyage|quote)|wiktionary)\.org\/[^\s\]]*)/g, '[');
    }

    function wikiTextDigitsToPersian(text) {
        text = replaceExcept(
            text,
            persianTools.toEnglishDigits,
            [patterns.argumentsBlacklist,patterns.fileNames,patterns.fileParameter]);
        text = replaceExcept(
            text,
            persianTools.toPersianDigits,
            [patterns.url, patterns.argumentsBlacklist, patterns.mathTag, patterns.imagePixelSize, patterns.fileNames, patterns.ref,
                patterns.sourceTag, patterns.arabicDigitsEnglishContext, patterns.signatures, patterns.htmlEntity, patterns.diffLink,
                patterns.htmlAttributes, patterns.fileParameter, patterns.templateParameterName, patterns.ipSign,
                patterns.parenthesesAfterDigits, patterns.otherLanguagesInline, patterns.isbn, patterns.englishDate,
                patterns.parameter, patterns.color, patterns.templateEnglishName, patterns.linksOnEnglishContext, patterns.citation]
        );
        return text
            // Decimal point, and thousands' separator
            .replace(/([۱۲۳۴۵۶۷۸۹۰])\.([۱۲۳۴۵۶۷۸۹۰])/g, '$1٫$2')
            .replace(/([۱۲۳۴۵۶۷۸۹۰]),([۱۲۳۴۵۶۷۸۹۰])/g, '$1٬$2')
            .replace(/([۱۲۳۴۵۶۷۸۹۰])( |)\u0652/g, '$1°')//تبدیل نویسه سکون+عدد فارسی به نویسه درجه و عدد فارسی
            .replace(/\u0652( |)([۱۲۳۴۵۶۷۸۹۰])/g, '°$2')
            //فاصله بین نویسه درجه و حروف الفبای فارسی به جز عدد فارسی
            .replace(/([\u0621-\u064A\u0653-\u0655\u067E\u0686\u0698\u06AF\u06A9\u0643\u06AA\uFED9\uFEDA\u06CC\uFEF1\uFEF2])°/g, '$1 °');
    }

    function dictationReplace(x, y, extensions, text) {
        return text.replace(
            new RegExp(
                '(^|[^' + persianTools.persianCharacters + '])(\\s|\u200c|_|)(' + x + ')(\\s|_)(' + y + ')(\\s|\u200c|_|)(' +
                    extensions + ')($|[^' + persianTools.persianCharacters + '])',
                'g'
            ),
            '$1$2$3\u200c$5$6$7$8'
        );
    }

    // it has dependency to MediaWiki:Gadget-Extra-Editbuttons-Dictionary.js
    function dictation(text) {
        var i,
            dictionary = persianToolsDictionary,
            NASB = '\u064b', // ًـ
            ZAMM = '\u064c'; // ُـ
        for (i in dictionary.complexes) {
            if (dictionary.complexes.hasOwnProperty(i)) {
                text = dictationReplace(
                    i,
                    dictionary.complexes[i],
                    'ی|یی|ها|های|هایی|هایم|هایت|هایش|هایمان|هایتان|هایشان|',
                    text
                );
            }
        }
        // for last name
        text = dictationReplace(
            dictionary.personNames,
            'ی|یی|زاده|نیا|گان|فر|نژاد|یان|ی\u200cها|یها',
            'ی|',
            text
        );
        // for 'آباد's
        text = dictationReplace(
            dictionary.personNames + '|' + dictionary.addToAbad,
            'آباد',
            'زاده|نیا|پور|گان|فر|نژاد|ی|یان|ها|های|یی|هایی|ی\u200cها|یها|',
            text
        );
        // for first names
        for (i in dictionary.firstNameComplex) {
            if (dictionary.firstNameComplex.hasOwnProperty(i)) {
                text = text.replace(
                    new RegExp(
                        '(^|[^' + persianTools.persianCharacters + ']|\\s|_)(' + i + ')(\\s|_)(' +
                            dictionary.firstNameComplex[i] + ')(\\s|_)($|[^' + persianTools.persianCharacters + ']|[^' +
                            persianTools.persianCharacters + '])',
                        'g'
                    ),
                    '$1$2\u200c$4$5$6'
                );
            }
        }
        // for colors
        text = dictationReplace(
            dictionary.colorsNames,
            'فام|گون',
            'زاده|نیا|پور|گان|فر|نژاد|ی|یی|ها|های|هایی|ی\u200cها|یها|هایم|هایت|هایش|هایمان|هایتان|هایشان|',
            text
        );
        // for numbers
        text = dictationReplace(
            dictionary.persianNumbers,
            'گانه|ماهه',
            'زاده|نیا|پور|گان|فر|نژاد|ی|یی|ها|های|هایی|هایم|هایت|هایش|هایمان|هایتان|هایشان|',
            text
        );
        // wrong dictation
        for (i in dictionary.forReplace) {
            if (dictionary.forReplace.hasOwnProperty(i)) {
                text = text.replace(
                    new RegExp(
                        '(^|[^' + persianTools.persianCharacters + '])(\\s|\u200c|_|)(' + i + ')(\\s|\u200c|_|)($|[^' +
                            persianTools.persianCharacters + '])',
                        'g'
                    ),
                    '$1$2' + dictionary.forReplace[i] + '$4$5'
                );
            }
        }

        // کلماتی که آ دارند
        text = text.replace(
            new RegExp("(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.wordsWithA + ")(ی|ئی|یی|ٔ|)(?= |«|»|\\.|،|_|\\]|\\s|\\:|\\)|\\<|\\>|؟|\\'|\\!|$)", 'g'),
            function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view
        );
        // بن مضارع که آ دارند
        text = text.replace(
            new RegExp("(^|\u200c|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.PresentVerbsWithA + ")(م|ی|د|یم|ید|ند)(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),
            function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view
        );

        // بن ماضی که آ دارند
        text = text.replace(
            new RegExp("(^|\u200c|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.PastVerbsWithA + ")(م|ی|یم|ید|ند|ه|)(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),
            function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view
        );

        // همزه ضم
        text = text.replace(
            new RegExp("(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.HamzehZam + ")(‌ها|ها|ین|ان|ی|ئی|یی|ٔ|)(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),
            function (x) { return x.replace(/وء/, 'ؤ').replace(/و/i, 'ؤ'); } // 'i' is just to trick bidi algorithm on code view
        );
        //همزه نصب
        text = text.replace(
            new RegExp("(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.HamzehNasb + ")(ی|ئی|یی|ٔ|)(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),
            function (x) { return x.replace(/ا/i, 'أ'); } // 'i' is just to trick bidi algorithm on code view
        );

        //همزه وسط کلمه
        for (i in dictionary.HamzehAtInside) {
            text = text.replace(new RegExp(
                "(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + i + ')(| )(' + dictionary.HamzehAtInside[i] + ")(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)",
                'g'
            ), '$1$2ء$4');
        }


        //همزه انتها
        text = text.replace(new RegExp("(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.HamzehAtEnd + ")(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),'$1$2ء');

        //الف مقصوره
        text = text.replace(
            new RegExp("(^|\\s|_|«|»|\\[|\\(|\\<|\\>|\\')(" + dictionary.AlefMaghsooreh + ")(?= |«|»|\\.|،|_|\\s|\\]|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),
            function (x) { return x.replace(/ا/i, 'ی'); } // 'i' is just to trick bidi algorithm on code view
        );

        // صفت+تر
        text = text.replace(new RegExp("(^|\\s|_|«|»|\\]|\\[|\\(|\\<|\\>|\\')(" + dictionary.adjective + ")( |_)تر(?= |«|»|\\.|\\[|\\]|،|_|\\s|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),'$1$2\u200cتر');
        
        // اسامی رنگ‌ها (به‌عنوان صفت)+تر
        text = text.replace(new RegExp("(^|\\s|_|«|»|\\]|\\[|\\(|\\<|\\>|\\')(" + dictionary.colorsNames + ")( |_)تر(?= |«|»|\\.|\\[|\\]|،|_|\\s|\\:|\\)|\\<|\\>|؟|\\!|\\'|$)", 'g'),'$1$2\u200cتر');
        
        text = text.replace(/به دست\u200cآورد/g, 'به دست آورد'); // Solving a bug!
        text = persianTools.normalizeZwnj(text);
        return text.replace(new RegExp("(^|[؛\\s\\n\\.،«»\'\\<\\>؟])(" + dictionary.needsNasb + ')[' + NASB + ZAMM + ']?([؛؟\\s\\n\\.،«»\'"\\<\\>]|$)', 'g'), function (match) {
            return match
                .replace(new RegExp('ا([\\s\\n\\.،«»؟؛"\'\\>\\<' + ZAMM + '])', 'i'), 'ا' + NASB + '$1')
                .replace(new RegExp(NASB + '["' + NASB + ZAMM + ']'), NASB);
        });
    }

    function wikiDictation(text) {
        return replaceExcept(
            text,
            dictation,
            [patterns.fileNames, patterns.signatures, patterns.url, patterns.galleryTag, patterns.insideQuote, patterns.argumentsBlacklist]
        );
    }
    function wikiApplyOrthography(text) {
        //حذف برچسب‌های خالی نرم‌افزار مدیاویکی
        var tags = ['math', 'code', 'nowiki', 'pre', 'source', 's', 'su[bp]', 'noinclude', 'includeonly', 'ref', 'big', 'small'];
        text = replaceExcept(
          text,
          function (text) {
            for (var i = 0; i < tags.length; ++i) {
              text = text.replace(new RegExp('\<' + tags[i] + '[^\>]*\>(\\n|\\s|\u200c)*?\<\\/' + tags[i] + '\>', 'g'), '');
              // remove the tags if they occurred multiple times consequently
              if (mw.config.get('wgNamespaceNumber') === 0 || mw.config.get('wgNamespaceNumber') === 4) {
                text = text.replace(new RegExp('(\<' + tags[i] + '\>){2,}', 'g'), '$1')
                  .replace(new RegExp('(\<\\/' + tags[i] + '\>){2,}', 'g'), '$1');
              }
            }
            return text;
          },
          [patterns.insideHtmlComment]
        );
        return replaceExcept(
            text,
            persianTools.applyOrthography,
            [patterns.fileNames, patterns.signatures, patterns.url, patterns.galleryTag, patterns.wikilinkTargets]
        ).replace(patterns.galleryTag, function (gallery) {
            // apply `applyOrthography` on gallery descriptions separately
            return gallery.replace(/^([^\|]*?\|)(.*)$/mg, function (x, y, z) {
                return y + persianTools.applyOrthography(z);
            });
        });
    }
    
    // probably should be exactly same above but for applyZwnj
    function wikiApplyZwnj(text) {
        return replaceExcept(
            text,
            persianTools.applyZwnj,
            [patterns.fileNames, patterns.signatures, patterns.url, patterns.galleryTag]
        ).replace(patterns.galleryTag, function (gallery) {
            // apply `applyOrthography` on gallery descriptions separatly
            return gallery.replace(/^([^\|]*?\|)(.*)$/mg, function (x, y, z) {
                return y + persianTools.applyZwnj(z);
            });
        });
    }

    function replaceEnMonth(text) {
        var enMonth = {
            'آگست':'اوت',
            'آگوست':'اوت',
            'جولای':'ژوئیه',
            'مارچ':'مارس',
            'آپریل':'آوریل',
            'فوریوری':'فوریه',
            'january': 'ژانویه',
            'jan': 'ژانویه',
            'february': 'فوریه',
            'feb': 'فوریه',
            'march': 'مارس',
            'mar': 'مارس',
            'april': 'آوریل',
            'apr': 'آوریل',
            'may': 'مه',
            'june': 'ژوئن',
            'jun': 'ژوئن',
            'july': 'ژوئیه',
            'august': 'اوت',
            'aug': 'اوت',
            'september': 'سپتامبر',
            'sept': 'سپتامبر',
            'sep': 'سپتامبر',
            'october': 'اکتبر',
            'oct': 'اکتبر',
            'november': 'نوامبر',
            'nov': 'نوامبر',
            'december': 'دسامبر',
            'dec': 'دسامبر'
        };
        for (var i in enMonth) {
            var text_new = text.replace(new RegExp(i, 'ig'), enMonth[i])
            if (text_new != text) {
                return text_new
            }
        }
        return text
    };

    function wikitranslateEnMonth(text) {
        return replaceExcept(
            text,
            function translateEnMonth(text) {
                var enMonthRegex = '(آگست|آگوست|جولای|مارچ|آپریل|january|jan|february|feb|march|mar|april|apr|may|jun|june|july|august|aug|sep|sept|september|oct|october|nov|november|december|dec)';
                return text.replace(new RegExp('([^a-zA-Z])(\^|\\||\\s|\\=|\\n|\\(|«|\\:)' + enMonthRegex + ' (\\d{1,2}|[۱۲۳۴۵۶۷۸۹۰]{1,2})\\, (\\d{3,4}|[۱۲۳۴۵۶۷۸۹۰]{3,4})(\\||\\s|\\n|\$|\\)|\\}|»)([\^a\-zA\-Z])', 'ig'),
                        function (x) {
                            x=x.replace(new RegExp('([\^a\-zA\-Z])(\^|\\||\\s|\\=|\\n|\\(|«|\\:)' + enMonthRegex + ' (\\d{1,2}|[۱۲۳۴۵۶۷۸۹۰]{1,2})\\, (\\d{3,4}|[۱۲۳۴۵۶۷۸۹۰]{3,4})(\\||\\s|\\n|\$|\\)|\\}||»)([^a-zA-Z])', 'ig'),
                            '$1$2$4 $3 $5$6$7')
                            x = persianTools.toPersianDigits(x);
                            x = replaceEnMonth(x);
                            return x;
                        })
                    .replace(new RegExp('([\^a\-zA\-Z])(\^|\\||\\s|\\=|\\n|\\(|«)((\\d{1,2}|[۱۲۳۴۵۶۷۸۹۰]{1,2}) |)' + enMonthRegex + ' (\\d{3,4}|[۱۲۳۴۵۶۷۸۹۰]{3,4})(\\||\\s|\\n|$|\\)|\\}|»|\\:)([\^a\-zA\-Z])', 'ig'),
                        function(x) {
                            x = persianTools.toPersianDigits(x);
                            x = replaceEnMonth(x);
                            return x;
                        }
                    );
            }, [patterns.fileNames, patterns.ref, patterns.fileParameter, patterns.galleryTag, patterns.mathTag, patterns.sourceTag, patterns.citation]
        )
    };
    function superTool(text) {
        text = persianWikiTools.wikiConvertToPersianCharacters(text);
        text = persianWikiTools.wikiApplyZwnj(text);
        text = persianWikiTools.wikiApplyOrthography(text);
        if (mw.config.get('wgNamespaceNumber') !== 10) {
            text = persianWikiTools.wikiTextDigitsToPersian(text);
        }
        text = persianWikiTools.wikiUrlMinifier(text);
        text = persianWikiTools.wikiDictation(text);
        text = persianWikiTools.wikiPunctuation(text);
        text = persianWikiTools.wikiSubsection(text);
        text = persianWikiTools.wikitranslateEnMonth(text);
        //ابزارهای بیشتر برگرفته از ویکی‌پدیای انگلیسی [[Mediawiki:Gadget-Extra-Editbuttons-autoed.js]]
        text = autoEd.autoEdISBN(text);
        text = autoEd.autoEdWhitespace(text);
        text = autoEd.autoEdHTMLtoWikitext(text);
        text = autoEd.autoEdHeadlines(text);
        // text = autoEd.autoEdTemplates(text);
        text = autoEd.autoEdTablestoWikitext(text);
        text = autoEd.autoEdExtraBreaks(text);
        text = persianWikiTools.addColumnToRefTemplate(text);
        return text;
    }
    
    function superToolMove(text) {
        text = persianWikiTools.wikiConvertToPersianCharacters(text);
        text = persianTools.applyZwnj(text);
        text = persianWikiTools.wikiApplyOrthography(text);
        text = persianWikiTools.wikiTextDigitsToPersian(text);
        text = persianWikiTools.wikiUrlMinifier(text);
        text = persianWikiTools.wikiDictation(text);
        text = persianWikiTools.wikiPunctuation(text);
        return text;
    }

    return {
        superTool: superTool,
        superToolMove: superToolMove,
        dictation: dictation,
        wikiApplyOrthography: wikiApplyOrthography,
        wikiApplyZwnj: wikiApplyZwnj,
        wikiConvertToPersianCharacters: wikiConvertToPersianCharacters,
        wikiDictation: wikiDictation,
        wikiPunctuation: wikiPunctuation,
        wikiSubsection:wikiSubsection,
        wikiUrlMinifier: wikiUrlMinifier,
        wikiTextDigitsToPersian: wikiTextDigitsToPersian,
        wikitranslateEnMonth: wikitranslateEnMonth,
        addColumnToRefTemplate: addColumnToRefTemplate,
        fixBadLinks: fixBadLinks,
    };
}());
if (typeof window !== "undefined") {
    window.persianWikiTools = persianWikiTools;
}