User:Jeblad/external-articles-dev-v0.0/script.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
var marker = 'external-article';
var agent = 'Gadget/ExternalArticle (0.1)';
var entity = null;
var domains = {
snl: {
encyclopedia: 'Store norske leksikon',
url: 'https://snl.no/',
category: 'Artikler med SNL-lenker fra Wikidata',
check: true,
property: 'P4342'
},
nbl: {
encyclopedia: 'Norsk biografisk leksikon',
url: 'https://nbl.snl.no/',
category: 'Artikler med NBL-lenker fra Wikidata',
check: true,
property: 'P5080'
},
nkl: {
encyclopedia: 'Norsk kunstnerleksikon',
url: 'https://nkl.snl.no/',
category: 'Artikler med NKL-lenker fra Wikidata',
check: true,
property: 'P5081'
},
sml: {
encyclopedia: 'Store medisinske leksikon',
url: 'https://sml.snl.no/',
category: 'Artikler med SML-lenker fra Wikidata',
check: true,
property: 'P5082'
}
};
var fallbacks = {
'external-article-enable': 'Enable externals',
'external-article-enable-desc': 'Enable loading of similar external pages',
'external-article-disable': 'Disable externals',
'external-article-disable-desc': 'Disable loading of similar external pages',
'external-article-button-dismiss': 'Dismiss',
'external-article-button-connect': 'Connect',
'external-article-connect-success-desc': 'External article is permanently added to the item.',
'external-article-connect-failure-property-desc': 'Adding the external article to the item trough the property failed.',
'external-article-connect-failure-qualifier-desc': 'Adding a qualifier to property for the external article failed.',
'external-article-connect-failure-token-desc': 'Getting the necessary token to be able to edit the item failed.',
'external-article-purge-failure-desc': 'Purging the page failed.',
'external-article-automatic-dismiss-desc': 'Alternate titles are exhausted and the external article is temporarily dismissed.',
'external-article-failure-title': 'External article failure',
'external-article-general-api-failure-desc': 'General unspecific API failure.',
'external-article-general-api-warning-desc': 'General specific API warning.',
'external-article-loader-failure-desc': 'Loader failed to deliver the modules.',
'external-article-not-connected-desc': 'Could not find a connected item.',
'external-article-property-exist-desc': 'The property already exist in the item.',
'external-article-previously-dismissed-desc': 'The external articles are previously dismissed, either manually or automatically.',
'external-article-edit-page': 'Edit page',
'external-article-mapping-relation': 'External is',
'external-article-skos-exact': 'exact',
'external-article-skos-close': 'close',
'external-article-skos-related': 'related',
'external-article-skos-narrower': 'narrower',
'external-article-skos-broader': 'broader'
};
var logWarnings = function( data ) {
for ( var lst in data.warnings ) {
for ( var msg in data.warnings ) {
mw.log( 'ExternalArticle ('+lst+'): ', data.warnings[lst][ msg ] );
}
}
};
var createFailNotice = function( context, msg ) {
mw.notify( msg.escaped(), {
title: context.encyclopedia,
autoHide: false,
tag: context.encyclopedia
} );
};
var createFailHandler = function( context, msg ) {
return function() {
createFailNotice( context, msg || mw.message( 'external-article-general-api-failure-desc' ) );
};
};
var createDoneHandler = function( context, msg ) {
return function( data ) {
if ( data.warnings ) {
logWarnings( data );
createFailNotice( context, msg || mw.message( 'external-article-general-api-warning-desc' ) );
}
};
};
var purge = function( context ) {
mw.log( 'ExternalArticle (entered purge): ', context );
var api = new mw.Api();
var articleId = mw.config.get( 'wgArticleId' );
return api.post( {
action: 'purge',
pageids: articleId
} )
.fail ( createFailHandler( context ) )
.done( createDoneHandler( context, mw.message( 'external-article-purge-failure-desc' ) ) );
};
var setQualifier = function( context, csrfToken, claimId, qualifier ) {
mw.log( 'ExternalArticle (entered setQualifier): ', context );
var foreign = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' );
return foreign.post( {
action: 'wbsetqualifier',
snaktype: 'value',
token: csrfToken,
claim: claimId,
property: 'P4390',
value: JSON.stringify({ 'id': qualifier }),
summary: agent
} )
.fail ( createFailHandler( context ) )
.done( createDoneHandler( context, mw.message( 'external-article-connect-failure-qualifier-desc' ) ) );
};
var createClaim = function( context, csrfToken, entityId, title ) {
mw.log( 'ExternalArticle (entered createClaim): ', context );
var foreign = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' );
return foreign.post( {
action: 'wbcreateclaim',
snaktype: 'value',
token: csrfToken,
entity: entityId,
property:context.property,
value:JSON.stringify(title.replace(/\s+/g, '_')),
summary: agent
} )
.fail ( createFailHandler( context ) )
.done( createDoneHandler( context, mw.message( 'external-article-connect-failure-property-desc' ) ) );
};
var queryToken = function( context ) {
mw.log( 'ExternalArticle (entered queryToken): ', context );
var foreign = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' );
return foreign.get( {
action: 'query',
meta: 'tokens'
} )
.fail ( createFailHandler( context ) )
.done( createDoneHandler( context, mw.message( 'external-article-connect-failure-token-desc' ) ) );
};
var connect = function( context, ext, qualifier ) {
var csrfToken = null;
return queryToken( context )
.done( function( data, success ) {
csrfToken = data.query.tokens.csrftoken;
createClaim( context, csrfToken, entity.id, ext.title )
.done( function( data ) {
setQualifier( context, csrfToken, data.claim.id, qualifier )
.done( function( data ) {
mw.notify( mw.message( 'external-article-connect-success-desc' ).escaped(), {
title: context.encyclopedia,
autoHide: true,
autoHideSeconds: 'short',
tag: context.encyclopedia
} );
purge( context );
} );
} );
} );
};
var buildNotification = function( context, data ) {
var $html = $( '<div>' );
var $content = $( '<div>' )
.addClass( 'mw-external-content' )
.css( {
'max-height': '350px',
'overflow': 'hidden',
'text-overflow': 'ellipsis'
} );
var connectBtn = new OO.ui.ButtonInputWidget( {
label: mw.message( 'external-article-button-connect' ).escaped(),
value: 'connect',
flags: [ 'progressive' ]
} );
var dismissBtn = new OO.ui.ButtonInputWidget( {
label: mw.message( 'external-article-button-dismiss' ).escaped(),
value: 'dismiss',
flags: []
} );
/*
var editVal = sessionStorage.getItem( marker + '-' + context.name + '-edit' );
var editCbx = new OO.ui.CheckboxInputWidget( {
value: 'edit',
selected: 'edit' === editVal
} );
*/
var assocLst = new OO.ui.DropdownInputWidget( {
label: null,
options: [
{ data: 'Q39893449', label: mw.message( 'external-article-skos-exact' ).escaped() },
{ data: 'Q39893184', label: mw.message( 'external-article-skos-close' ).escaped() },
{ data: 'Q39894604', label: mw.message( 'external-article-skos-related' ).escaped() },
{ data: 'Q39893967', label: mw.message( 'external-article-skos-narrower' ).escaped() },
{ data: 'Q39894595', label: mw.message( 'external-article-skos-broader' ).escaped() }
]
} );
var fieldset = new OO.ui.FieldsetLayout( {
label: null,
items: [
new OO.ui.FieldLayout( assocLst, {
label: mw.message( 'external-article-mapping-relation' ).escaped()
} ),
/*
new OO.ui.FieldLayout( editCbx, {
label: mw.message( 'external-article-edit-page' ).escaped(),
align: 'inline'
} ),
*/
new OO.ui.FieldLayout(
new OO.ui.Widget( {
content: [
new OO.ui.HorizontalLayout( {
items: [
dismissBtn,
connectBtn
] } ) ] } ) )
] } );
var form = new OO.ui.FormLayout( {
$content: fieldset.$element,
action: '/api/formhandler',
method: 'get'
} );
/*
editCbx.$element.on( 'change', function () {
sessionStorage.setItem( marker + '-' + context.name + '-edit', editCbx.isSelected() ? 'edit' : 'no-edit' );
} );
*/
connectBtn.$element.on( 'click', null, context, function( event ) {
connect( context, data, assocLst.value );
return true;
} );
dismissBtn.$element.on( 'click', null, context, function( event ) {
/*
mw.notify( mw.message( 'external-article-button-dismiss-success-desc' ).escaped(), {
title: context.encyclopedia,
autoHide: true,
autoHideSeconds: 'short',
tag: context.encyclopedia
} );
*/
queryRequest( context );
return true;
} );
$( '<a>' ).attr( { 'href': data.url } ).addClass( 'mw-notification-subtitle' ).text( data.title ).appendTo( $content );
$( data.xhtml_body ).find( 'p:first' ).appendTo( $content );
$content.appendTo( $html );
//$( '<hr>' ).appendTo( $html );
form.$element.appendTo( $html );
form.$element.on( 'click', function( event ) {
event.stopPropagation();
} );
mw.notify( $html, {
title: context.encyclopedia,
autoHide: false,
tag: context.encyclopedia,
type: marker
} );
};
var attemptRequest = function( context, title ) {
jQuery.ajax( {
dataType: "json",
url: context.url + mw.util.wikiUrlencode( title ) + '.json',
context: context,
headers: {
'User-Agent': navigator.userAgent+' '+agent
},
success: function( data, textStatus, jqXHR ){
buildNotification( this, data );
},
error: function( jqXHR, textStatus, errorThrown ){
if ( textStatus === 'error' && errorThrown === '' ) {
queryRequest( context );
}
}
} );
};
var queryRequest = function( context ) {
if ( context.index === undefined ) {
context.index = -1;
}
if ( context.index >= context.titles.length ) {
var aid = marker + '-' + context.name + '-' + mw.config.get( 'wgArticleId' );
sessionStorage.setItem( aid, 'dismissed' );
mw.notify( mw.message( 'external-article-automatic-dismiss-desc' ).escaped(), {
title: context.encyclopedia,
autoHide: true,
autoHideSeconds: 'short',
tag: context.encyclopedia
} );
return;
}
attemptRequest( context, context.titles[ context.index++ ] );
};
var stripParenthesis = function( str ) {
return str.replace( /\s*\(.*?\)\s*$/, '' );
};
var toLowerCaseFirst = function( str ) {
return str[ 0 ].toLowerCase() + str.slice( 1 );
};
var inContentNamespace = function( namespaces ) {
return 0 <= namespaces.indexOf( mw.config.get( 'wgNamespaceNumber' ) );
}
var isAction = function( action ) {
return 'view' === mw.config.get( 'wgAction' )
}
$.when( mw.loader.using( [ 'mediawiki.api.messages', 'mediawiki.util', 'mediawiki.ForeignApi', 'oojs-ui-core' ] ) )
.then( function() {
"use strict";
return new mw.Api().getMessages( Object.keys( fallbacks ), { amlang: mw.config.get( 'wgUserLanguage' ) } )
.fail( function() {
$.each( fallbacks, function( key, message ) {
mw.messages.set( key, message );
} );
} )
.then( function( messages ) {
var msgs = {};
jQuery.extend( msgs, fallbacks, messages );
$.each( msgs, function( key, message ) {
mw.messages.set( key, message );
} );
} );
} )
.fail( function() {
$.each( fallbacks, function( key, message ) {
mw.messages.set( key, message );
} );
mw.notify( mw.message( 'external-article-loader-failure-desc' ).escaped(), {
title: mw.message( 'external-article-failure-title' ).escaped(),
autoHide: true
} );
})
.then( function() {
"use strict";
// bail out?
if ( !inContentNamespace( mw.config.get( 'wgContentNamespaces' ) )
|| !isAction( 'view' )
|| mw.util.getParamValue( 'type' )
|| mw.util.getParamValue( 'diff' )
|| mw.util.getParamValue( 'redirect' )
|| mw.util.getParamValue( 'veaction' )
) {
mw.log( 'ExternalArticle: ', 'terminates' );
return;
}
// check if the external article is previously dismissed
Object.keys( domains ).map( function( name ) {
var aid = marker + '-' + name + '-' + mw.config.get( 'wgArticleId' );
var domain = domains[ name ];
domain.name = name;
domain.check &= sessionStorage.getItem( aid ) !== 'dismissed';
} );
// extend caction menu
var queryDomains = function() {
var name = null; // @todo should use "let", but this is es5
var domain = null; // @todo should use "let", but this is es5
for ( name in domains ) {
domain = domains[ name ];
if ( domain.check && domain.titles ) {
queryRequest( domain );
}
}
};
var dismissDomains = function() {
$( '.mw-notification-type-'+marker ).trigger( 'click' );
};
mw.util.addPortletLink(
'p-cactions', '#',
mw.message( 'external-article-enable' ).escaped(),
'ca-enable-externals',
mw.message( 'external-article-enable-desc' ).escaped(),
null, null
);
$( '#ca-enable-externals' ).on( 'click', function() {
$( '#ca-enable-externals' ).hide();
$( '#ca-disable-externals' ).show();
sessionStorage.setItem( marker + '-' + 'state', 'enabled' );
queryDomains();
} );
mw.util.addPortletLink(
'p-cactions', '#',
mw.message( 'external-article-disable' ).escaped(),
'ca-disable-externals',
mw.message( 'external-article-disable-desc' ).escaped(),
null, null
);
$( '#ca-disable-externals' ).on( 'click', function() {
$( '#ca-disable-externals' ).hide();
$( '#ca-enable-externals' ).show();
sessionStorage.setItem( marker + '-' + 'state', 'disabled' );
dismissDomains();
} );
var state = sessionStorage.getItem( marker + '-' + 'state' );
$( ( ( state || 'enabled' ) === 'enabled' ) ? '#ca-enable-externals' : '#ca-disable-externals' ).hide();
var foreign = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' );
var title = mw.config.get( 'wgTitle' );
var dbName = mw.config.get( 'wgDBname' );
var language = mw.config.get( 'wgContentLanguage' );
foreign.get( {
action: 'wbgetentities',
titles: title,
sites: dbName,
props: 'aliases|labels|sitelinks|claims',
languages: language,
sitefilter: dbName
} )
.done( function( data, success ) {
mw.log( 'ExternalArticle (wbgetentities): ', data );
if ( data.warnings || !data.success ) {
var content;
if ( !data.success ) {
content = mw.message( 'external-article-general-api-failure-desc' ).escaped();
}
else {
content = $( '<dl>' );
for ( var msg in data.warnings.wbgetentities ) {
$( '<li>' ).text( data.warnings.wbgetentities[ msg ] ).appendTo( content );
}
}
mw.notify( content, {
title: mw.message( 'external-article-failure-title' ).escaped(),
autoHide: true
} );
return;
}
//var entity = null;
var found = false;
if ( data.entities ) {
for ( var eid in data.entities ) {
entity = data.entities[ eid ];
if ( entity.sitelinks ) {
for ( var sid in entity.sitelinks ) {
var sitelink = entity.sitelinks[ sid ];
found = sitelink.site == dbName && sitelink.title == title;
if ( found ) {
break;
}
}
}
if ( found ) {
break;
}
}
}
if ( !found ) {
mw.log( 'ExternalArticle: ', 'about to terminate, entity not found' );
mw.notify( mw.message( 'external-article-not-connected-desc' ).escaped(), {
title: mw.message( 'external-article-failure-title' ).escaped(),
autoHide: true
} );
return;
}
// check if the external article is previously dismissed
var name = null; // @todo should use "let", but this is es5
var domain = null; // @todo should use "let", but this is es5
for ( name in domains ) {
domain = domains[ name ];
domain.check &= !entity.claims[domain.property];
if ( false && !domain.check ) {
mw.notify( mw.message( entity.claims[domain.property]
? 'external-article-property-exist-desc'
: 'external-article-previously-dismissed-desc' ).escaped(), {
title: domain.encyclopedia,
autoHide: true,
autoHideSeconds: 'short'
} );
continue;
}
var titles = [];
var i, l;
titles.push( stripParenthesis( mw.config.get( 'wgTitle' ) ) );
titles.push( toLowerCaseFirst( stripParenthesis( mw.config.get( 'wgTitle' ) ) ) );
if ( entity.labels && entity.labels[ language ] ) {
var label = entity.labels[ language ];
titles.push( stripParenthesis( label.value ) );
titles.push( toLowerCaseFirst( stripParenthesis( label.value ) ) );
}
if ( entity.aliases && entity.aliases[ language ] ) {
var aliases = entity.aliases[ language ];
for ( i=0,l=aliases.length; i<l; i++ ) {
var alias = aliases[ i ];
titles.push( stripParenthesis( alias.value ) );
titles.push( toLowerCaseFirst( stripParenthesis( alias.value ) ) );
}
}
var seen = {};
domain.titles = [];
for ( i=0,l=titles.length; i<l; i++ ) {
var titleString = titles[ i ];
if ( !seen[ titleString ] ) {
domain.titles.push( titleString );
}
seen[ titleString ] = true;
}
}
var state = sessionStorage.getItem( marker + '-' + 'state' );
if ( ( state || 'enabled' ) === 'enabled' ) {
queryDomains();
}
} );
} );