MediaWiki:Gadget-wikibugs-core.js
Перейти к навигации
Перейти к поиску
JS-код ниже относится к скрытому гаджету wikibugs-core. Связанный CSS-файл: MediaWiki:Gadget-wikibugs.css. Связанный JSON-файл: MediaWiki:Gadget-wikibugs-ignoreList.json.
После сохранения или недавних изменений очистите кэш браузера.
/*
* Original version: https://pl.wikipedia.org/wiki/MediaWiki:Wikibugs.js (2008-12-17)
* Russian version by [[User:Александр Сигачёв]], [[User:Putnik]], [[User:LEMeZza]]
* Converted to OOjs (2017-05-20) by [[User:Putnik]]
* Rewritten to be lazyloaded from [[MediaWiki:Gadget-wikibugs.js]] (2024-02-24) by [[User:Stjn]]
*/
mw.loader.using( [
'mediawiki.api',
'mediawiki.Title',
'mediawiki.htmlform.codex.styles',
'mediawiki.util',
'oojs-ui-core',
'oojs-ui.styles.icons-editing-core',
'oojs-ui-widgets',
'oojs-ui-windows',
], function () {
//'use strict';
window.wb$bugsPage = window.wb$bugsPage || 'Википедия:Сообщения об ошибках';
// Pages where the script does not run are in [[MediaWiki:Gadget-wikibugs.js]]
var wb$badPageData = require( './wikibugs-ignoreList.json' );
var wb$badPages = Object.keys( wb$badPageData );
var wb$i18n = {
title: 'Сообщить об ошибке',
btnFix: 'Исправить самостоятельно',
btnReport: 'Сообщить…',
btnCancel: 'Закрыть',
btnSend: 'Отправить',
fldPage: 'Название страницы',
fldText: 'Текст сообщения',
fldTextInfo: `Пожалуйста, опишите ошибку как можно точнее. При сообщении
о\u00A0фактической ошибке не забудьте указать источник, подтверждающий
вашу информацию.`.replace( /[\n\t]+/g, ' ' ),
fldCaptcha: 'Проверочный код',
fldSign: 'Подпись',
fldSignIP: 'будет указан ваш IP-адрес',
noAltText: 'Если вы не можете увидеть код, уберите протокол (HTTP) у ссылок и отправьте сообщение заново.',
alertShort: 'Описание ошибки слишком коротко. Пожалуйста, расширьте его.',
alertNoPage: 'Введите корректное имя страницы.',
alertCaptcha: `В вашем тексте содержатся внешние ссылки. Пожалуйста,
введите код с изображения и отправьте сообщение ещё раз.`,
alertError: 'Попробуйте ещё раз, так как при отправке произошла ошибка:',
sentFromMobile: 'Отправлено с мобильной версии',
protectionLevel: 'Уровень защиты страницы: ',
protections: {
autoconfirmed: 'до автоподтверждённых',
editautoreviewprotected: 'до автопатрулируемых',
sysop: 'до администраторов',
},
msgSign: 'Автор сообщения: ',
htmlIpWarn: `<strong>Внимание.</strong> При\u00A0отправке сообщения ваш IP-адрес
будет публично доступен на\u00A0странице сообщений об\u00A0ошибках.`,
htmlInfo: `<div class="wikibugs-social-warning">
<p><strong>Не\u00A0сообщайте</strong> об\u00A0ошибках на\u00A0других
сайтах (например, <strong>«ВКонтакте»</strong> или
<strong>«Одноклассники»</strong>), они будут проигнорированы.</p>
<p>Отсутствие статьи в\u00A0Википедии\u00A0— не\u00A0ошибка, вы можете оставить
<a href="${ mw.util.getUrl( 'Википедия:К созданию' ) }">запрос на её создание</a>.</p>
</div>
<p>Если вы заметили ошибку в\u00A0Википедии,
пожалуйста, исправьте её самостоятельно, используемая на\u00A0этом
сайте технология <a href="${ mw.util.getUrl( 'вики' ) }">вики</a>
позволяет это сделать.
Не\u00A0смущайтесь, одно из\u00A0правил Википедии гласит:
«<a href="${ mw.util.getUrl( 'Википедия:Правьте смело' ) }">Правьте смело</a>»!
Если вы не\u00A0можете исправить ошибку самостоятельно, сообщите
о\u00A0ней с\u00A0помощью данной формы.</p><p><strong>Если ошибка
уже исправлена\u00A0— не\u00A0сообщайте о\u00A0ней.</strong></p>
<p>Не\u00A0оставляйте свой телефон и/или электронный адрес, ответ
на\u00A0сообщение будет дан только на\u00A0странице
с\u00A0сообщениями и нигде больше.</p>
<p><a href="${ mw.util.getUrl( wb$bugsPage ) }">Текущий
список сообщений об ошибках</a></p>`,
};
// Support namespace aliases
const nsIds = mw.config.get( 'wgNamespaceIds' );
let nsAliases = Object.keys( nsIds ).filter( el => {
return [ 6, 14 ].includes( nsIds[ el ] );
} ).map( el => el.replace( /_/g, ' ' ) );
const wb$nsRegExp = new RegExp( `^(${ nsAliases.join( ':|' ) }:|\\/)`, 'i' );
function getWarning( str, isHtml ) {
var $html = $( '<div class="cdx-message cdx-message--block cdx-message--warning">' );
$html.append( '<span class="cdx-message-icon"></span>' );
var $content = $( '<div class="cdx-message__content">' );
if ( isHtml ) {
$content.html( str );
} else {
$content.text( str );
}
$html.append( $content );
return $html;
}
var wb$isValidPageName = function( name ) {
if ( !name || mw.config.get( 'wgNamespaceNumber' ) === -1 ) {
return false;
}
name = name.replace( /_/g, ' ' );
return !wb$badPages.includes( name );
};
var wb$isTalkPage = mw.config.get( 'wgCanonicalNamespace' ).toLowerCase().includes( 'talk' );
var wb$getPageName = function() {
var title = mw.config.get( 'wgTitle' );
if ( wb$isTalkPage ) {
var subjectPageNs = mw.config.get( 'wgNamespaceNumber' ) - 1;
if ( subjectPageNs === 0 ) {
return title;
}
return String( mw.Title.makeTitle( subjectPageNs, title ) ).replace( /_/g, ' ' );
}
return mw.config.get( 'wgPageName' ).replace( /_/g, ' ' );
};
// Code from [[:c:user:JWBTH/CD]], author: [[user:Jack who built the house]]
function es6ClassToOoJsClass( targetClass ) {
const originClass = Object.getPrototypeOf( targetClass );
targetClass.parent = targetClass.super = originClass;
OO.initClass( originClass );
targetClass.static = Object.create( originClass.static );
Object.getOwnPropertyNames( targetClass )
.filter( key => key !== 'static' )
.forEach( key => {
const descriptor = Object.getOwnPropertyDescriptor( targetClass, key );
if ( descriptor.enumerable || descriptor.get ) {
targetClass.static[ key ] = targetClass[ key ];
}
} );
targetClass.parent = targetClass.super = originClass;
return targetClass;
}
var wb$api = null;
var wb$windowManager = null;
var wb$pageWarn = null;
var wb$ReportDialog = es6ClassToOoJsClass( class wb$ProcessReportDialog extends OO.ui.ProcessDialog {
static get name() { return 'wbReportDialog' }
static get title() { return wb$i18n.title }
static get actions() {
return [
{ label: wb$i18n.btnSend, action: 'send', flags: [ 'primary', 'progressive' ] },
{ label: wb$i18n.btnCancel, action: 'cancel', flags: [ 'safe', 'close' ] },
];
}
static get size() { return 'medium' }
constructor () {
super();
}
initialize( ...args ) {
super.initialize( ...args );
// Prepare form
this.inputPage = new OO.ui.TextInputWidget( {
placeholder: wb$i18n.fldPage,
value: wb$getPageName(),
disabled: wb$isValidPageName( mw.config.get( 'wgPageName' ) ) && !mw.config.get( 'wgNamespaceNumber' ),
} );
this.inputText = new OO.ui.MultilineTextInputWidget( {
placeholder: wb$i18n.fldTextInfo,
rows: 5
} );
this.inputCaptcha = new OO.ui.TextInputWidget( {
placeholder: wb$i18n.fldCaptcha,
} );
this.panelCaptcha = new OO.ui.FieldLayout( this.inputCaptcha, {
label: wb$i18n.fldCaptcha,
} );
this.panelCaptcha.toggle( false );
this.imageCaptcha = new OO.ui.ToggleWidget();
this.imageCaptcha.$element.css( 'text-align', 'right' );
this.imageCaptchaImg = $( '<img>' ).attr( 'alt', wb$i18n.noAltText );
this.imageCaptcha.$element.append( this.imageCaptchaImg );
this.imageCaptcha.toggle( false );
this.inputSign = new OO.ui.TextInputWidget( {
placeholder: wb$i18n.fldSign,
value: mw.config.get( 'wgUserName' ) || wb$i18n.fldSignIP,
disabled: true
} );
var fieldset = new OO.ui.FieldsetLayout( {
classes: [ 'container' ],
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.inputPage, {
label: wb$i18n.fldPage,
align: 'top'
} ),
new OO.ui.FieldLayout( this.inputText, {
label: wb$i18n.fldText,
align: 'top'
} ),
this.panelCaptcha,
this.imageCaptcha,
new OO.ui.FieldLayout( this.inputSign, {
label: wb$i18n.fldSign,
} ),
] );
this.panel = new OO.ui.PanelLayout( {
padded: true,
expanded: false,
} );
this.panel.$element.append( wb$pageWarn );
if ( mw.config.get( 'wgUserName' ) === null ) {
this.panel.$element.append( getWarning( wb$i18n.htmlIpWarn, true ) );
}
this.panel.$element.append( fieldset.$element );
this.$body.append( this.panel.$element );
}
getSetupProcess( data ) {
return super.getSetupProcess( data );
}
getReadyProcess( data ) {
return super.getReadyProcess( data );
}
getActionProcess( action ) {
const dialog = this;
const superAction = () => {
return super.getActionProcess( action );
};
if ( action !== 'send' ) {
dialog.close();
return superAction();
}
dialog.getActions().setAbilities( { send: false } );
// Send message
var content = dialog.inputText.getValue().trim();
if ( content === '' || content.length < 20 || !content.match( ' ' ) ) {
mw.notify( wb$i18n.alertShort, { tag: 'wb$NotifySubmit' } );
dialog.inputText.focus();
dialog.getActions().setAbilities({ send: true });
return superAction();
}
var page = dialog.inputPage.getValue()
.replace( /^https?:\/\/ru\.wikipedia\.org\/wiki\/(.+)$/, '$1' )
.replace( /_/g, ' ' );
page = decodeURIComponent( page );
var section;
var signature = [];
if ( location.hostname.includes( '.m.wikipedia.org' ) ) {
signature.push( wb$i18n.sentFromMobile );
}
if ( page === mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ) &&
wb$isValidPageName( mw.config.get( 'wgPageName' ) )
) {
section = page.replace( wb$nsRegExp, ':$1' );
if ( mw.config.get( 'wgNamespaceNumber' ) === 6 ) {
content = `[[File:${
mw.config.get( 'wgTitle' )
}|thumb|left|100px]]\n* ${content}\n{{clear}}`;
}
var editRestrictions = mw.config.get( 'wgRestrictionEdit' );
if ( editRestrictions.length > 0 ) {
signature.push( wb$i18n.protectionLevel + editRestrictions.map( l => wb$i18n.protections[ l ] || l ).join( ', ' ) );
}
} else {
page = page
.replace( /\[\[([^\[\]\|]+)\|[^\[\]\|]+\]\]/g, '$1' )
.replace( /[\[\]\|]/g, '' )
.replace( /^\s+/g, '' )
.replace( /\s+$/g, '' );
if ( !wb$isValidPageName( page ) ) {
mw.notify( wb$i18n.alertNoPage, { tag: 'wb$NotifySubmit' } );
if ( wb$isValidPageName( mw.config.get( 'wgPageName' ) ) ) {
dialog.inputPage.setValue( mw.config.get( 'wgPageName' ) );
} else {
dialog.inputPage.setValue( '' );
dialog.inputPage.focus();
}
dialog.getActions().setAbilities({ send: true });
return superAction();
}
section = page.replace( wb$nsRegExp, ':$1' );
}
section = `[[${section}]]`;
signature.push( wb$i18n.msgSign + '~~' + '~~' );
content += '\n\n';
content += signature.join( '. ' );
dialog.getActions().get()[ 0 ].pushPending();
wb$api = wb$api || new mw.Api();
var data = {
errorformat: 'html',
errorlang: mw.config.get( 'wgUserLanguage' ),
errorsuselocal: true,
};
var captchaId = dialog.imageCaptchaImg.data( 'id' );
if ( captchaId ) {
data.captchaid = captchaId;
data.captchaword = dialog.inputCaptcha.getValue().trim();
}
wb$api.newSection(
wb$bugsPage,
section,
content,
data
).catch( function( code, err ) {
dialog.getActions().get()[ 0 ].popPending();
var $error = $( '<div>' ).text( wb$i18n.alertError );
$error.append( wb$api.getErrorMessage( err ) );
mw.notify( $error, { type: 'error', tag: 'wb$NotifySubmit' } );
dialog.getActions().setAbilities({ send: true });
} ).then( function( xhr ) {
if ( OO.getProp( xhr, 'edit', 'result' ) === 'Success' ) {
// Success, go to DiscussionTools heading ID
var url = mw.config.get( 'wgServer') + mw.util.getUrl( wb$bugsPage );
var timestamp = xhr.edit.newtimestamp.replace( /[T:-]/g, '' ).replace( /\d{2}Z/, '00' );
var anchor = `h-${page.replace( / /g, '_' )}-${timestamp}`;
window.location.href = `${url}#${anchor}`;
} else if ( OO.getProp( xhr, 'edit', 'captcha', 'type' ) === 'image' ) {
// Captcha
dialog.imageCaptchaImg
.attr( 'src', xhr.edit.captcha.url )
.data( 'id', xhr.edit.captcha.id )
.on( 'load', () => {
dialog.updateSize();
} );
dialog.imageCaptcha.toggle( true );
dialog.inputCaptcha.setValue( '' );
dialog.panelCaptcha.toggle( true );
dialog.updateSize();
dialog.getActions().get()[ 0 ].popPending();
mw.notify( wb$i18n.alertCaptcha, { type: 'warning', tag: 'wb$NotifySubmit' } );
dialog.getActions().setAbilities( { send: true } );
} else {
// Error
dialog.getActions().get()[ 0 ].popPending();
var $error = $( '<div>' ).text( wb$i18n.alertError );
$error.append( wb$api.getErrorMessage( xhr ) );
mw.notify( $error, { type: 'error', tag: 'wb$NotifySubmit' } );
dialog.getActions().setAbilities( { send: true } );
}
} );
return superAction();
}
} );
var wb$InfoDialog = es6ClassToOoJsClass( class wb$ProcessInfoDialog extends OO.ui.ProcessDialog {
static get name() { return 'wbInfoDialog' }
static get title() { return wb$i18n.title }
static get actions() {
return [
{
label: wb$i18n.btnReport,
action: 'report',
flags: [ 'primary', 'progressive' ],
modes: [ 'all', 'editable' ],
},
{
label: wb$i18n.btnFix,
action: 'edit',
icon: 'edit',
flags: 'progressive',
modes: 'editable',
},
{
label: wb$i18n.btnCancel,
action: 'cancel',
flags: [ 'safe', 'close' ],
modes: [ 'all', 'editable' ],
},
];
}
static get size() { return 'large' }
constructor () {
super();
}
initialize( ...args ) {
super.initialize( ...args );
const $infoHtml = $( '<div class="wikibugs-info">' ).html( $.parseHTML( wb$i18n.htmlInfo ) );
this.panel = new OO.ui.PanelLayout( {
padded: true,
expanded: false,
} );
this.panel.$element.append( $infoHtml );
var pageName = wb$getPageName();
if ( !wb$isValidPageName( pageName ) ) {
var pageWarn = wb$badPageData[ pageName ];
if ( pageWarn !== true ) {
wb$pageWarn = getWarning( pageWarn );
this.panel.$element.append( wb$pageWarn );
}
}
this.$body.append( this.panel.$element );
}
getSetupProcess( data ) {
const dialog = this;
return super.getSetupProcess( data )
.next( function() {
// Disable edit button here
if ( !mw.config.get( 'wgIsProbablyEditable' ) ) {
dialog.actions.setMode( 'all' );
}
} );
}
getReadyProcess( data ) {
return super.getReadyProcess( data );
}
getActionProcess( action ) {
if ( action === 'edit' ) {
// Go to edit page
var $editLink = $( mw.config.get( 'skin' ) === 'minerva' ? '#ca-edit' : '#ca-edit a' );
var editUrl = mw.util.getUrl( wb$bugsPage );
if ( $editLink.length ) {
editUrl = $editLink.attr( 'href' );
}
window.location.assign( editUrl );
} else if ( action === 'report' ) {
this.close();
wb$windowManager.openWindow( 'wbReportDialog' );
} else {
this.close();
}
return super.getActionProcess( action );
}
});
// Expose this function for [[MediaWiki:Gadget-wikibugs.js]]
window.wb$runWikibug = function () {
const hadNoManager = wb$windowManager === null;
wb$windowManager = wb$windowManager || new OO.ui.WindowManager();
if ( hadNoManager ) {
$( 'body' ).append( wb$windowManager.$element );
const infoDialog = new wb$InfoDialog();
const reportDialog = new wb$ReportDialog();
wb$windowManager.addWindows( [ infoDialog, reportDialog ] );
}
wb$windowManager.openWindow( 'wbInfoDialog' );
};
} );