Utilisateur:Ayack/addViafData.js
Apparence
Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;
Firefox (sur GNU/Linux) / Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.mw.loader.using('mediawiki.util', function () {
/***********************************************************************
* addViafData.js
*
* A tool to make it easy to select and import authority control data
* from VIAF (viaf.org) using a text query.
*
* Adds a link to the toolbox which opens a frame at the top of the page
* containing a search box which loads data directly from VIAF. Click
* the icon to use the record, or the number to jump to the VIAF record
* page.
*
* Bugs and suggestions to [[User:Inductiveload]], or patch as needed
*
* Version 0.1 - 2012-01-19 - Initial release
* - 2012-01-25 - Allow suggested text to load even on
* non-existent pages
* - 2012-03-10 - Warn when VIAF AutoSuggest might not
* return all hits
* - 2012-04-23 - Add ability to save pages, update pages
* while editing, de-select VIAF entries
*
**********************************************************************/
var VIAFDataGrabber = function(){ //constructor
//list of parameters allowed in AC templates
this.template_parameters_allowed = ['GND', 'BNF', 'LCCN', 'VIAF', 'SELIBR', 'NLA', 'ULAN', 'SUDOC', 'type', 'WORLDCATID', 'ISNI'];
this.ac_template_re = /{{ *[Aa]utorité *\|[\s\S]*?}}/m; //regex to find AC templates
this.footer_re = /((\=+ *Liens? externes? *\=+)\n(\n*\{\{[aA]utres projets[^\}]*\}\})?)/ ;//regex to find the footers which go under the AC template
this.icons = {
'add':'/media/wikipedia/commons/thumb/4/41/Ambox_emblem_plus.svg/20px-Ambox_emblem_plus.svg.png',
'remove':'/media/wikipedia/commons/thumb/9/97/Dialog-error-round.svg/20px-Dialog-error-round.svg.png'
}
this.pageDataFound = false;
this.acDataFound = false;
this.acDataFoundIsBad = false;
this.viafAutosuggestMaxResults= 10; //max results viaf returns
this.add_VIAF_button();
//this.add_VIAF_pane(); //uncomment when debugging to prevent having to click button each time
}
VIAFDataGrabber.prototype.construct_VIAF_search_URL = function(query){
return 'http://viaf.org/viaf/search?query=local.personalNames="' + query + '"&stylesheet=/viaf/xsl/results.xsl&sortKeys=holdingscount&maximumRecords=100'
}
VIAFDataGrabber.prototype.close_VIAF_pane = function(){
$('#add_viaf_data_pane').remove();
}
VIAFDataGrabber.prototype.add_VIAF_pane = function(){
var myself = this;
if ($('#add_viaf_data_pane').length > 0){
return
}
mw.util.addCSS( '.selected .viaf-id-link { font-weight:bold; }' );
mw.util.addCSS( '.viaf-entry-icon { float:left; width:20px; height:20px; background-image:url("' + this.icons['add'] + '"); }' );
mw.util.addCSS( '.selected .viaf-entry-icon { background-image:url("' + this.icons['remove'] + '"); }' );
mw.util.addCSS( '#viaf_raw_proposed_data {margin-left:1em; font-size:120%; background-color:white; }' );
mw.util.addCSS( '.viaf-changes-list {margin-left:2em; font-size:80%;}' );
this.viafDiv = $('<div id="add_viaf_data_pane" style="position:relative; background-color:#F9F9F9; border:1px solid #AAAAAA; padding:1em; margin-bottom:0.5em; margin-top:0.5em;"><h3>Ajouter des notices d’autorité</h3></div>')
var closeDiv = $('<div style="position:absolute; right:1em; top:0.1em;"></div>');
var closeLink = $('<a href="#">[Fermer]</a>');
closeLink.click( function(){
myself.close_VIAF_pane()
});
closeDiv.append(closeLink);
this.viafDiv.append(closeDiv);
var jump_to_viaf_link = $("<a> Aller à la page de recherche du VIAF.</a>");
var viaf_query_input = $('<input type="text" name="viaf_query" id="viaf_query_input" value="' + mw.config.get( 'wgTitle' ) + '"/>');
viaf_query_input.change( function(){
// link to real VIAF search
jump_to_viaf_link.attr('href', myself.construct_VIAF_search_URL( $('#viaf_query_input').val() ) );
} );
var submitVIAFquery = $('<input type="button" value="Rechercher dans le VIAF" id="submit_viaf_query" name="submit_viaf_query"/>')
submitVIAFquery.click( function(){
//using real search (but how to make the cross domain request?)
//var url = 'http://viaf.org/viaf/search?query=local.personalNames = "' + $('#viaf_query_input').val() + '"&version=1.1&operation=searchRetrieve&recordSchema=http://viaf.org/VIAFCluster&maximumRecords=50&startRecord=1&resultSetTTL=300&recordPacking=xml&recordXPath=&sortKeys=&httpAccept=text/xml'
//using autosuggest (clumsy, but we can use JSONP)
$.ajax( {
url: 'http://viaf.org/viaf/AutoSuggest',
data: {
query: $('#viaf_query_input').val()
},
dataType: 'jsonp',
success: function( data ) {
myself.display_query_results(data);
}
} );
} );
this.viafResultsDiv = $('<div id="viaf_results"></div>');
this.viafCurrentDataDiv = $('<div></div>');
this.viafProposedDataDiv = $('<div id="proposed_authority_control_data"></div>');
this.viafSaveACDiv = $('<div id="viaf_save_authority_control" style="display:none;"><hr></div>');
var saveACButton = $('<input type="button" value="Mettre à jour les notices d’autorité de la page" id="viaf_save_ac_template" name="viaf_save_ac_template"/>');
this.viafSaveACDiv.append(saveACButton);
saveACButton.click( function(){
myself.save_ac_data();
});
this.viafDiv.append(viaf_query_input, submitVIAFquery, jump_to_viaf_link);
this.viafDiv.append('<hr>', this.viafResultsDiv)
this.viafDiv.append('<hr>', this.viafCurrentDataDiv);
this.viafDiv.append('<hr>', this.viafProposedDataDiv);
this.viafDiv.append(this.viafSaveACDiv);
$('#bodyContent').prepend( this.viafDiv );
viaf_query_input.change(); //trigger an update of the link
if ( mw.config.get( 'wgAction' ) == 'view' ){ //get data from API
this.get_raw_page( mw.config.get( 'wgPageName' ), this.show_current_authority_data)
} else if ($.inArray( mw.config.get( 'wgAction' ), ['submit', 'edit'] ) > -1 ){ //or from the current edit box
this.show_current_authority_data ($('#wpTextbox1').val() );
}
submitVIAFquery.click(); //preload the page name results
}
VIAFDataGrabber.prototype.show_current_authority_data = function(data){
if (data == null){
var current_ac_data = null
} else {
var current_ac_data = data.match(/{{ *[Aa]utorité *\|.*}}/g);
}
this.pageDataFound = true;
if (current_ac_data == null ){
this.viafCurrentDataDiv.html('Aucune notice d’autorité n’a été trouvée sur cette page.');
this.acDataFound = false;
this.acDataFoundIsBad = false;
} else if (current_ac_data.length == 1){
this.viafCurrentDataDiv.html('Des notices d’autorité ont été trouvées sur cette page. Les nouvelles notices vont leur être ajoutées.<br>');
this.viafCurrentDataDiv.append('<tt style="margin-left:1em;" id="current_authority_control_data">' + current_ac_data[0] + '</tt>');
this.acDataFound = this.parse_ac_template( current_ac_data[0] );
this.acDataFoundIsBad = false;
} else {
this.viafCurrentDataDiv.html('<span class="error">Plusieurs modèles {{Autorité}} figurent sur cette page :</span><br>')
this.acDataFound = true;
this.acDataFoundIsBad = true;
for (i in current_ac_data){
this.viafCurrentDataDiv.append('<tt style="margin-left:1em" id="current_authority_control_data">' + current_ac_data[i] + '</tt><br>');
}
}
}
VIAFDataGrabber.prototype.parse_ac_template = function(template){
//parse a string holding a AC template into the AC array
var i = 0;
var parameter = ''
var array = {};
while(template[i] != '|'){ //get past the {{template name|
i = i+1;
}
while(1){
if (i == template.length){ //somehow we have overstepped the end of the template - maybe it was incomplete
break;
}
i = i + 1;
if (template[i] != '|' && template[i] != '}'){
parameter = parameter + template[i];
} else { //we have completed a parameter
var myRegexp = /([^=]+)\s*=\s*(.*)/g; //look for parameter = value
var match = myRegexp.exec(parameter);
if (match != null){
array[match[1]] = match[2]
}
if (template[i] == '}'){ //end of the template
break;
}
parameter = '';
}
}
return array
}
VIAFDataGrabber.prototype.add_VIAF_button = function(){
var btn_id = 'tb-viaf-authority-control'
var portletLink = mw.util.addPortletLink('p-tb', '#', 'Ajouter des notices d’autorité', btn_id, 'Ajouter des notices d’autorité à partir du VIAF');
// Bind click handler
$( '#' + btn_id ).click( $.proxy( this.add_VIAF_pane, this ) );
}
VIAFDataGrabber.prototype.display_query_results = function(results){
if (results['result'] == null){
this.viafResultsDiv.html('Aucun résultat trouvé pour "'+results['query']+'"');
} else {
var viafids = []; //list of ids to prevent dupes
var results_list = $('<ul id="viaf-results-list" style="list-style: none;"><ul>')
var count = 0;
for (i in results['result']){
if ($.inArray(results['result'][i]['viafid'], viafids) == -1 ){ //fliter out duplicate VIAF ids
viafids.push(results['result'][i]['viafid']);
results_list.append(this.build_list_entry(results['result'][i]));
}
count++;
}
this.viafResultsDiv.html('').append(results_list);
if (count >= this.viafAutosuggestMaxResults ){
var warning = $("<span style='font-style:italic' id='viaf-warn-further-results'>D’autres résultats peuvent être présents dans le VIAF. Voir <a href='" + this.construct_VIAF_search_URL( $('#viaf_query_input').val() ) + "'>la page de recherche du VIAF</a>.</span>");
this.viafResultsDiv.append(warning);
}
}
}
VIAFDataGrabber.prototype.build_list_entry = function(result){
var myself = this;
var entry = $('<li></li>');
var use_id = $('<div class="viaf-entry-icon"></div>');
use_id.click( function(){
if (entry.hasClass('selected')){
entry.removeClass('selected');
myself.remove_data();
} else {
$.ajax({
url: 'http://creatorlinks.wmflabs.org/viafLinks.php',
data: {
format: 'json',
id: result['viafid'],
},
dataType: 'jsonp',
success: function( data ) {
if( data.links ) {
myself.add_viaf_data( data );
myself.viafResultsDiv.find('li').removeClass('selected'); //remove other entries' bolding
entry.addClass('selected'); //add it to this one
} else {
alert( 'Identifiant VIAF invalide.' );
}
},
error: function( xhr ) {
alert( 'Erreur de communication avec creatorlinks.wmflabs.org : la requête a échoué.' );
}
});
}
});
entry.append(use_id, ' VIAF ID: ', '<a class="viaf-id-link" href="http://viaf.org/viaf/' + result['viafid'] + '">' + result['viafid'] + '</a> ', result['term']);
return entry;
}
VIAFDataGrabber.prototype.remove_data = function(){
//remove any result selected
this.viafProposedDataDiv.empty();
this.viafProposedDataDiv.empty();
this.merge_authority_data(null);
}
VIAFDataGrabber.prototype.add_viaf_data = function( result ){
// adds data from a viaf json result to the AC data already present
if (!this.pageDataFound){
this.viafCurrentDataDiv.html('<span class="error">La syntaxe wiki de la page ne peut être chargée. Veuillez réessayer plus tard.</span>');
return;
}
if (this.acDataFoundIsBad){
this.viafCurrentDataDiv.append('<span class="error">Les notices d’autorité de la page ne peuvent être fusionnées avec les nouvelle. Veuillez supprimer les modèles en doublon et réessayer.</span>');
return;
}
//page data is loaded, and it is OK, let's merge the data!
this.merge_authority_data(result);
}
VIAFDataGrabber.prototype.construct_ac_template = function(data){
var text = '{{Autorité'
for (field in data){
if ($.inArray(field, this.template_parameters_allowed) > -1 ){
text += '|' + field + '=' + data[field];
}
}
text = text + '}}';
return text;
}
VIAFDataGrabber.prototype.merge_authority_data = function(result){
//Merge authority data from a VIAF result with any existing data
//construct an array of new data
new_data = {};
if( result && result.links ) {
for (field in result.links ) {
var id = field.toUpperCase();
if ( $.inArray( id, this.template_parameters_allowed ) > -1 ){ //if the parameter is allowed, get the WS template parameter and save it
var value = result.links[field];
var bnfRegex = /^cb(.*)$/;
if( id == 'BNF' && bnfRegex.test( value ) ) {
new_data[id] = bnfRegex.exec( value )[1];
} else {
new_data[id] = result.links[field];
}
}
}
}
this.added_fields = {}; //fields add the existing data
this.conflicted_fields = {}; //fields that conflict and need approval
this.pending_fields = {}; //fields that don't conflict but won't be added
for (field in new_data){
if (this.acDataFound && field in this.acDataFound){
if (this.acDataFound[field] == new_data[field]){ //duplicate field, ignore
continue;
}
console.log('Conflit sur la notice : ' + field + '. Notices présentes : "' + this.acDataFound[field] + '" Nouvelles notices : "' + new_data[field] + '"' );
this.conflicted_fields[field] = new_data[field];
} else {
this.added_fields[field] = new_data[field];
}
}
this.provisional_data = Object.assign({}, this.acDataFound);
for (field in this.added_fields){
if (!(field in this.provisional_data)){ //add any new data by default
this.provisional_data[field] = this.added_fields[field]
}
}
this.show_suggestions();
}
VIAFDataGrabber.prototype.show_suggestions = function(){
var myself = this;
this.viafSaveACDiv.css('display','none');
if (!('VIAF' in this.provisional_data)){ //we don't have a selected item, clear out and get out
this.viafProposedDataDiv.empty();
return;
}
if ($.isEmptyObject(this.added_fields) && $.isEmptyObject(this.pending_fields) && $.isEmptyObject(this.conflicted_fields)){
this.viafProposedDataDiv.html('Aucune notice d’autorité à ajouter ' + this.provisional_data['VIAF'] + '.');
} else {
if ($.isEmptyObject(this.added_fields) && $.isEmptyObject(this.provisional_data) ){
this.viafProposedDataDiv.html('Aucune notice d’autorité sélectionnée.<br>');
} else {
template = this.construct_ac_template(this.provisional_data)
this.viafProposedDataDiv.html('Modèle proposé :<br><tt id="viaf_raw_proposed_data">' +template+ '</tt><br>');
var renderedTemplateHTML = $('<div id="viaf-rendered-template"></div>');
this.viafProposedDataDiv.append(renderedTemplateHTML);
//render the template and display it
$.ajax({
url: mw.util.wikiScript( 'api' ),
data: {
format: 'json',
action: 'parse',
prop: 'text',
title: mw.config.get( 'wgPageName' ),
text: template
},
dataType: 'json',
success: function( data ) {
renderedTemplateHTML.append( $(data['parse']['text']['*']));
},
error: function( xhr ) {
alert( 'Erreur de rendu.' );
}
});
}
var added_list = $('<ul class="viaf-changes-list"></ul>')
var pending_list = $('<ul class="viaf-changes-list"></ul>')
var conflict_list = $('<ul class="viaf-changes-list"></ul>')
var list_item, link;
for (field in this.added_fields){
list_item = $( '<li>Notice ajoutée : ' + field + ': ' + this.added_fields[field] + '. </li>')
link = $('<a href="#">Retirer cette notice.</a>');
link.bind('click', {field: field}, function(e){
myself.remove_added(e.data.field)
return false;
});
added_list.append(list_item.append(link));
}
for (field in this.pending_fields){
list_item = $( '<li>Pending field: ' + field + ': ' + this.pending_fields[field] + '. </li>')
link = $('<a href="#">Add this value.</a>');
link.bind('click', {field: field}, function(e){
myself.add_removed(e.data.field)
return false;
});
pending_list.append(list_item.append(link));
}
for (field in this.conflicted_fields){
list_item = $( '<li>Conflit sur la notice : ' + field + '. Notice présente : ' + this.provisional_data[field] + '; Notice en conflit : ' + this.conflicted_fields[field] + '. </li>')
link = $('<a href="#">Intervertir les valeurs.</a>');
link.bind('click', {field: field}, function(e){
myself.approve_conflict(e.data.field)
return false;
});
conflict_list.append(list_item.append(link));
}
//show whichever list have items
if (!$.isEmptyObject(this.added_fields)){ this.viafProposedDataDiv.append('Modifications effectuées :', added_list); }
if (!$.isEmptyObject(this.pending_fields)){ this.viafProposedDataDiv.append('Notices disponibles :', pending_list);}
if (!$.isEmptyObject(this.conflicted_fields)){this.viafProposedDataDiv.append('Conflits :', conflict_list);}
if ($('#viaf_raw_proposed_data').length > 0 && $('#viaf_raw_proposed_data').text() != $('#current_authority_control_data').text()){ //if we changed anything
this.viafSaveACDiv.css('display','');
} else {
this.viafSaveACDiv.css('display','none');
}
}
}
VIAFDataGrabber.prototype.approve_conflict = function(field){
var temp = this.provisional_data[field];
this.provisional_data[field] = this.conflicted_fields[field];
this.conflicted_fields[field] = temp;
this.show_suggestions(); //update the suggestions
}
VIAFDataGrabber.prototype.remove_added = function(field){
this.pending_fields[field] = this.added_fields[field];
delete this.added_fields[field];
delete this.provisional_data[field];
this.show_suggestions(); //update the suggestions
}
VIAFDataGrabber.prototype.add_removed = function(field){
this.added_fields[field] = this.pending_fields[field];
this.provisional_data[field] = this.pending_fields[field];
delete this.pending_fields[field];
this.show_suggestions(); //update the suggestions
}
VIAFDataGrabber.prototype.save_ac_data = function(){
if ( mw.config.get( 'wgAction' ) == 'view' ){ //update in the background
this.get_raw_page(mw.config.get('wgPageName'), this.update_page);
} else if ($.inArray( mw.config.get( 'wgAction' ), ['submit', 'edit'] ) > -1 ){
var text = $('#wpTextbox1').val();
var text = this.add_ac_template_to_text(text);
$('#wpTextbox1').val(text);
$('#wpTextbox1').css({'outline':'2px solid green'});
setTimeout(function() {
$('#wpTextbox1').css({'outline':''});
}, 2000);
}
}
VIAFDataGrabber.prototype.add_ac_template_to_text = function(text){
//splice the template into the text, overwriting any current template
var raw_template = $('#viaf_raw_proposed_data').text();
var match = this.ac_template_re.exec(text);
if (match == null){ //there is no existing template
var foot = this.footer_re.exec(text)
if (foot != null){
text = text.replace(this.footer_re, foot[1] + '\n' + raw_template + '\n')
} else {
text = text + '\n\n' + raw_template;
}
} else {
text = text.replace(this.ac_template_re, raw_template); //update the text in the text box
}
return text;
}
VIAFDataGrabber.prototype.update_page = function(data){
var text = this.add_ac_template_to_text(data);
this.save_page( mw.config.get( 'wgPageName' ), text, 'Ajout/modification de [[Modèle:Autorité|notices d’autorité]] à partir du [[VIAF]].' );
}
VIAFDataGrabber.prototype.get_raw_page = function(pagetitle, callback){
var myself = this;
//get the current page text
$.ajax({
url: mw.util.wikiScript( 'index' ),
data: {
action: 'raw',
title: pagetitle,
},
cache:false,
success:function(data){
$.proxy(callback, myself)(data);
},
error:function(jqXHR, textStatus, errorThrown){
alert('Le texte de la page [[' + pagetitle + ']] ne peut être chargé');
}
});
}
VIAFDataGrabber.prototype.save_page = function(title, content, summary, go_to_diff){
var myself = this;
$.ajax({
url: mw.util.wikiScript( 'api' ),
data: {
format: 'json',
action: 'edit',
title: title,
summary: summary,
text: content,
token: mw.user.tokens.get( 'csrfToken' )
},
dataType: 'json',
type: 'POST',
success: function( data ) {
if ( data && data.edit && data.edit.result == 'Success' ) {
window.location = mw.util.wikiScript( 'index' ) + '?' + $.param({ title: mw.config.get( 'wgPageName' ), diff:data.edit.newrevid , oldid:data.edit.oldrevid });
} else if ( data && data.error ) {
alert( 'Erreur : l’API a retourné un code d’erreur "' + data.error.code + '": ' + data.error.info );
} else {
alert( 'Erreur : l’API a retourné un résultat inconnu.' );
}
},
error: function( xhr ) {
alert( 'Erreur : la requête a échoué.' );
}
});
}
jQuery( document ).ready( function() {
if ($.inArray( mw.config.get( 'wgNamespaceNumber' ), [0, 2] ) > -1 ){ //only trigger in sensible namespaces
VIAFDataGrabberInstance = new VIAFDataGrabber();
}
});
});