مدیاویکی:Gadget-CheckDictation.js

از پژوهشکده امر به معروف
پرش به: ناوبری، جستجو

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

  • فایرفاکس / سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload کلیک کنید، یا کلید‌های Ctrl-F5 یا Ctrl-R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-R)
  • گوگل کروم: کلیدهای Ctrl+Shift+R را با هم فشار دهید (در رایانه‌های اپل مکینتاش کلید‌های ⌘-Shift-R)
  • اینترنت اکسپلورر: کلید Ctrl را نگه‌دارید و روی دکمهٔ Refresh کلیک کنید، یا کلید‌های Ctrl-F5 را با هم فشار دهید
  • اپرا: حافظهٔ نهانی مرورگر را از طریق منوی Tools → Preferences پاک کنید
$(function () {
    if (['view', 'edit'].indexOf(mw.config.get('wgAction')) === -1) {
        return;
    }
    if ([0, 12].indexOf(mw.config.get('wgNamespaceNumber')) === -1) {
        return;
    }
    if (mw.util.getParamValue('diff') || mw.util.getParamValue('oldid')) {
        return;
    }
    if ($('.noarticletext').length) {
        return;
    }

    mw.util.addCSS('#dictationform * { font-family: inherit; } #dictationform { font-size: 105% }');

    $.getJSON('//tools.wmflabs.org/checkdictation-fa/check/' + mw.config.get('wgPageName')).then(function (result) {
        if (!Array.isArray(result.result)) {
            console.log(result.error);
            return;
        }
        var issues = result.result;
        if (issues.length === 0) {
            console.log('ابزار اشتباه‌یاب اشکالی در صفحه پیدا نکرد.');
            mw.notify('ابزار اشتباه‌یاب اشکالی در صفحه پیدا نکرد.');
            return;
        }

        var availableTypes = {};
        issues.forEach(function (x) {
            availableTypes[x.type] = true;
        });
        var types = result.types,
            legend;

        legend = Object.keys(types).filter(function (x) {
            return availableTypes[x];
        }).map(function (x) {
            var type = types[x];
            return [
                $('<div>').css({ width: '12px', height: '12px', display: 'inline-block', 'background-color': type.color }),
                ' ',
                $('<span>', { text: type.title }).css({ 'font-size': '10pt' })
            ];
        }).reduce(function (x, y) {
            return x.concat('، ', y);
        });

        $('#checkdictation-tool').remove();

        $('h1:first').after($('<div>', {
            id: 'checkdictation-tool'
        }).css({
            border: '2px solid #b3000b',
            padding: '1em',
            'background-color': '#fefce3',
            'margin-bottom': '8px',
            'border-radius': '15px'
        }).append(
            $('<big>', {
                text: issues.length.toLocaleString('fa') + ' مورد مشکوک به اشتباه نوشتاری یا شیوه‌نامه‌ای یافت شد!'
            }).css('font-style', 'italic'),
            ' (',
            legend,
            ')',
            $('<div>', { id: 'spellmarkedwords', text: 'موارد مشکوک به اشتباه: ' }),
            '<br><br>',
            $('<div>', { id: 'checkdictation-button-place'}),
            [
                'نکتهٔ ۱: بعضی از این موارد، فقط در حالت ویرایش دیده‌ می‌شوند!',
                'نکتهٔ ۲: با کلیک کردن بر روی کلمات در بالا، بدون رفتن به پنجرهٔ ویرایش به صورت خودکار می‌توانید کلمهٔ درست را جایگزین کنید.',
                'نکتهٔ ۳: می‌توانید چند مورد را پشت سر هم با کلیک انتخاب کنید و با زدن دکمه‌ای که ظاهر می‌شود همهٔ آنها را در یک ویرایش جایگزین کنید.'
            ].map(function (x) { return $('<div>', { text: x }).css('font-size', '8pt'); })
        ));
        $('<button>', { text: 'همهٔ موارد درست است!', style: 'margin-right: 2em', id: 'checkdictation-close' }).click(function () {
            SetCorrectWord()
            mw.notify('همهٔ موارد به عنوان درست درنظر گرفته شد. این موارد برای شما تا زمانی که کوکی مروگرتان خالی نشده‌است نمایش داده نمی‌شوند.' , { autoHide: false });
            }).appendTo('#checkdictation-button-place');
        var arabic_diacritics="ًٌٍَُِّْٔ"
        var main_regex = '\[؛؟\\s\\n\\r\\•●⚫⬤\\„\\”\\‚\\’\\‘\\“\\[\\]\\{\\}\\t\\<\\>\\.\\,\\"' + "\\'\\+\\!\\?\\-\\»«،\\:\\|\\(\\)\]";
        var start_regex = '\(\^\|' + main_regex + '\)';
        var end_regex = '\(\$\|['+arabic_diacritics+']*' + main_regex + '\)';
        var articleBody = $('#bodyContent, #article')[0];

        var replacements = [];
        var markedItems = [];
        var ChDicCorrectWordList=getCookie('ChDicCorrectWord').split(',');
        issues.forEach(function (item, i) {
            var word = item.word,
                type = types[item.type],
                suggestions = item.suggestions.sort(),
                cleanedWord = item.cleaned_word,
                regexp, preparedId;
            if (ChDicCorrectWordList.indexOf(word)>-1||ChDicCorrectWordList.indexOf(' '+word)>-1){return;}
            if (i !== 0) {
                markedItems.push('، ');
            }
            regexp = new RegExp(type.syntax ?
                regexpEscape(word) :
                (start_regex + '(' +
                    word.substring(0, word.length - 1).replace(/[ء-يٓ-ٕپچژگکكڪﻙﻚیﻱﻲكﮑﮐﮏﮎﻜﻛﻚﻙىﻯيہەھﻰ-ﻴ]/g, '$&\[ً-ِْٰٔ\]\*') +word.slice(-1)+
                    ')' + end_regex), 'g');
            preparedId = 'tool-' + encodeURI(word).replace(/%/g, '.');
            markWord(articleBody, regexp, word, suggestions[0] || type.hint, type.color, preparedId);
            var element = $('<span>', {
                style: 'background-color: ' + type.color,
                text: word,
                title: suggestions[0] || type.hint
            });
            element.css('cursor', 'pointer');
            element.click(function () {
                if (!type.autofix) {
                    location.hash = preparedId;
                    return;
                }
                dictationReplaceDialog(
                    ('«' + word + '» را می‌خواهید با چه چیزی جایگرین کنید؟'),
                    word,
                    suggestions
                ).then(function (toWord) {
                    var changeSummary = word + '⟸' + toWord;
                    element.css('background-color', '').css('color', 'grey').text(changeSummary).off();
                    toWord = toWord.replace(/\200c /g, ' ').replace(/ \200c/g, ' ');
                    if (mw.config.get('wgAction') === 'edit') {
                        $('#wpTextbox1').val($('#wpTextbox1').val().replace(regexp, '$1' + toWord + '$3'));
                    } else {
                        replacements.push([regexp, '$1' + toWord + '$3', changeSummary]);
                        $('#checkdictation-apply').show();
                    }
                }, function () {
                    if (/[كڪﻙﻚيىےۍېہەھﭖﭗﭘﭙﭺﭻﭼﭽﮊﮋﮎﮏﮐﮑﻙﻚﻛﻜﮒﮓﮔﮕﮤﮥﯼﯽﯾﯿﻯﻰﻱﻲﻳﻴﺁﺂﺄﺃﺅﺆﺇﺈﺉﺊﺋﺌﺎﺏﺐﺑﺒﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻫﻭﻮﻰﻲﻶﻸﻺﻼ]/.exec(word)) {
                        alert ('لغت پیشنهادی نویسهٔ غیرفارسی یا نویسهٔ نادرست دارد. قبل از گزارش لغت، لطفاً ابرابزار را در صفحه برانید!');
                        return;
                    }
                    if (/((.*\u200c)$|^(\u200c.*))/.exec(word)) {
                        alert ('در انتها یا ابتدای لغت پیشنهادی نویسهٔ فاصلهٔ مجازی اضافی وجود دارد. لطفاً آن را به کمک ابزار جایگزینی یا ابرابزار حذف کنید');
                        return;
                    }
                    $('checkdictation-marked-' + word.replace(/ /g, '_')).css('background-color', '');
                    element.css('background-color', '').css('color', 'grey').off();
                    loadPage('ویکی‌پدیا:اشتباه‌یاب/فهرست موارد درست').then(function (text) {
                        if ((text + '\n').indexOf('* ' + (cleanedWord || word) + '\n') !== -1) { return; }
                        return savePage('ویکی‌پدیا:اشتباه‌یاب/فهرست موارد درست', text + '\n* ' + (cleanedWord || word), 'افزودن لغت درست و پرکاربرد «' + (cleanedWord || word)+'» به فهرست کلمات [[وپ:اشتباه|اشتباه‌یاب]]. موجود در مقالهٔ [['+ mw.config.get('wgPageName')+']]');
                    }).then(function () {
                        mw.notify('کلمهٔ «' + word + '» به فهرست کلمات درست و پرکاربرد افزوده شد.');
                    });
                    $.get('//tools.wmflabs.org/checkdictation-fa/check/Botupdate').then(function () {}, function () {});
                });
            });

            markedItems.push(element[0]);
        });
        if (markedItems.length === 0) {
            mw.notify('ابزار موارد مشکوک را برای شما نمایش نمی‌دهد چون شما همه را درست درنظر گرفتید.');
            $('#checkdictation-tool').hide()
            return;
        };
        $('#spellmarkedwords').append(markedItems);
        $('<button>', { text: 'جایگزینی مواردی که انتخاب کردید!', style: 'margin-right: 2em', id: 'checkdictation-apply' }).click(function () {
            $(this).prop('disabled', 'disabled').text('در حال دریافت و جایگزینی صفحه...');
            loadPage(mw.config.get('wgPageName')).then(function (text) {
                replacements.forEach(function (x) { text = text.replace(x[0], x[1]); });
                return savePage(
                    mw.config.get('wgPageName'),
                    text,
                    '/'+'*جایگزینی با [[وپ:اشتباه|اشتباه‌یاب]]*'+'/' + replacements.map(function (x) { return x[2]; }).join('، ')
                );
            }).then(function () {
                mw.notify('انجام شد، لطفاً بررسی کنید');
                location.href = mw.util.getUrl(mw.config.get('wgPageName'), { diff: 'last' });
            });
        }).hide().appendTo('#spellmarkedwords');
    });
});

