Участник:Putnik/infobox.js
Перейти к навигации
Перейти к поиску
/*
* В случае, если на странице нет шаблона-карточки, показывает,
* как она могла бы выглядеть на этой странице.
*/
( function ( mw, $ ) {
var api;
var wdApi;
var loopCnt = 0;
var blacklist = [];
var site = mw.config.get( 'wgDBname' );
var templateNS = mw.config.get( 'wgFormattedNamespaces' )[ 10 ];
function addIndicator( icon, action, title ) {
var $indicatorLink = $( '<a>' )
.append( new OO.ui.IconWidget( {
icon: icon
} ).$element );
if ( typeof action === 'string' ) {
$indicatorLink.attr( 'href', mw.util.getUrl( action ) );
} else {
$indicatorLink.attr( 'href', '#' );
if ( typeof action === 'function' ) {
$indicatorLink.on( 'click', action );
}
}
if ( title ) {
$indicatorLink.attr( 'title', title );
}
var $indicator = $( '<div>' )
.addClass( 'mw-indicator' )
.append( $indicatorLink );
mw.util.$content.find( '.mw-indicators' ).append( $indicator );
}
function addTemplate( wikitext ) {
api.postWithToken( 'csrf', {
action: 'edit',
title: mw.config.get( 'wgTitle' ),
prependtext: wikitext + '\n',
summary: '+' + wikitext,
} ).done( function ( data ) {
window.location.reload();
} );
}
function generateTemplate( templateTitle ) {
var replacement = new RegExp( '^' + templateNS + ':' );
var wikitext = '{' + '{' + templateTitle.replace( replacement, '' ) + '}}';
// Генерация HTML-кода шаблона.
api.get( {
action: 'parse',
prop: 'text',
title: mw.config.get( 'wgTitle' ),
text: wikitext
} ).done( function ( data ) {
if ( data.parse && data.parse.text ) {
var $infobox = $( '<div>' )
.append( $( data.parse.text[ '*' ] ) )
.find( '.infobox' );
$contentText = mw.util.$content.find( '.mw-body-content .mw-parser-output' )
.prepend( $infobox );
// Переход к шаблону.
addIndicator( 'code', templateTitle, 'Перейти к шаблону ' + wikitext );
// Вставка в код статьи.
addIndicator( 'templateAdd', function ( e ) {
e.preventDefault();
addTemplate( wikitext );
}, 'Вставить шаблон ' + wikitext + ' в начало статьи' );
} else {
mw.notify( 'Ошибка при генерации HTML-кода карточки', 'error' );
}
} );
}
/*
* Запрос ссылок на шаблоны в проекте для найденных элементов шаблонов.
*/
function getMainInfoboxSitelink( templateId ) {
// Запрос ссылки для элемента.
wdApi.get( {
action: 'wbgetentities',
props: 'sitelinks',
ids: templateId
} ).done( function ( data ) {
if ( data.success ) {
for ( var i in data.entities ) {
if ( !i.match( /^Q/ ) ) {
continue;
}
var sitelinks = data.entities[ i ].sitelinks;
if ( !sitelinks ) {
continue;
}
if ( sitelinks[ site ] ) {
generateTemplate( sitelinks[ site ].title );
return;
}
}
}
console.log( 'No infobox: ', templateId );
} );
}
/*
* Рекурсивный поиск шаблонов.
*/
function getMainInfobox( entityId ) {
// TODO: Сюда ссылку на запрос
// TODO: Исключить перечисления (Q12139612)
var query = 'SELECT DISTINCT ?tpl\
WHERE {\
{\
SELECT DISTINCT ?tpl ?tplClass ?supTpl ?depth (count(?midTpl) as ?specific)\
WHERE {\
{\
SELECT DISTINCT ?tpl ?tplClass (count(?mid) as ?depth)\
WHERE {\
?tpl wdt:P31 wd:Q19887878 .\
?tpl wdt:P1423 ?tplClass .\
wd:' + entityId + ' wdt:P31|wdt:P106 ?entityClass .\
?entityClass wdt:P279* ?mid .\
?mid wdt:P279* ?tplClass .\
}\
GROUP BY ?tpl ?tplClass\
}\
OPTIONAL{\
?tpl wdt:P279* ?midTpl .\
?midTpl wdt:P279* ?supTpl .\
}\
}\
GROUP BY ?tpl ?tplClass ?supTpl ?depth\
}\
FILTER EXISTS {\
?page schema:about ?tpl .\
?page schema:isPartOf <https:' + mw.config.get( 'wgServer' ) + '/> .\
}\
}\
ORDER BY ASC(?depth) DESC(?specific)\
LIMIT 1';
var url = 'https://query.wikidata.org/sparql?format=json&query=' + mw.util.rawurlencode( query );
$.post( url, function( data ) {
var templateUrl = ( ( ( ( ( data || {} ).results || {} ).bindings || [] )[ 0 ] || {} ).tpl || {} ).value;
if ( !templateUrl ) {
mw.notify( 'Не найден соответствующий шаблон-карточка', 'error' );
generateTemplate( templateNS + ':Универсальная карточка' );
return;
}
var templateId = templateUrl.replace( 'http://www.wikidata.org/entity/', '' );
getMainInfoboxSitelink( templateId );
});
}
/*
* Получение данных о шаблоне из Викиданных и вывод индикаторов.
*/
function checkExistingInfobox( templateName ) {
wdApi.get( {
action: 'wbgetentities',
props: 'claims',
sites: site,
titles: templateNS + ':' + templateName,
} ).done( function ( data ) {
var entityId;
var isInfobox = false;
var tplEntityId;
if ( data.success && data.entities ) {
for ( tplEntityId in data.entities ) {
var claims = ( data.entities[ tplEntityId ] || {} ).claims || {};
// Поиск связанного элемента.
entityId = ( ( ( ( ( claims.P1423 || {} )[ 0 ] || {} ).mainsnak || {} ).datavalue || {} ).value || {} ).id;
// Проверка типа шаблона.
var tplType = ( ( ( ( ( claims.P31 || {} )[ 0 ] || {} ).mainsnak || {} ).datavalue || {} ).value || {} ).id;
isInfobox = ( tplType === 'Q19887878' );
break;
}
}
// Иконка шаблона.
if ( isInfobox ) {
addIndicator( 'code', templateNS + ':' + templateName, 'Перейти к шаблону {' + '{' + templateName + '}}' );
} else {
addIndicator( 'alert', 'd:' + tplEntityId, 'Перейти к элементу шаблона {' + '{' + templateName + '}} в Викиданных для исправления типа (P31)' );
}
// Иконка типа.
if ( entityId ) {
addIndicator( 'wikiText', 'd:' + entityId, 'Перейти к элементу темы шаблона {' + '{' + templateName + '}} в Викиданных' );
processInfoboxEntityId( entityId );
} else {
addIndicator( 'noWikiText', 'd:' + tplEntityId, 'Перейти к элементу шаблона {' + '{' + templateName + '}} в Викиданных для исправления темы (P1423)' );
}
} );
}
function processInfoboxEntityId( entityId ) {
// Запрос ссылок для элементов.
wdApi.get( {
action: 'wbgetentities',
props: 'claims',
ids: entityId
} ).done( function ( data ) {
var propertyIds = [];
if ( data.success ) {
for ( var i in data.entities ) {
if ( !i.match( /^Q/ ) ) {
return;
}
var claims = ( data.entities[ i ] || {} ).claims;
if ( !claims || !claims.P1963 ) {
continue;
}
for ( var k in claims.P1963 ) {
var propertyId = ( ( ( ( ( claims.P1963 || {} )[ k ] || {} ).mainsnak || {} ).datavalue || {} ).value || {} ).id;
if ( propertyId ) {
propertyIds.push( propertyId );
}
}
}
}
if ( propertyIds.length ) {
requestPropertiesInfo( propertyIds );
}
} );
}
function requestPropertiesInfo( propertyIds ) {
// Запрос ссылок для элементов.
wdApi.get( {
action: 'wbgetentities',
props: 'info',
ids: propertyIds
} ).done( function ( data ) {
var fields = [];
if ( data.success ) {
for ( var i in data.entities ) {
if ( !i.match( /^P/ ) ) {
return;
}
var entity = data.entities[ i ];
fields.push( {
code: entity.id,
datatype: entity.datatype
} );
}
}
} );
}
/*
* Получение данных о TemplateData для шаблона и вывод индикатора.
*/
function checkTemplateData( templateName ) {
api.get( {
action: 'templatedata',
titles: templateNS + ':' + templateName,
} ).done( function ( data ) {
if ( data.pages && Object.keys( data.pages ).length === 0 ) {
addIndicator( 'articleNotFound', templateNS + ':' + templateName, 'Перейти к элементу шаблона {' + '{' + templateName + '}}' );
}
} );
}
/*
* Инициализация скрипта.
*/
var init = function () {
api = new mw.Api();
wdApi = new mw.ForeignApi( '//www.wikidata.org/w/api.php' );
if ( mw.config.get( 'wgAction' ) !== 'view' ||
mw.config.get( 'wgNamespaceNumber' ) ||
mw.config.get( 'wgIsMainPage' ) ||
mw.config.get( 'wgDiffNewId' ) ||
mw.config.get( 'wgDiffOldId' ) ||
[ 'metawiki', 'wikidatawiki' ].includes( mw.config.get( 'wgDBname' ) )
) {
return;
}
if ( mw.config.get( 'wgWikibaseItemId' ) === null ) {
mw.notify( 'К странице не привязан элемент Викиданных', 'warn' );
return;
}
// TODO: Проблема с mw.util.$content где-то в mediawiki.page.ready.
if ( mw.util.$content === null ) {
mw.util.$content = $( '#mw-content-text' );
}
// Если на странице есть карточка, то добавляем иконки:
// 1. Перехода к шаблону,
// 2. Удаления шаблона и вставки пустого.
// С самим шаблоном ничего не делаем.
// TODO: Показывать по клику, чтобы можно было увидеть,
// как она выглядит с пустыми параметрами.
var $infobox = mw.util.$content.find( '.infobox:not(.vertical-navbox)' );
if ( $infobox.length ) {
// Переход к шаблону.
var templateName = $infobox.first().data('name');
if ( templateName && templateName !== '{' + '{subst:PAGENAME}}' ) {
checkExistingInfobox( templateName );
checkTemplateData( templateName );
}
// Удаление и вставка пустого.
addIndicator( 'cancel', function ( e ) {
e.preventDefault();
mw.util.$content.find( '.infobox' ).remove();
init();
}, 'Скрыть имеющиеся шаблоны-карточки и показать, как будет выглядеть автоматически заполненная карточка' );
return;
}
getMainInfobox( mw.config.get( 'wgWikibaseItemId' ) );
};
$.when(
$.ready,
mw.loader.using( [
'mediawiki.api',
'mediawiki.ForeignApi',
'mediawiki.page.ready',
'mediawiki.util',
'oojs-ui-widgets',
'oojs-ui.styles.icons-alerts',
'oojs-ui.styles.icons-content',
'oojs-ui.styles.icons-editing-advanced',
'oojs-ui.styles.icons-interactions',
] )
).done( init );
}( mediaWiki, jQuery ) );