User:RockyMasum/common.js common.js page

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search

/* (c) 2019 by User:Magnus Manske. GPLv3 or later.

This tool lets you quickly add statements for Structured Data on Commons (SDC) to (selected) files on galleries, category pages, and serach results.

Demo video: https://www.youtube.com/watch?v=RIjXRJNcbL0

Demo video 2 (item creation/Wikidata Infobox): https://www.youtube.com/watch?v=vvSimZSD_IU

To use this script, add it to your common.js page, like so: importScript('User:Magnus Manske/sdc_tool.js') ;

Activate by clicking on the "SDC" link in the box in the lower-right corner, or by pressing S with (Alt/Ctrl/whatever your browser uses).

  • /

$.when(mw.loader.using(['oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'mediawiki.ForeignApi']), $.ready).done ( function () {

// Dialog function SDCdialog( config ) { SDCdialog.super.call( this, config ); } OO.inheritClass( SDCdialog, OO.ui.Dialog );

// Specify a name for .addWindows() SDCdialog.static.name = 'SDCdialog'; // Specify a title statically (or, alternatively, with data passed to the opening() method). SDCdialog.static.title = 'Find a target item for SDC';

SDCdialog.prototype.update_results = function () { let html = "" ; $.each ( this.results , function ( result_id , v ) {

html += "

" ; html += "
<input style='color:green;font-size:1.5em;' class='sdc_dialog_cegision_button' result='" ; html += result_id+"' type='button' value='✓' />
" ; html += "
" ; html += "
[<a href='https://www.wikidata.org/wiki/"+v.q+"' target='_blank'>"+v.q + "</a>]
" ; html += "
" ; html += "
" ; html += "

" ;

} ) ;

if ( html === ) html = '

No results found on Wikidata

' ;

$('#sdc_dialog_results').html(html); $.each ( this.results , function ( result_id , v ) { $('#sdc_dialog_results b.result_label[result="'+result_id+'"]').text(v.label); $('#sdc_dialog_results div.result_description[result="'+result_id+'"]').text(v.description); } ) ; let me = this ; $('.sdc_dialog_cegision_button').click(function(){ let result_id = $(this).attr('result')*1 ; console.log(me.results); let item = me.results[result_id] ; me.on_decision(item);

}); }

SDCdialog.prototype.get_time_claim_for_year = function ( property , year ) { let value = {

           "time": "+"+year+"-01-01T00:00:00Z",
           "timezone": 0,
           "before": 0,
           "after": 0,
           "precision": 9,
           "calendarmodel": "http://www.wikidata.org/entity/Q1985727"
       } ;

let claim = {mainsnak:{snaktype:"value",property:property,datavalue:{value:value,type:'time'}},type:"statement",rank:"normal"} ; return claim ; }

SDCdialog.prototype.create_new_item_for_category = function () { let me = this ; let label = mw.config.values.wgTitle ; let data = { claims:[{mainsnak:{snaktype:"value",property:'P373',datavalue:{value:label,type:'string'}},type:"statement",rank:"normal"}], labels:{en:{language:"en",value:label}} } ; let summary = 'SDC: created item based on Commons category ' + label ;

// If the page exists, add sitelink if ( mw.config.values.wgArticleId !== 0 ) { data.sitelinks = {"commonswiki":{site:"commonswiki",title:mw.config.values.wgPageName}} ; }

let is_human = false ; let gender =  ; $.each ( mw.config.values.wgCategories , function ( dummy , category ) { let m = category.match ( /^(\d{3,4}) births$/ ) ; if ( m !== null ) { data.claims.push ( me.get_time_claim_for_year ( 'P569' , m[1] ) ) ; is_human = true ; } m = category.match ( /^(\d{3,4}) deaths$/ ) ; if ( m !== null ) { data.claims.push ( me.get_time_claim_for_year ( 'P570' , m[1] ) ) ; is_human = true ; } if ( category.match ( /^Female / ) !== null ) gender = 'Q6581072' ; if ( category.match ( /^Male / ) !== null ) gender = 'Q6581097' ; } ) ; if ( gender !== ) { let value = {'entity-type':'item',id:gender} ; let claim = {mainsnak:{snaktype:"value",property:'P21',datavalue:{value:value,type:'wikibase-entityid'}},type:"statement",rank:"normal"} ; data.claims.push ( claim ) ; is_human = true ; } if ( is_human ) { let value = {'entity-type':'item',id:'Q5'} ; let human = {mainsnak:{snaktype:"value",property:'P31',datavalue:{value:value,type:'wikibase-entityid'}},type:"statement",rank:"normal"} ; data.claims.push ( human ) ; }

sdc.get_wikidata_token ( function ( token ) { let params = { action:'wbeditentity', new:'item', data:JSON.stringify(data), token:token, summary:summary, format:'json' } ; let api = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' ); api.post(params).done(function(d) { if ( d.success != 1 ) { console.log ( d ) ; alert ( "Something went wrong with item creation, see JS console" ) ; return ; } let q = d.entity.id ; let item = {q:q,label:label,description:} ; me.on_decision(item); } ) ; } ); }

/* // Obsolete, but keeping code around in case of mw issues... SDCdialog.prototype.get_qs_creation = function () { let me = this ; let commands = [ "CREATE" ] ; commands.push ( "LAST\tLen\t\""+mw.config.values.wgTitle+"\"" ) ; commands.push ( "LAST\tP373\t\""+mw.config.values.wgTitle+"\"" ) ;

let is_human = false ; $.each ( mw.config.values.wgCategories , function ( dummy , category ) { let m = category.match ( /^(\d{3,4}) births$/ ) ; if ( m !== null ) { commands.push ( "LAST\tP569\t+"+m[1]+"-01-01T00:00:00Z/9") ; is_human = true ; } m = category.match ( /^(\d{3,4}) deaths$/ ) ; if ( m !== null ) { commands.push ( "LAST\tP570\t+"+m[1]+"-01-01T00:00:00Z/9") ; is_human = true ; } } ) ; if ( is_human ) commands.push ( "LAST\tP31\tQ5") ; return commands.join("\n") ; } */

