Jump to content
Wikipedia The Free Encyclopedia

User:Polygnotus/Scripts/SourceTable3.js

From Wikipedia, the free encyclopedia
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
Documentation for this user script can be added at User:Polygnotus/Scripts/SourceTable3.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
 // AfD Source Assessment Tool

 //Features:
 //Continue where you left off
 //autopopulate the refs

 /*
 2add:
 - give eachs ref an archive.org link by default if none exists?
 -numbering the wikitable
 - bug: comments aren't displayed yet

 */

 /*

 [[User:Polygnotus/Scripts/SourceTable]]

 [[Wikipedia:User_scripts/Requests#Source_assessing]] 
  [[Template:Source assess table]] used in [[Wikipedia:Articles for deletion/Nambiar Builders]] is a lot like [[User:Polygnotus/Scripts/SourceTable]]. 

  I should also check out [[User:Awesome Aasim/xfdvote]]. See also [[Wikipedia:Notability_(organizations_and_companies)#How_to_apply_the_criteria]] -- [[Wikipedia_talk:WikiProject_Articles_for_creation#Source_Assessment_Tables]]

 https://en.wikipedia.org/wiki/Wikipedia:User_scripts/Requests/Archive_10#h-Source_assessing-20241206231600

 There's also {{ORGCRIT assess table}}, which is a variation specific to WP:NCORP (organizations and companies notability criteria).


 */


 // Only run on AfD edit pages
 varcurrentAction=mw.config.get('wgAction');
 if(mw.config.get('wgPageName').startsWith('Wikipedia:Articles_for_deletion/')&&
 (currentAction==='edit'||currentAction==='submit')){
 $(function(){
 console.log('AfD Source Assessment script running...');

 // Add button to page heading
 if($('#firstHeading').length){
 $('<button>')
 .attr('id','assessSourcesButton')
 .text('Assess Sources')
 .css({
 'margin-left':'10px',
 'margin-bottom':'5px',
 'display':'inline-block',
 'vertical-align':'middle',
 'font-size':'15px',
 'padding':'4px 8px'
 })
 .click(function(e){
 e.preventDefault();
 showSourceAssessmentPopup();
 })
 .appendTo('#firstHeading');

 console.log('Assess Sources button added');
 }elseif($('#editform').length){
 $('<button>')
 .attr('id','assessSourcesButton')
 .text('Assess Sources')
 .css({
 'margin':'10px 0',
 'display':'block'
 })
 .click(function(e){
 e.preventDefault();
 showSourceAssessmentPopup();
 })
 .prependTo('#editform');

 console.log('Assess Sources button added to editform');
 }elseif($('.editButtons').length){
 // Fallback for preview pages
 $('<button>')
 .attr('id','assessSourcesButton')
 .text('Assess Sources')
 .css({
 'margin':'10px 0',
 'display':'inline-block',
 'padding':'4px 8px'
 })
 .click(function(e){
 e.preventDefault();
 showSourceAssessmentPopup();
 })
 .prependTo('.editButtons');

 console.log('Assess Sources button added to editButtons');
 }
 });
 }

 // Global state
 varassessmentState={
 sources:[],
 assessments:[]
 };

 functionshowSourceAssessmentPopup(){
 // Extract article name
 varafdPageName=mw.config.get('wgPageName');
 vararticleName=extractArticleName(afdPageName);

 console.log('Loading sources for:',articleName);

 // Always try to load state from existing wikicode in textbox first
 vareditTextarea=document.getElementById('wpTextbox1');
 if(!editTextarea){
 mw.notify('Error: Could not find edit textarea.',{type:'error'});
 return;
 }

 varexistingState=parseExistingAssessment(editTextarea.value);

 if(existingState){
 // Use existing state from textbox
 assessmentState=existingState;
 console.log('Loaded existing state with',existingState.sources.length,'sources');
 console.log('First source assessments:',existingState.assessments[0]);
 if(existingState.assessments.length>1){
 console.log('Second source assessments:',existingState.assessments[1]);
 }
 displayPopup();
 }else{
 // No existing assessment found, fetch article content to extract sources
 console.log('No existing assessment found, fetching article sources...');
 newmw.Api().get({
 action:'query',
 prop:'revisions',
 rvprop:'content',
 titles:articleName,
 formatversion:2
 }).done(function(data){
 try{
 if(!data.query||!data.query.pages||data.query.pages.length===0){
 mw.notify('Error: Could not retrieve article data.',{type:'error'});
 return;
 }

 varpage=data.query.pages[0];
 if(page.missing){
 mw.notify('The article "'+articleName+'" could not be found.',{type:'error'});
 return;
 }

 if(!page.revisions||page.revisions.length===0){
 mw.notify('No revisions found for the article.',{type:'error'});
 return;
 }

 varpageContent=page.revisions[0].content;
 varreferences=extractReferences(pageContent);

 if(references.length===0){
 mw.notify('No references found in the article.',{type:'warning'});
 return;
 }

 // Initialize state
 assessmentState.sources=references;
 assessmentState.assessments=references.map(function(){
 return{
 independent:'',
 reliable:'',
 significant:'',
 comments:''
 };
 });

 displayPopup();
 }catch(error){
 mw.notify('An error occurred: '+error.message,{type:'error'});
 console.error('Error:',error);
 }
 }).fail(function(error){
 mw.notify('Failed to fetch article content.',{type:'error'});
 console.error('API error:',error);
 });
 }
 }

 functiondisplayPopup(){
 // Remove existing popup if present
 $('#sourceAssessmentPopup').remove();

 // Create popup overlay
 varpopup=$('<div>')
 .attr('id','sourceAssessmentPopup')
 .css({
 'position':'fixed',
 'top':'0',
 'left':'0',
 'width':'100%',
 'height':'100%',
 'background':'rgba(0,0,0,0.5)',
 'z-index':'10000',
 'display':'flex',
 'align-items':'center',
 'justify-content':'center',
 'overflow':'auto'
 });

 // Create popup content
 varcontent=$('<div>')
 .css({
 'background':'white',
 'padding':'20px',
 'border-radius':'5px',
 'width':'90%',
 'max-height':'90%',
 'overflow':'auto',
 'position':'relative'
 });

 // Add close button to top right
 varcloseButton=$('<button>')
 .text(×ばつ')
 .css({
 'position':'absolute',
 'top':'10px',
 'right':'10px',
 'border':'none',
 'background':'#f0f0f0',
 'font-size':'24px',
 'width':'30px',
 'height':'30px',
 'border-radius':'50%',
 'cursor':'pointer',
 'line-height':'1',
 'padding':'0'
 })
 .hover(
 function(){$(this).css('background','#e0e0e0');},
 function(){$(this).css('background','#f0f0f0');}
 )
 .click(function(){
 popup.remove();
 });
 content.append(closeButton);

 // Add title
 content.append($('<h2>').text('Source Assessment for WP:GNG').css('margin-top','0'));

 // Create table
 vartable=$('<table>')
 .attr('id','sourceAssessmentTable')
 .css({
 'width':'100%',
 'border-collapse':'collapse',
 'margin':'20px 0'
 });

 // Add header
 varthead=$('<thead>');
 varheaderRow=$('<tr>');
 ['#','Source','Independent','Reliable','Significant Coverage','Count Toward GNG','Comments'].forEach(function(header){
 varth=$('<th>').text(header).css({
 'border':'1px solid #ccc',
 'padding':'8px',
 'background':'#f0f0f0',
 'text-align':'left'
 });

 // Set specific width for Count Toward GNG column
 if(header==='Count Toward GNG'){
 th.css('width','20px');
 }

 headerRow.append(th);
 });
 thead.append(headerRow);
 table.append(thead);

 // Add body
 vartbody=$('<tbody>');
 assessmentState.sources.forEach(function(source,index){
 varrow=createAssessmentRow(source,index);
 tbody.append(row);
 });
 table.append(tbody);

 content.append(table);

 // Add buttons
 varbuttonDiv=$('<div>').css({'text-align':'right','margin-top':'10px'});

 $('<button>')
 .text('Generate Wikicode')
 .css({'margin-right':'10px','padding':'8px 16px'})
 .click(function(){
 generateWikicode();
 })
 .appendTo(buttonDiv);

 $('<button>')
 .text('Close')
 .css({'padding':'8px 16px'})
 .click(function(){
 popup.remove();
 })
 .appendTo(buttonDiv);

 content.append(buttonDiv);
 popup.append(content);
 $('body').append(popup);
 }

 functioncreateAssessmentRow(source,index){
 varassessment=assessmentState.assessments[index];
 varrow=$('<tr>').attr('data-index',index);

 // Number column
 varnumberCell=$('<td>').css({
 'border':'1px solid #ccc',
 'padding':'8px',
 'text-align':'center',
 'font-weight':'bold'
 }).text(index+1);
 row.append(numberCell);

 // Source column
 varsourceCell=$('<td>').css({
 'border':'1px solid #ccc',
 'padding':'8px',
 'max-width':'300px',
 'overflow':'auto'
 }).html(source);
 row.append(sourceCell);

 // Create radio button option boxes for Independent, Reliable, Significant Coverage
 ['independent','reliable','significant'].forEach(function(field){
 varcell=$('<td>').css({
 'border':'1px solid #ccc',
 'padding':'8px'
 });

 varradioGroup=$('<div>').css({'display':'flex','flex-direction':'column','gap':'4px'});

 [
 {value:'yes',text:'Yes'},
 {value:'no',text:'No'},
 {value:'unknown',text:'Unknown'},
 {value:'partial',text:'Partial'}
 ].forEach(function(option){
 varradioId='radio_'+index+'_'+field+'_'+option.value;
 varlabel=$('<label>').css({'display':'flex','align-items':'center','cursor':'pointer'});

 varradio=$('<input>')
 .attr('type','radio')
 .attr('name','radio_'+index+'_'+field)
 .attr('id',radioId)
 .val(option.value)
 .css({'margin-right':'4px'});

 if(assessment[field]===option.value){
 radio.attr('checked','checked');
 }

 radio.change(function(){
 assessmentState.assessments[index][field]=$(this).val().trim();
 updateRowStatus(row,index);
 });

 label.append(radio);
 label.append($('<span>').text(option.text));
 radioGroup.append(label);
 });

 cell.append(radioGroup);
 row.append(cell);
 });

 // Count Toward GNG column
 vargngCell=$('<td>').css({
 'border':'1px solid #ccc',
 'padding':'8px',
 'text-align':'center',
 'width':'20px'
 }).attr('data-gng','');
 row.append(gngCell);

 // Comments column
 varcommentsCell=$('<td>').css({
 'border':'1px solid #ccc',
 'padding':'8px'
 });
 varcommentsTextarea=$('<textarea>')
 .css({'width':'100%','min-height':'40px'})
 .val(assessment.comments)
 .on('input',function(){
 assessmentState.assessments[index].comments=$(this).val().trim();
 });
 commentsCell.append(commentsTextarea);
 row.append(commentsCell);

 // Update initial status
 updateRowStatus(row,index);

 returnrow;
 }

 functionupdateRowStatus(row,index){
 varassessment=assessmentState.assessments[index];
 vargngCell=row.find('td[data-gng]');

 varallYes=assessment.independent==='yes'&&
 assessment.reliable==='yes'&&
 assessment.significant==='yes';

 if(allYes){
 row.css('background-color','#d4edda');
 gngCell.html('<img alt="Yes" src="//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Check-green.svg/20px-Check-green.svg.png" width="13" height="13">');
 gngCell.attr('data-gng','yes');
 }elseif(assessment.independent||assessment.reliable||assessment.significant){
 row.css('background-color','#f8d7da');
 gngCell.html('<img alt="No" src="//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Dark_Red_x.svg/20px-Dark_Red_x.svg.png" width="13" height="13">');
 gngCell.attr('data-gng','no');
 }else{
 row.css('background-color','white');
 gngCell.html('');
 gngCell.attr('data-gng','');
 }
 }

 functiongenerateWikicode(){
 varwikicode='\n\n{{User:Polygnotus/Templates/SourceAssessTable\n';

 assessmentState.sources.forEach(function(source,index){
 varassessment=assessmentState.assessments[index];
 varnum=index+1;

 // Escape pipe characters


 wikicode+='|src'+num+'='+source+'\n';
 wikicode+='|num'+num+'='+num+'\n';

 wikicode+='|ind'+num+'='+assessment.independent+'\n';
 wikicode+='|rel'+num+'='+assessment.reliable+'\n';
 wikicode+='|sig'+num+'='+assessment.significant+'\n';
 wikicode+='|comments'+num+'='+assessment.comments+'\n';

 });

 wikicode+='}}\n';

 // Insert into edit textarea
 vareditTextarea=document.getElementById('wpTextbox1');
 if(editTextarea){
 // Remove existing assessment if present
 varcurrentContent=editTextarea.value;
 varpattern=/\n*\{\{User:Polygnotus\/Templates\/SourceAssessTable[\s\S]*?\}\}\n*/;
 currentContent=currentContent.replace(pattern,'');

 editTextarea.value=currentContent+wikicode;
 $(editTextarea).trigger('change');

 mw.notify('Source assessment added to edit area.',{type:'success'});
 $('#sourceAssessmentPopup').remove();
 }else{
 mw.notify('Failed to find edit textarea.',{type:'error'});
 }
 }

 functionparseExistingAssessment(content){
 // Check if there's already an assessment in the content
 // We need to find the template and handle nested braces properly
 varstartPattern=/\{\{User:Polygnotus\/Templates\/SourceAssessTable/;
 varstartMatch=content.search(startPattern);

 if(startMatch===-1){
 console.log('No existing assessment template found');
 returnnull;
 }

 // Find the matching closing braces by counting
 varbraceCount=0;
 varinTemplate=false;
 vartemplateEnd=-1;

 for(vari=startMatch;i<content.length-1;i++){
 if(content[i]==='{'&&content[i+1]==='{'){
 braceCount++;
 inTemplate=true;
 i++;// Skip next character
 }elseif(content[i]==='}'&&content[i+1]==='}'){
 braceCount--;
 if(braceCount===0&&inTemplate){
 templateEnd=i+2;
 break;
 }
 i++;// Skip next character
 }
 }

 if(templateEnd===-1){
 console.log('Could not find end of template');
 returnnull;
 }

 varfullTemplate=content.substring(startMatch,templateEnd);
 console.log('Found template, length:',fullTemplate.length);

 // Extract just the parameters (between first newline after template name and closing braces)
 vartemplateNameEnd=fullTemplate.indexOf('\n');
 if(templateNameEnd===-1){
 console.log('Template has no parameters');
 returnnull;
 }

 vartemplateContent=fullTemplate.substring(templateNameEnd+1,fullTemplate.length-2);

 varsources=[];
 varassessments=[];

 // Parse parameters - handle multiline values
 varparams={};
 varcurrentParam=null;
 varcurrentValue='';

 varlines=templateContent.split('\n');
 for(vari=0;i<lines.length;i++){
 varline=lines[i];

 // Check if this line starts a new parameter
 varparamMatch=line.match(/^\|([a-zA-Z]+\d+)=(.*)$/);
 if(paramMatch){
 // Save previous parameter if exists
 if(currentParam){
 params[currentParam]=currentValue;
 }

 // Start new parameter
 currentParam=paramMatch[1];
 currentValue=paramMatch[2];
 }elseif(currentParam&&line.trim()!==''){
 // Continue previous parameter value (multiline)
 currentValue+='\n'+line;
 }
 }

 // Don't forget to save the last parameter
 if(currentParam){
 params[currentParam]=currentValue;
 }

 console.log('Parsed parameters:',params);

 // Determine number of sources
 varmaxNum=0;
 Object.keys(params).forEach(function(key){
 varnumMatch=key.match(/\d+$/);
 if(numMatch){
 varnum=parseInt(numMatch[0]);
 if(num>maxNum)maxNum=num;
 }
 });

 console.log('Found',maxNum,'sources');

 // Extract sources and assessments
 for(vari=1;i<=maxNum;i++){
 if(params['src'+i]){
 varsource=params['src'+i].replace(/\{\{!\}\}/g,'|').trim();
 sources.push(source);
 assessments.push({
 independent:(params['ind'+i]||'').trim(),
 reliable:(params['rel'+i]||'').trim(),
 significant:(params['sig'+i]||'').trim(),
 comments:(params['comments'+i]||'').trim()
 });
 }
 }

 if(sources.length===0){
 console.log('No sources found in template');
 returnnull;
 }

 console.log('Successfully parsed',sources.length,'sources with assessments');

 return{
 sources:sources,
 assessments:assessments
 };
 }

 functionextractArticleName(afdPageName){
 vararticleName=afdPageName.replace('Wikipedia:Articles_for_deletion/','');

 // Handle nomination numbers
 varnominationMatch=articleName.match(/(.*) \((\d+)(st|nd|rd|th) nomination\)$/);
 if(nominationMatch){
 articleName=nominationMatch[1];
 }

 returnarticleName;
 }

 functionextractReferences(content){
 varreferences=[];
 varindex=0;

 while(true){
 varstartIndex=content.indexOf('<ref',index);
 if(startIndex===-1)break;

 varendIndex=content.indexOf('>',startIndex);
 if(endIndex===-1)break;

 vartagContent=content.substring(startIndex,endIndex+1);

 // Skip self-closing tags
 if(tagContent.endsWith('/>')){
 index=endIndex+1;
 continue;
 }

 varrefEndIndex=content.indexOf('</ref>',endIndex);
 if(refEndIndex===-1)break;

 varrefContent=content.substring(endIndex+1,refEndIndex).trim();

 // Skip empty refs
 if(refContent){
 references.push(refContent);
 }

 index=refEndIndex+6;
 }

 console.log('Extracted',references.length,'references');
 returnreferences;
 }

AltStyle によって変換されたページ (->オリジナル) /