// Copyedited from https://de.wikipedia.org/wiki/MediaWiki:Gadget-Rechtschreibpruefung.js
function markWord(node, text, word, hint, color, preparedId) {
    var pos, len, newnodes = 0;
    var newnode, middlenode, endnode;

    // textnode - search for word
    if (node.nodeType == 3) {
        pos = node.data.search(text);
        if (pos >= 0) {
            // create new span-element
            newnode = $('<span>', {
                title: hint,
                class: 'checkdictation-marked checkdictation-marked-' + word.replace(/ /g, '_'),
                id: preparedId
            }).css('background-color', color)[0];

            // get length of the matching part
            len = node.data.match(text)[0].length;

            // splits content in three parts: begin, middle and end
            middlenode = node.splitText(pos);
            endnode = middlenode.splitText(len);

            // appends a copy of the middle to the new span-node
            newnode.appendChild(middlenode.cloneNode(true));
            // replace middlenode with the new span-node
            middlenode.parentNode.replaceChild(newnode, middlenode);

            newnodes = 1;
        }
    } else if ((node.nodeType == 1) // element node
        && (node.hasChildNodes()) // with child nodes
        && (node.tagName.toLowerCase() != "script") // no script, style and form
        && (node.tagName.toLowerCase() != "style") && (node.tagName.toLowerCase() != "form")) {
        var this_child;
        for (this_child = 0; this_child < node.childNodes.length; this_child++) {
            this_child = this_child + markWord(node.childNodes[this_child], text, word, hint, color, preparedId);
        }
    }
    return newnodes;
}