// Customize the initialize() function: This is where to add content to the dialog body and set up event handlers. SDCdialog.prototype.initialize = function () { // Call the parent method. SDCdialog.super.prototype.initialize.call( this ); // Create and append a layout and some content. this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );

let html = "

"; html += "

Enter a search query for Wikidata items

" ; html += "

<input type='text' id='sdc_dialog_query' style='width:100%' placeholder='search query' />

" ; html += "

" ;

if ( mw.config.values.wgNamespaceNumber == 14 ) {

html += "

or

" ;

}

html += "

" ;

this.content.$element.append( html ); this.$body.append( this.content.$element );

// Create a new item based on the category if ( mw.config.values.wgNamespaceNumber == 14 ) { //let qs = this.get_qs_creation() ; //console.log(qs); //let url = "https://tools.wmflabs.org/quickstatements/api.php?action=import&format=v1&temporary=1&openpage=1&data="+encodeURIComponent(qs) ; //let button_create_new_item = new OO.ui.ButtonWidget( { label: 'create new item based on this category in QuickStatements',href:url,target:'_blank' } ) ; let button_create_new_item = new OO.ui.ButtonWidget( { label: 'create new item based on this category',href:'#' } ) ; $('#create_new_item_container ').html(button_create_new_item.$element); $('#create_new_item_container a.oo-ui-buttonElement-button').click(function(){me.create_new_item_for_category();}); }

this.results = [] ;

let me = this ; me.query_counter = 0 ; me.last_query =  ; $('#sdc_dialog_query').keyup(function(){ me.run_query() ; }); };

