مدیاویکی:Gadget-Extra-Editbuttons-persianwikitools.js
از بنیاد دانش آزاد
نکته: پس از ذخیرهکردن ممکن است برای دیدن تغییرات نیاز باشد که حافظهٔ نهانی مرورگر خود را پاک کنید.
- فایرفاکس / سافاری: کلید 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|doi|style|شابک|عرض|bibcode|isbn|pmid|arxiv)\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, 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|colspan|color|rowspan|cellpadding|cellspacing|height|width|size|border|thumbtime|name|perrow)\s*[\=\:]\s*(?:['\"].*?['\"]|[\da-z]+)/gi, htmlEntity: /&#\d+;/, imagePixelSize: /[\|=] *[x\d]+?(px|پیکسل)[\]\|\s]/g, // means it will capture |10px| and |10x10px| insideQuote: /[^ا]".*?"/g, wikilinkTargets: /\[[^\[|\]]+/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/> 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 + '،»؛\\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); var needChange = false; if (typeof 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 (typeof 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); 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] ); 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(/\n{3,}/g, '\n\n') // Cosmetic changes bot replaces .replace(/\[\[(رده|الگو|ویکی\u200cپدیا)\: +/g, '[[$1:') .replace(/[\n\s]*\{\{[•·ن](w?)\}\}\s*/g, '{{•$1}} ') .replace(/ *(<\/? ?br ?\/?>|\{\{بر\}\}) */g, '{{سخ}}') .replace(/(<\/ref>)\s+(<ref)/g, '$1$2') .replace(/([^=])[\s\n]+<ref(?!erences)/g, '$1<ref') .replace(/(\n?)[\s\n]+?<\/ref>/g, '$1</ref>') .replace(/([^=])\n+(\=.*?\=\n+)/g, '$1\n\n$2') .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(/(\{\{فم\}\}|\&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(']]و ', ']] و ') .trim(); } 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.toPersianDigits, [patterns.url, patterns.argumentsBlacklist, patterns.mathTag, patterns.imagePixelSize, patterns.fileNames, patterns.ref, patterns.sourceTag, patterns.arabicDigitsEnglishContext, patterns.signatures, patterns.htmlEntity, 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.colorAsParameter, patterns.tagNames] ); return text // Decimal point, and thousands' separator .replace(/([۱۲۳۴۵۶۷۸۹۰])\.([۱۲۳۴۵۶۷۸۹۰])/g, '$1٫$2') .replace(/([۱۲۳۴۵۶۷۸۹۰]),([۱۲۳۴۵۶۷۸۹۰])/g, '$1٬$2'); } 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'; // ًـ 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('(^| |_|«|»)(' + dictionary.wordsWithA + ')(ی|ئی|یی|ٔ|)(?= |«|»|\\.|،|_|$)', 'g'), function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view ); // بن مضارع که آ دارند text = text.replace( new RegExp('(^|\u200c| |_|«|»)(' + dictionary.PresentVerbsWithA + ')(م|ی|د|یم|ید|ند)(?= |«|»|\\.|،|_|$)', 'g'), function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view ); // بن ماضی که آ دارند text = text.replace( new RegExp('(^|\u200c| |_|«|»)(' + dictionary.PastVerbsWithA + ')(م|ی|یم|ید|ند|ه|)(?= |«|»|\\.|،|_|$)', 'g'), function (x) { return x.replace(/ا/i, 'آ'); } // 'i' is just to trick bidi algorithm on code view ); // صفت+تر text = text.replace( new RegExp('(^| |_|«|»|\\]|\\[)(' + dictionary.adjective + ')( |_)تر(?= |«|»|\\.|\\[|\\]|،|_|\\:|$)', 'g'), '$1$2\u200cتر'); // اسامی رنگها (بهعنوان صفت)+تر text = text.replace( new RegExp('(^| |_|«|»|\\]|\\[)(' + dictionary.colorsNames + ')( |_)تر(?= |«|»|\\.|\\[|\\]|،|_|\\:|$)', '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 + ')([\\s\\n\\.،«»؛"])' + NASB + '?', 'g'), function (match) { return match.replace(/ا([\s\n\.،«»؛"])/i, 'ا' + NASB + '$1').replace(new RegExp(NASB + '["' + NASB + ']'), NASB); }); } function wikiDictation(text) { return replaceExcept( text, dictation, [patterns.fileNames, patterns.signatures, patterns.url, patterns.galleryTag, patterns.insideQuote] ); } function wikiApplyOrthography(text) { return replaceExcept( text, persianTools.applyOrthography, [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.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 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); //ابزارهای بیشتر برگرفته از ویکیپدیای انگلیسی [[Mediawiki:Gadget-Extra-Editbuttons-autoed.js]] text = autoEd.autoEdISBN(text); text = autoEd.autoEdWhitespace(text); // text = autoEd.autoEdWikilinks(text); text = autoEd.autoEdHTMLtoWikitext(text); text = autoEd.autoEdHeadlines(text); // text = autoEd.autoEdTemplates(text); text = autoEd.autoEdTablestoWikitext(text); text = autoEd.autoEdExtraBreaks(text); // text = autoEd.autoEdLinks(text); text = persianWikiTools.addColumnToRefTemplate(text); text = persianWikiTools.fixBadLinks(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, wikiUrlMinifier: wikiUrlMinifier, wikiTextDigitsToPersian: wikiTextDigitsToPersian, addColumnToRefTemplate: addColumnToRefTemplate, fixBadLinks: fixBadLinks, }; }()); if (typeof window !== "undefined") { window.persianWikiTools = persianWikiTools; }