function loadPage(title) {
    return new mw.Api().get({
        action: 'query',
        prop: 'revisions',
        titles: title,
        rvprop: 'content',
        format: 'json'
    }).then(function (data) {
        return data.query.pages[Object.keys(data.query.pages)[0]].revisions[0]['*'];
    });
}

// from: http://80.68.89.23/2006/Jan/20/escape/
function regexpEscape(text) {
	return text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
}

function savePage(title, text, summary) {
    return new mw.Api().post({
        action: 'edit',
        title: title,
        text: text,
        summary: summary,
        nocreate: '',
        minor: '',
        token: mw.user.tokens.get('editToken')
    }).then(function (data) {
        if (data.error && data.error.info) {
            mw.notify(data.error.info);
        }
    }, function (data) {
        mw.notify(data);
    });
}
function getCookie(cname) {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1);
        if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
    }
    return "";
}

function setCookie(correctWord){
    correctWord=(correctWord+","+getCookie('ChDicCorrectWord')).split(',')
    var uniqueNames = [];
    $.each(correctWord, function(i, el){
        if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
    });
    if (uniqueNames.indexOf("") > -1) {
        uniqueNames.splice(uniqueNames.indexOf(""), 1);
    }
    document.cookie = "ChDicCorrectWord=" + uniqueNames + "; ";
}

function SetCorrectWord(){
    var correctWord=document.getElementById('spellmarkedwords').innerText.split(':');
    if (correctWord.length==2){setCookie(correctWord[1].split('،'))};
}

function dictationReplaceDialog(title, word, suggestions) {
    var defer = $.Deferred();
    $('#dictationform, #dictationform-input').remove();
    $('<div>', {
        text: title
    }).append(
        '<br><br>',
        $('<input>', {
            id: 'dictationform-input',
            value: word,
            style: 'line-height: 2;'
        }),
        $('<div>').append(suggestions.map(function (text) {
            return $('<button>', { text: text }).click(function () { $('#dictationform-input').val(text); });
        }))
    ).dialog({
        width: 600,
        title: 'اصلاح یک کلمه به طور عمومی در متن',
        buttons: [{
            text: 'افزودن به فهرست کلمات درست و پرکاربرد',
            class: 'ui-button-red',
            click: function () {
                if (confirm('کلماتی که به فهرست افزوده می‌شوند باید درست و پرکاربرد باشند. اگر کلمه درست و پرکاربرد است دکمهٔ Ok را کلیک کنید در غیر این صورت دکمهٔ Cancel را کلیک کنید.')){
                    defer.reject();
                }
                $(this).dialog('close');
            }
        }, {
            text: 'اصلاح شود',
            class: 'ui-button-green',
            click: function () {
                defer.resolve($('#dictationform-input', this).val());
                $(this).dialog('close');
            }
        }],
        close: function () {
            $('#dictationform, #dictationform-input').remove();
        }
    }).parent().prop('id', 'dictationform');
    return defer;
}