SDCdialog.prototype.run_query = function () { let me = this ; let query = $('#sdc_dialog_query').val(); me.results = [] ; if ( query== || query==me.last_query ) return ; me.last_query = query ; me.query_counter++ ; let qc = me.query_counter ; var wgUserLanguage = mw.config.get('wgUserLanguage') $.getJSON('https://www.wikidata.org/w/api.php?callback=?',{ action:'wbsearchentities', search:query, language:wgUserLanguage, limit:50, type:'item', format:'json' },function(d){ if ( me.query_counter != qc ) return ; // New query was started while this one was running $(d.search).each(function(k,v){ me.results.push({q:v.id,label:v.label,description:v.description||}); }); me.update_results(); }); }

// Override the getBodyHeight() method to specify a custom height (or don't to use the automatically generated height). SDCdialog.prototype.getBodyHeight = function () { return this.content.$element.outerHeight( true ); };

var sdc = {

// Properties allowed to set; must be of 'Wikidata item' type properties : { P180 : 'depicts' , P921 : 'main subject', P195 : 'collection' , P793 : 'significant event' , P1071 : 'location of creation' , P7108 : 'location of the point of view' , P5961 : 'depicted part' , P6243 : 'digital representation of', P8058 : 'symbol of' , } ,

exclude_files:['Gtk-dialog-info-14px.png','Reasonator_logo_proposal_no_background.png'], is_stopped : true, active : false, dialog: new SDCdialog( { size: 'medium' } ), windowManager: new OO.ui.WindowManager(), mid_cache:[], mid2file:[], media_items:[], wikidata_items_to_load:[], wikidata_item_labels:[], target_item : { q:, label:, description: },

init : function () { if ( mw.config.values.wgNamespaceNumber == 6 ) return ; // Not for single images if ( $('a.image').length == 0 ) return ; // No possible thumbnails let me = this ; me.dialog.on_decision = me.set_target_item; $( document.body ).append( me.windowManager.$element ); me.windowManager.addWindows( [ me.dialog ] );

me.show_main_element(); me.try_guess_main_item(); //me.toggle_main(); // Auto-open } ,

try_guess_main_item : function () { let me = this ; if ( typeof wgWikibaseItemId == 'undefined' || wgWikibaseItemId == ) return ;

me.try_set_main_item(wgWikibaseItemId); } ,

try_set_main_item : function (q) { let me = this ; me.wikidata_items_to_load=[q] ; me.load_wikidata_items(function(){ $.getJSON("https://www.wikidata.org/w/api.php?callback=?&action=wbgetentities&format=json&ids="+q,function(d){ let item = (d.entities||{})[q] ; if ( typeof item == 'undefined' ) return ; if ( me.does_item_have_property_target(item,'P31','Q4167836') ) { let statement = ((item.claims||item.statements||{}).P301||[])[0] ; if ( typeof statement == 'undefined' ) return ; // No "category's main topic" let target_id = (((statement.mainsnak||{}).datavalue||{}).value||{}).id ; if ( typeof target_id != 'undefined' && target_id != q ) me.try_set_main_item(target_id); return ; } let label = $(me.wikidata_item_labels[q]).text(); me.set_target_item({q:q,label:label,description:}); }); }); } ,

update_main_position : function () { let bottom = $('#cat_a_lot_toggle').length>0 ? 30 : 0 ; $('#sdc_main').css({bottom:bottom+'px'}) } ,

show_action_button : function () { let me = this ; var action_button = new OO.ui.ButtonWidget( { label: 'Set '+me.get_property()+' to '+me.target_item.q, href: '#', flags: 'progressive' } ); $('#sdc_action_button_container').html(action_button.$element); $('#sdc_action_button_container a.oo-ui-buttonElement-button').click(function(){ if ( $('input.sdc_checkbox:checked').length == 0 ) { alert("No files selected"); return false ; } me.is_stopped = false ; me.show_action_stop_button(); me.edit_next(); return false; }); } ,

show_wikidata_infobox_button : function () { let me = this ; if ( mw.config.values.wgNamespaceNumber != 14 ) return ; // Categories only if ( $('#wdinfobox').length > 0 ) return ; // Already has infobox var wikidata_infobox_button = new OO.ui.ButtonWidget( { label: 'Add Wikidata Infobox for '+me.target_item.q, href: '#', flags: 'progressive' } ); $('#sdc_add_wikidata_infobox_button').html(wikidata_infobox_button.$element); $('#sdc_add_wikidata_infobox_button a.oo-ui-buttonElement-button').click(function(){ //let wikitext = 'The ID "'+ME.TARGET_ITEM.Q+'" is unknown to the system. Please use a valid entity ID.\n' ; // old syntax

let wikitext = '

NO WIKIDATA ID FOUND!

Search for RockyMasum/common.js common.js page on Wikidata

Create new Wikidata item
Upload media

\n' ;

let summary = 'SDC: added '+wikitext ; $('#sdc_add_wikidata_infobox_button').html('Editing...'); me.get_token ( function ( token ) { let params = { action:'edit', title:mw.config.values.wgPageName, prependtext:wikitext, token:token, summary:summary, format:'json' } ; $.post('/w/api.php',params,function(d){ if ( (d.edit||{}).result != 'Success' ) { console.log(d); alert ( "Something went wrong with the edit, see JS console" ) ; return ; }

let html = "

"+wikitext+" was added, reload page to show

" ;

$('#bodyContent').prepend(html); $('#sdc_add_wikidata_infobox_button').html(); },'json'); } ); return false; }); } ,

show_action_stop_button : function () { let me = this ; var action_button = new OO.ui.ButtonWidget( { label: 'Stop editing', href: '#', flags: 'destructive' } ); $('#sdc_action_button_container').html(action_button.$element); $('#sdc_action_button_container a.oo-ui-buttonElement-button').click(function(){ me.is_stopped=true; $('#sdc_action_button_container').html("Stopping edits..."); return false; }); } ,

set_prominent_checkbox : function ( state ) { $('#sdc_prominent').prop( "checked", state ); } ,

edit_next : function () { let me = this ; if ( me.is_stopped ) return me.show_action_button(); // User stopped this let cbs = $('input.sdc_checkbox:checked') ; if ( cbs.length == 0 ) { // All done me.set_prominent_checkbox ( false ) ; return me.show_action_button(); }

let cb = $(cbs.get(0)) ; let file = decodeURIComponent(cb.attr('file')) ; if ( typeof file == 'undefined' ) { // All done me.set_prominent_checkbox ( false ) ; return me.show_action_button(); }

me.get_mediainfo_id_for_file ( file , function ( mediainfo_id ) { me.add_item_statement_to_item(mediainfo_id,me.get_property(),me.target_item.q,me.is_prominent(),function(ok){ // TODO check ok cb.attr('checked', false); cb.prop('checked', false); me.edit_next(); //delete me.media_items[mediainfo_id] ; me.load_media_items([mediainfo_id]); }); } ) ;

} ,

is_prominent : function() { return $('#sdc_prominent').is(":checked"); } ,

// `file` WITHOUT File: prefix! get_mediainfo_id_for_file : function ( file , callback ) { let me = this ; if ( typeof me.mid_cache[file] != 'undefined') { return callback ( me.mid_cache[file] ) ; } $.get('/w/api.php',{ action:'query', prop:'info', titles:"File:"+file, format:'json' },function(d){ let mid = -1 ; $.each ( d.query.pages , function ( page_id , page_info ) { mid = page_id } ) ; if ( mid == -1 ) mid =  ; else mid = 'M'+mid ; me.mid_cache[file] = mid ; callback(mid); },'json'); } ,

get_wikidata_token : function ( callback ) { let params = { action : 'query' , meta : 'tokens' , format : 'json' } ; let api = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php' ); api.post(params).done(function(d) { callback(d.query.tokens.csrftoken); } ) ; } ,

get_token : function ( callback ) { $.post ( '/w/api.php' , { action : 'query' , meta : 'tokens' , format : 'json' , } , function ( d ) { callback(d.query.tokens.csrftoken); } ) ; } ,

does_item_have_property_target : function ( item , property , target_item_id ) { let statement_present = false ; $.each ( ((item.statements||item.claims||{})[property]||[]) , function ( dummy , statement ) { if ( ((((statement||{}).mainsnak||{}).datavalue||{}).value||{}).id == target_item_id ) { statement_present = true ; } } ) ; return statement_present ; } ,

add_item_statement_to_item : function ( item_id , property , target_item_id , prominent , callback ) { let me = this ; let value = {'entity-type':'item',id:target_item_id} ; let data = {claims:[{mainsnak:{snaktype:"value",property:property,datavalue:{value:value,type:'wikibase-entityid'}},type:"statement",rank:"normal"}]} ; let summary = 'SDC: added d:Special:EntityPage/'+property+' => d:Special:EntityPage/'+target_item_id+'' ; if ( prominent ) { data.claims[0].rank = 'preferred' ; summary += ', prominent' ; }

// Check if statement already present if ( typeof me.media_items[item_id] != 'undefined' ) { if ( me.does_item_have_property_target(me.media_items[item_id],property,target_item_id) ) return callback(true); }

me.get_token ( function ( token ) { let params = { action:'wbeditentity', id:item_id, data:JSON.stringify(data), token:token, summary:summary, format:'json' } ; $.post('/w/api.php',params,function(d){ callback(true); },'json'); } ); } ,

set_target_item : function ( item ) { let me = sdc ; me.target_item = item ;

let html = "" ;

html += "Target item: [<a href='https://www.wikidata.org/wiki/"+item.q+"' target='_blank'>"+item.q+"</a>]

"; html = "

"+html+"

" ;

$('#sdc_target_item_display').html(html).show(); $('#sdc_target_item_label').text(item.label);

me.show_action_button(); me.show_wikidata_infobox_button();

me.update_main_position(); me.windowManager.closeWindow( me.dialog ); } ,

get_property : function () { return $('#sdc_property').val(); } ,

open_dialog : function () { this.windowManager.openWindow( this.dialog ); if ( $('#sdc_dialog_query').val() == ) { $('#sdc_dialog_query').val(mw.config.values.wgTitle) ; $('#sdc_dialog_query').keyup(); } setTimeout(function(){$('#sdc_dialog_query').focus()},500); } ,

show_main_element : function () { let me = this ;

let html = "

" ;

html += "<a href='#' id='sdc_main_button' accesskey='s' title='Structured Data on Commons tagger [shortcut:S]'>SDC</a>" ;

html += "" ; html += "

" ;

$('body').append(html); $('#sdc_main_button').click(function(){ me.toggle_main(); return false; });

let button_all = new OO.ui.ButtonWidget( { label: 'All',href: '#' } ) ; let button_toggle = new OO.ui.ButtonWidget( { label: 'Toggle',href: '#' } ) ; let button_none = new OO.ui.ButtonWidget( { label: 'None',href: '#' } ) ; $('#sdc_cb_all ').html(button_all.$element); $('#sdc_cb_toggle').html(button_toggle.$element); $('#sdc_cb_none').html(button_none.$element); $('#sdc_cb_all a.oo-ui-buttonElement-button').click(function(){ $('input.sdc_checkbox').attr('checked', true); return false; }); $('#sdc_cb_toggle a.oo-ui-buttonElement-button').click(function(){ $('input.sdc_checkbox').click(); return false; }); $('#sdc_cb_none a.oo-ui-buttonElement-button').click(function(){ $('input.sdc_checkbox').attr('checked', false); return false; });

let button_sti = new OO.ui.ButtonWidget( { label: 'Set target item',href: '#' } ) ; $('#sdc_target_item_button ').html(button_sti.$element); $('#sdc_target_item_button a.oo-ui-buttonElement-button').click(function(){me.open_dialog(me);});

$('#sdc_property').change(function(){me.show_action_button()});

me.update_main_position(); setTimeout(me.update_main_position,200); } ,

toggle_main : function () { this.active = !this.active ; if ( this.active ) { this.show_checkboxes(); $('#sdc_options').show(); } else { $('div.sdc_checkbox_container').remove(); $('#sdc_options').hide(); } this.update_main_position(); } ,

cache_file_media_ids : function ( files ) { let me = this ; let chunks = [ [] ] ; let MAX_CHUNK_SIZE = 50 ; $.each ( files , function ( dummy , file ) { if ( chunks[chunks.length-1].length < MAX_CHUNK_SIZE ) { chunks[chunks.length-1].push ( file ) ; } else { chunks.push ( [ file ] ) ; } } ) ; me.wikidata_items_to_load = [] ; $.each ( chunks , function ( dummy , chunk ) { me.cache_file_media_ids_chunk(chunk) ; } ) ; } ,

cache_file_media_ids_chunk : function ( files ) { let me = this ; let params = { action:'query', prop:'info', titles:"File:"+files.join("|File:"), format:'json' } ; $.post('/w/api.php',params,function(d){ let to_load = [] ; $.each ( d.query.pages , function ( page_id , page_info ) { if ( page_id == -1 ) return ; // Paranoia let mid = 'M'+page_id ; let file = page_info.title.replace(/^File:/,).replace(/ /g,'_'); me.mid_cache[file] = mid ; me.mid2file[mid] = file ; to_load.push ( mid ) ; } ) ; me.load_media_items(to_load); },'json'); } ,

load_media_items : function ( mids ) { if ( mids.length == 0 ) return ; let me = this ; let params = { action:'wbgetentities', ids:mids.join('|'), format:'json' } ; $.post('/w/api.php',params,function(d){ $.each ( d.entities , function ( mid , mi ) { me.media_items[mid] = mi ; me.update_file_sdc(mid); } ) ; me.load_wikidata_items(); },'json'); } ,

load_wikidata_items : function ( callback ) { let me = this ; let to_load = [] ; // Should never be more than 50 $.each ( me.wikidata_items_to_load , function ( dummy , q ) { if ( typeof me.wikidata_item_labels[q] != 'undefined' ) { me.update_q_labels(q); return ; } if ( $.inArray(q,to_load) !== -1 ) return ; to_load.push(q) ; } ) ; me.wikidata_items_to_load = [] ; if ( to_load.length == 0 ) return ; $.getJSON('https://www.wikidata.org/w/api.php?callback=?',{ action:'wbformatentities', ids:to_load.join('|'), format:'json' },function(d){ $.each ( d.wbformatentities , function ( q , html ) { me.wikidata_item_labels[q] = html.replace('<a ','<a target="_blank" ') ; me.update_q_labels(q); } ) ; if ( typeof callback != 'undefined' ) callback() ; }); } ,

update_q_labels : function ( q ) { let me = this ; $('td.q_to_load[q="'+q.replace(/'/g, "'")+'"]').removeClass('q_to_load').html(me.wikidata_item_labels[q]); } ,

get_wikidata_item_label_td : function ( q , prominent ) { let me = this ; let style = 'vertical-align:top;' ; if ( prominent ) style += 'font-weight:bold;' ; if ( typeof me.wikidata_item_labels[q] == 'undefined' ) {

return ""+q+"" ;

} else {

return ""+me.wikidata_item_labels[q]+"" ;

} } ,

update_file_sdc : function ( mid ) { let me = this ; let file = me.mid2file[mid] ; if ( typeof file == 'undefined' ) return ; let mi = me.media_items[mid] ; if ( typeof mi == 'undefined' ) return ; let out = [] ; $.each ( (mi.statements||{}) , function ( property , statements ) { $.each ( statements , function ( dummy , statement ) { if ( ((statement.mainsnak||{}).datavalue||{}).type != 'wikibase-entityid' ) return ; me.wikidata_items_to_load.push(property); let wd_item_id = statement.mainsnak.datavalue.value.id ; me.wikidata_items_to_load.push(wd_item_id); out.push({property:property,target:wd_item_id,prominent:statement.rank=='preferred'}); } ) ; } ) ;

let h =  ; if ( out.length == 0 ) {

let html = "

" ; html += "
No SDC
" ; html += "

" ;

h = $(html); } else {

let html = "

" ; html += "<tbody>" ; $.each ( out , function ( dummy , row ) { html += "" ; html += me.get_wikidata_item_label_td(row.property,false) ; html += me.get_wikidata_item_label_td(row.target,row.prominent) ; html += "" ; } ) ; html += "</tbody>

" ;

h = $(html); h.find('td').css({padding:'1px','text-align':'left'}); }

let element = $($('input.sdc_checkbox[file="'+me.sanitize_file_attribute(file)+'"]').parent()) ; $('div.sdc_statements[mid="'+mid+'"').remove(); element.after(h); } ,

sanitize_file_attribute : function ( file ) { return encodeURIComponent(file).replace(/'/g, "'") ; } ,

show_checkboxes : function () { let me = this ; let files = [] ; $('a.image').each(function(num,a){ let file = decodeURIComponent($(a).attr('href')).replace(/^.+\/File:/,) ; if ( $.inArray(file,me.exclude_files) > -1 ) return ; // Bad file! if ( $(a).parents('#wdinfobox').length > 0 ) return ; // In infobox files.push(file);

let html = "

" ; html += "
<input type='checkbox' class='sdc_checkbox' file='"+me.sanitize_file_attribute(file)+"' />
" ; html += "

" ;

$(a).after(html); }); me.cache_file_media_ids(files); }

} ;

sdc.init(); });