Jump to content
Wikipedia The Free Encyclopedia

User:Polygnotus/Scripts/XC.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.
This user script seems to have a documentation page at User:Polygnotus/Scripts/XC.
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.
 // ExtendedConfirmedChecker.js
 // Adds indicators next to usernames on talk pages showing extended confirmed status
 // License: copyleft

 $(function(){
 'use strict';

 // Only run on talk pages
 constnamespace=mw.config.get('wgNamespaceNumber');
 console.log('Current namespace:',namespace);
 if(namespace%2!==1){
 console.log('Not a talk page, exiting');
 return;
 }
 console.log('Running on talk page');

 // Cache handling
 constCACHE_KEY='ec-status-cache';
 constCACHE_EXPIRY=24*60*60*1000;// 24 hours

 functionloadCache(){
 try{
 constcache=localStorage.getItem(CACHE_KEY);
 if(cache){
 const{data,timestamp}=JSON.parse(cache);
 if(Date.now()-timestamp<CACHE_EXPIRY){
 returnnewMap(Object.entries(data));
 }
 }
 }catch(e){
 console.error('Error loading cache:',e);
 }
 returnnewMap();
 }

 functionsaveCache(cache){
 try{
 constcacheData={
 data:Object.fromEntries(cache),
 timestamp:Date.now()
 };
 localStorage.setItem(CACHE_KEY,JSON.stringify(cacheData));
 }catch(e){
 console.error('Error saving cache:',e);
 }
 }

 // Define advanced groups that imply extended confirmed status
 constADVANCED_GROUPS=newSet([
 'sysop',// Administrators
 'bot',// Bots
 'checkuser',// CheckUsers
 'oversight',// Oversighters
 'founder',// Founders
 'steward',// Stewards
 'staff',// Wikimedia staff
 'bureaucrat',// Bureaucrats
 'extendedconfirmed'// Explicitly extended confirmed
 ]);

 constprocessedUsers=newSet();
 constuserGroups=loadCache();

 // Check if a URL path is a subpage
 functionisSubpage(path){
 // First decode the URL to handle any encoded characters
 constdecodedPath=decodeURIComponent(path);
 // Remove any URL parameters or fragments
 constcleanPath=decodedPath.split(/[?#]/)[0];
 // Check if there's a slash after "User:"
 return/User:[^/]+\//.test(cleanPath);
 }

 // Find all user links in signatures
 functionfindUserLinks(){
 // Find both regular user links and redlinks, excluding talk pages and user subpages
 constlinks=$('#content a').filter(function(){
 consthref=$(this).attr('href');
 // Basic check for user page links
 if(!href||(!href.startsWith('/wiki/User:')&&!href.startsWith('/w/index.php?title=User:'))){
 returnfalse;
 }

 // Exclude talk pages
 if(href.includes('talk')){
 returnfalse;
 }

 // Exclude already processed links
 if($(this).attr('data-ec-checked')){
 returnfalse;
 }

 // Check for subpages
 if(href.startsWith('/wiki/')){
 if(isSubpage(href)){
 returnfalse;
 }
 }else{
 // For redlinks, check the title parameter
 consturl=newURL(href,window.location.origin);
 consttitle=url.searchParams.get('title');
 if(title&&isSubpage(title)){
 returnfalse;
 }
 }

 returntrue;
 });

 console.log('Found user links:',links.length);
 links.each((_,link)=>{
 constusername=getUsernameFromLink(link);
 console.log('User link:',$(link).text(),'→',username,$(link).attr('href'));
 });
 returnlinks;
 }

 // Extract username from link
 functiongetUsernameFromLink(link){
 consthref=$(link).attr('href');
 letmatch;

 // Handle both regular wiki links and redlinks
 if(href.startsWith('/wiki/')){
 match=decodeURIComponent(href).match(/User:([^/?&#]+)/);
 }else{
 // For redlinks, check the title parameter
 consturl=newURL(href,window.location.origin);
 consttitle=url.searchParams.get('title');
 if(title){
 match=decodeURIComponent(title).match(/User:([^/?&#]+)/);
 }
 }

 if(match){
 // Remove any subpage part if it somehow got through
 constusername=match[1].split('/')[0];
 returnusername.replace(/_/g,' ');
 }
 returnnull;
 }

 // Check if user has any advanced group
 functionhasAdvancedGroup(groups){
 returngroups.some(group=>ADVANCED_GROUPS.has(group));
 }

 // Batch process users to reduce API calls
 asyncfunctionprocessUserBatch(users){
 if(users.length===0)return;

 constuserList=users.join('|');
 console.log('Fetching groups for users:',userList);

 constmaxRetries=3;
 letretryCount=0;
 letdelay=1000;// Start with 1 second delay

 while(retryCount<maxRetries){
 try{
 constresponse=await$.ajax({
 url:mw.util.wikiScript('api'),
 data:{
 action:'query',
 format:'json',
 list:'users',
 usprop:'groups|blockinfo',
 ususers:userList,
 formatversion:'2'
 },
 dataType:'json'
 });

 console.log('API response:',response);

 if(response.error&&response.error.code==='ratelimited'){
 console.log('Rate limited, waiting before retry...');
 awaitnewPromise(resolve=>setTimeout(resolve,delay));
 delay*=2;// Exponential backoff
 retryCount++;
 continue;
 }

 if(response.query&&response.query.users){
 response.query.users.forEach(user=>{
 letstatus;
 if(user.missing){
 status='missing';
 }elseif(user.blockedby){
 status='blocked';
 }else{
 constgroups=user.groups||[];
 // Check if user has any advanced group
 status=hasAdvancedGroup(groups)?'extended':'normal';
 }
 userGroups.set(user.name,status);
 });

 // Save updated cache
 saveCache(userGroups);
 }
 break;// Success, exit retry loop

 }catch(error){
 console.error('Error fetching user groups:',error);
 if(retryCount>=maxRetries-1){
 // Mark all users in batch as error if we've exhausted retries
 users.forEach(username=>userGroups.set(username,'error'));
 saveCache(userGroups);
 }else{
 awaitnewPromise(resolve=>setTimeout(resolve,delay));
 delay*=2;// Exponential backoff
 retryCount++;
 }
 }
 }
 }

 // Add status indicator next to username
 functionaddStatusIndicator(link,status){
 // Remove any existing indicators next to this link
 $(link).siblings('.ec-status-indicator').remove();

 letsymbol,color,title;
 switch(status){
 case'extended':
 symbol='✔';
 color='#00a000';
 title='Extended confirmed user';
 break;
 case'error':
 symbol='?';
 color='#666666';
 title='Error checking status';
 break;
 case'blocked':
 symbol='🚫';
 color='#cc0000';
 title='Blocked user';
 break;
 case'missing':
 symbol='!';
 color='#666666';
 title='User not found';
 break;
 default:
 symbol='✘';
 color='#cc0000';
 title='Not extended confirmed';
 }

 constindicator=$('<span>')
 .addClass('ec-status-indicator')
 .css({
 'margin-left':'4px',
 'font-size':'0.85em',
 'color':color,
 'cursor':'help'
 })
 .attr('title',title)
 .text(symbol);

 $(link).after(indicator);
 $(link).attr('data-ec-checked','true');
 }

 // Main processing function
 asyncfunctionprocessPage(){
 console.log('Processing page...');
 constuserLinks=findUserLinks();
 constbatchSize=50;
 constusers=[];

 userLinks.each((_,link)=>{
 constusername=getUsernameFromLink(link);
 if(username&&!processedUsers.has(username)){
 users.push(username);
 processedUsers.add(username);
 }
 });

 // Process users in batches
 for(leti=0;i<users.length;i+=batchSize){
 constbatch=users.slice(i,i+batchSize);
 awaitprocessUserBatch(batch);
 }

 // Add indicators
 userLinks.each((_,link)=>{
 constusername=getUsernameFromLink(link);
 constisExtendedConfirmed=userGroups.get(username);
 addStatusIndicator(link,isExtendedConfirmed);
 });
 }

 // Run on page load and when new content is added
 processPage();
 mw.hook('wikipage.content').add(processPage);
 });

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