Jump to content
Wikipedia The Free Encyclopedia

User:Polygnotus/Scripts/ListGenerator.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/ListGenerator.
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.
 // Universal Wikipedia List Copier - Refactored for simplicity and maintainability

 constCONFIG={
 API_DELAY:500,
 MAX_RETRIES:3,
 BASE_URL:'https://en.wikipedia.org',
 API_URL:'https://en.wikipedia.org/w/api.php'
 };

 // ===== CORE UTILITIES =====

 functionaddTooltip(element,text){
 element.title=text;
 }

 functionformatItems(items,includeUrls,baseUrl=`${CONFIG.BASE_URL}/wiki/`){
 if(!includeUrls)returnitems.join('\n');
 returnitems.map(item=>`${baseUrl}${encodeURIComponent(item.replace(/ /g,'_'))}`).join('\n');
 }

 asyncfunctioncopyToClipboardOrDownload(text,filename,statusElement){
 constsuccess=awaittryClipboardCopy(text);
 if(!success){
 statusElement.innerHTML=`<p>Clipboard access failed. Click the link below to download items:</p>`;
 offerTextAsDownload(text,filename,statusElement);
 }
 returnsuccess;
 }

 functionofferTextAsDownload(text,filename,statusElement){
 constblob=newBlob([text],{type:'text/plain'});
 consturl=URL.createObjectURL(blob);
 constdownloadLink=document.createElement('a');
 Object.assign(downloadLink,{
 href:url,
 download:filename||'wikipedia-items.txt',
 textContent:`Download ${filename||'items'} as text file`,
 style:'display: block; margin-top: 10px;'
 });
 statusElement.appendChild(downloadLink);
 }

 asyncfunctiontryClipboardCopy(text){
 if(navigator.clipboard?.writeText){
 try{
 awaitnavigator.clipboard.writeText(text);
 returntrue;
 }catch{}
 }

 // Fallback method
 try{
 consttextarea=document.createElement('textarea');
 Object.assign(textarea.style,{
 position:'fixed',
 left:'-999999px',
 top:'-999999px'
 });
 textarea.value=text;
 document.body.appendChild(textarea);
 textarea.focus();
 textarea.select();
 constsuccess=document.execCommand('copy');
 document.body.removeChild(textarea);
 returnsuccess;
 }catch{
 returnfalse;
 }
 }

 // ===== API UTILITIES =====

 asyncfunctionmakeApiRequest(url,retryCount=0){
 awaitnewPromise(resolve=>setTimeout(resolve,CONFIG.API_DELAY));

 try{
 constresponse=awaitfetch(url);

 if(response.status===429||response.status>=500){
 if(retryCount<CONFIG.MAX_RETRIES){
 awaitnewPromise(resolve=>setTimeout(resolve,Math.pow(2,retryCount)*1000));
 returnmakeApiRequest(url,retryCount+1);
 }
 thrownewError(`Request failed after ${CONFIG.MAX_RETRIES} retries: ${response.status}`);
 }

 if(!response.ok){
 thrownewError(`HTTP ${response.status}: ${response.statusText}`);
 }

 constdata=awaitresponse.json();

 if(data.error?.code==='maxlag'){
 constwaitTime=(data.error.lag||5+2)*1000;
 awaitnewPromise(resolve=>setTimeout(resolve,waitTime));
 returnmakeApiRequest(url,retryCount);
 }

 if(data.error){
 thrownewError(`API Error: ${data.error.code} - ${data.error.info}`);
 }

 returndata;
 }catch(error){
 if(retryCount<CONFIG.MAX_RETRIES){
 awaitnewPromise(resolve=>setTimeout(resolve,1000));
 returnmakeApiRequest(url,retryCount+1);
 }
 throwerror;
 }
 }

 // Generic paginated API fetcher
 asyncfunctionfetchAllPages(apiConfig,statusCallback){
 letallItems=[];
 letcontinueToken=null;
 letpagesProcessed=0;

 do{
 consturl=apiConfig.buildUrl(continueToken);
 statusCallback(`${apiConfig.progressMessage} (page ${pagesProcessed+1})...`);

 constdata=awaitmakeApiRequest(url);
 const{items,continueToken:nextToken}=apiConfig.parseResponse(data);

 allItems=allItems.concat(items);
 continueToken=nextToken;
 pagesProcessed++;

 statusCallback(`Retrieved ${allItems.length}${apiConfig.itemType} (page ${pagesProcessed})...`);
 }while(continueToken);

 returnallItems;
 }

 // ===== CONSOLIDATED FETCH METHODS =====

 // Generic paginated fetcher - handles all simple list-based APIs
 asyncfunctionfetchPaginatedList(listType,params,statusCallback=()=>{}){
 constconfigs={
 categoryMembers:{
 list:'categorymembers',
 titleParam:'cmtitle',
 continueParam:'cmcontinue',
 limitParam:'cmlimit',
 namespaceParam:'cmnamespace',
 dataPath:'categorymembers',
 defaultNamespaces:'0|1|2|3|4|5|6|7|8|9|10|11|12|13|15'
 },
 categorySubcategories:{
 list:'categorymembers',
 titleParam:'cmtitle',
 continueParam:'cmcontinue',
 limitParam:'cmlimit',
 namespaceParam:'cmnamespace',
 dataPath:'categorymembers',
 defaultNamespaces:'14'
 },
 backlinks:{
 list:'backlinks',
 titleParam:'bltitle',
 continueParam:'blcontinue',
 limitParam:'bllimit',
 namespaceParam:'blnamespace',
 dataPath:'backlinks'
 },
 prefixPages:{
 list:'allpages',
 titleParam:'apprefix',
 continueParam:'apcontinue',
 limitParam:'aplimit',
 namespaceParam:'apnamespace',
 dataPath:'allpages'
 },
 search:{
 list:'search',
 titleParam:'srsearch',
 continueParam:'sroffset',
 limitParam:'srlimit',
 dataPath:'search'
 }
 };

 constconfig=configs[listType];
 if(!config){
 thrownewError(`Unknown list type: ${listType}`);
 }

 returnfetchAllPages({
 buildUrl:(continueToken)=>{
 leturl=`${CONFIG.API_URL}?action=query&list=${config.list}&${config.limitParam}=max&maxlag=5&format=json&origin=*`;

 // Add title/search parameter
 if(config.titleParam&&params.title){
 if(listType==='categoryMembers'||listType==='categorySubcategories'){
 url+=`&${config.titleParam}=Category:${encodeURIComponent(params.title)}`;
 }else{
 url+=`&${config.titleParam}=${encodeURIComponent(params.title)}`;
 }
 }

 // Add namespace parameter
 if(config.namespaceParam){
 constnamespace=params.namespace!==undefined?params.namespace:config.defaultNamespaces;
 if(namespace!==null){
 url+=`&${config.namespaceParam}=${namespace}`;
 }
 }

 // Add continuation token
 if(continueToken){
 url+=`&${config.continueParam}=${continueToken}`;
 }

 returnurl;
 },
 parseResponse:(data)=>({
 items:data.query?.[config.dataPath]?.map(item=>item.title)||[],
 continueToken:data.continue?.[config.continueParam]||null
 }),
 progressMessage:params.progressMessage||`Fetching ${listType}`,
 itemType:params.itemType||'items'
 },statusCallback);
 }

 // Individual fetch methods using the consolidated approach
 asyncfunctionfetchCategoryMembers(categoryTitle){
 returnfetchPaginatedList('categoryMembers',{
 title:categoryTitle,
 progressMessage:`Fetching items for: ${categoryTitle}`,
 itemType:'items'
 });
 }

 asyncfunctionfetchCategorySubcategories(categoryTitle){
 returnfetchPaginatedList('categorySubcategories',{
 title:categoryTitle,
 progressMessage:`Fetching subcategories for: ${categoryTitle}`,
 itemType:'subcategories'
 });
 }

 asyncfunctionfetchBacklinks(targetTitle,namespaces,statusText){
 returnfetchPaginatedList('backlinks',{
 title:targetTitle,
 namespace:namespaces,
 progressMessage:`Fetching backlinks for: ${targetTitle}`,
 itemType:'backlinks'
 },(msg)=>statusText.innerHTML=msg);
 }

 asyncfunctionfetchPrefixPages(prefix,namespace,statusText){
 returnfetchPaginatedList('prefixPages',{
 title:prefix,
 namespace:namespace,
 progressMessage:`Fetching pages with prefix "${prefix}" in namespace ${namespace}`,
 itemType:'pages'
 },(msg)=>statusText.innerHTML=msg);
 }

 asyncfunctionfetchSearchResults(query,statusText){
 returnfetchPaginatedList('search',{
 title:query,
 progressMessage:`Searching for: "${query}"`,
 itemType:'search results'
 },(msg)=>statusText.innerHTML=msg);
 }

 // Combined category fetch methods
 asyncfunctionfetchCategoryBoth(categoryTitle){
 const[items,subcategories]=awaitPromise.all([
 fetchCategoryMembers(categoryTitle),
 fetchCategorySubcategories(categoryTitle)
 ]);
 return[...items,...subcategories];
 }

 // Recursive methods
 asyncfunctionfetchCategoryMembersRecursive(categoryTitle,statusText){
 constvisited=newSet();
 constallItems=[];
 constqueue=[categoryTitle];
 lettotalCategories=0;

 while(queue.length>0){
 constcurrentCategory=queue.shift();
 constcategoryKey=`Category:${currentCategory}`;

 if(visited.has(categoryKey))continue;
 visited.add(categoryKey);
 totalCategories++;

 statusText.innerHTML=`Getting items from "${currentCategory}" (processed ${totalCategories} categories, found ${allItems.length} items, queue: ${queue.length})...`;

 constcurrentItems=awaitfetchCategoryMembers(currentCategory);
 allItems.push(...currentItems);

 constsubcategories=awaitfetchCategorySubcategories(currentCategory);
 for(constsubcategoryofsubcategories){
 if(!visited.has(subcategory)){
 queue.push(subcategory.replace('Category:',''));
 }
 }
 }

 return[...newSet(allItems)];
 }

 asyncfunctionfetchCategorySubcategoriesRecursive(categoryTitle,statusText){
 constvisited=newSet();
 constallSubcategories=[];
 constqueue=[`Category:${categoryTitle}`];

 while(queue.length>0){
 constcurrentCategory=queue.shift();

 if(visited.has(currentCategory))continue;
 visited.add(currentCategory);

 statusText.innerHTML=`Exploring subcategories (found ${allSubcategories.length} categories, queue: ${queue.length})...`;

 constcategoryNameForApi=currentCategory.replace('Category:','');
 constdirectSubcategories=awaitfetchCategorySubcategories(categoryNameForApi);

 for(constsubcategoryofdirectSubcategories){
 if(!visited.has(subcategory)){
 allSubcategories.push(subcategory);
 queue.push(subcategory);
 }
 }
 }

 return[...newSet(allSubcategories)];
 }

 asyncfunctionfetchCategoryBothRecursive(categoryTitle,statusText){
 constvisited=newSet();
 constallItems=[];
 constallSubcategories=[];
 constqueue=[categoryTitle];
 lettotalCategories=0;

 while(queue.length>0){
 constcurrentCategory=queue.shift();
 constcategoryKey=`Category:${currentCategory}`;

 if(visited.has(categoryKey))continue;
 visited.add(categoryKey);
 totalCategories++;

 statusText.innerHTML=`Getting items and subcategories from "${currentCategory}" (processed ${totalCategories} categories, found ${allItems.length} items, ${allSubcategories.length} subcategories, queue: ${queue.length})...`;

 const[currentItems,directSubcategories]=awaitPromise.all([
 fetchCategoryMembers(currentCategory),
 fetchCategorySubcategories(currentCategory)
 ]);

 allItems.push(...currentItems);

 for(constsubcategoryofdirectSubcategories){
 if(!visited.has(subcategory)){
 allSubcategories.push(subcategory);
 queue.push(subcategory.replace('Category:',''));
 }
 }
 }

 return[...newSet([...allItems,...allSubcategories])];
 }

 // Article links fetcher
 asyncfunctionfetchArticleLinks(statusText){
 constarticleTitle=document.querySelector('.mw-first-heading').textContent;
 constapiUrl=`${CONFIG.API_URL}?action=query&titles=${encodeURIComponent(articleTitle)}&prop=revisions&rvprop=content&format=json&origin=*`;

 constdata=awaitmakeApiRequest(apiUrl);

 if(!data.query?.pages){
 thrownewError('Could not fetch article content.');
 }

 constpages=Object.values(data.query.pages);
 if(pages.length===0||!pages[0].revisions){
 thrownewError('No content found for this article.');
 }

 constwikitext=pages[0].revisions[0]['*'];
 constwikilinkRegex=/\[\[([^\]|\[]+)(?:\|[^\]]+)?\]\]/g;
 constlinks=[];
 letmatch;

 while((match=wikilinkRegex.exec(wikitext))!==null){
 letlinkTarget=match[1].trim();

 if(linkTarget.includes('#')){
 linkTarget=linkTarget.split('#')[0];
 }

 if(linkTarget&&
 !linkTarget.startsWith('File:')&&
 !linkTarget.startsWith('Image:')&&
 !linkTarget.startsWith('Category:')&&
 !linkTarget.startsWith('Template:')&&
 !linkTarget.startsWith(':')&&
 !linkTarget.includes('|')){
 links.push(linkTarget);
 }
 }

 // Return links in original order (don't sort)
 return[...newSet(links)];
 }

 // Scrape watchlist items from the current page (no API calls)
 asyncfunctionscrapeWatchlistFromPage(){
 constwatchlistItems=[];

 // Primary method: Extract from data-target-page attributes
 consttargetPageElements=document.querySelectorAll('[data-target-page]');
 console.log(`Found ${targetPageElements.length} data-target-page elements`);

 for(constelementoftargetPageElements){
 constpageName=element.getAttribute('data-target-page');

 if(pageName){
 // Remove namespace prefixes to get the actual article name
 letarticleName=pageName;

 // Handle special cases
 if(pageName.startsWith('Talk:')){
 // For talk pages, extract the main article name
 articleName=pageName.replace('Talk:','');
 }elseif(pageName.includes(':')&&
 !pageName.startsWith('Category:')&&
 !pageName.startsWith('File:')&&
 !pageName.startsWith('Template:')&&
 !pageName.startsWith('Help:')&&
 !pageName.startsWith('Portal:')&&
 !pageName.startsWith('MediaWiki:')){
 // Skip other namespace pages like Wikipedia:, User:, etc.
 continue;
 }

 // Only include if it's a mainspace article (no colon in name)
 if(articleName&&!articleName.includes(':')&&!watchlistItems.includes(articleName)){
 watchlistItems.push(articleName);
 }
 }
 }

 // Backup method: Look for .mw-changeslist-title links if we didn't get many results
 if(watchlistItems.length<3){
 console.log('Using backup method: .mw-changeslist-title');
 consttitleLinks=document.querySelectorAll('.mw-changeslist-title');

 for(constlinkoftitleLinks){
 consthref=link.getAttribute('href');
 if(href&&href.startsWith('/wiki/')){
 constpageName=decodeURIComponent(href.replace('/wiki/','').replace(/_/g,' '));

 // Extract mainspace article name
 letarticleName=pageName;
 if(pageName.startsWith('Talk:')){
 articleName=pageName.replace('Talk:','');
 }elseif(pageName.includes(':')){
 continue;// Skip other namespaces
 }

 if(articleName&&!watchlistItems.includes(articleName)){
 watchlistItems.push(articleName);
 }
 }
 }
 }

 console.log(`Final watchlist items found: ${watchlistItems.length}`,watchlistItems);
 return[...newSet(watchlistItems)];
 }

 // Helper function to extract target title
 functionextractTargetTitle(){
 consturlParams=newURLSearchParams(window.location.search);
 lettargetTitle=urlParams.get('target');

 if(!targetTitle){
 constheadingElement=document.querySelector('.mw-first-heading');
 if(headingElement){
 constmatch=headingElement.textContent.match(/Pages that link to "(.+)"/);
 if(match)targetTitle=match[1];
 }
 }

 if(!targetTitle){
 constlinkElement=document.querySelector('.mw-whatlinkshere-target a');
 if(linkElement){
 targetTitle=linkElement.getAttribute('title')||linkElement.textContent;
 }
 }

 returntargetTitle;
 }

 // ===== UI UTILITIES =====

 functioncreateControlBox(title,insertTarget){
 constcontainer=document.createElement('div');
 Object.assign(container.style,{
 padding:'10px',
 margin:'10px 0',
 backgroundColor:'#f8f9fa',
 border:'1px solid #a2a9b1',
 borderRadius:'3px'
 });

 consttitleElement=document.createElement('h4');
 titleElement.textContent=title;
 Object.assign(titleElement.style,{
 margin:'0 0 10px 0',
 fontSize:'14px',
 fontWeight:'bold'
 });
 container.appendChild(titleElement);

 constbuttonsDiv=document.createElement('div');
 buttonsDiv.style.marginBottom='10px';

 consturlCheckbox=document.createElement('input');
 urlCheckbox.type='checkbox';
 urlCheckbox.id='includeUrls';
 urlCheckbox.style.marginLeft='15px';

 consturlLabel=document.createElement('label');
 urlLabel.htmlFor='includeUrls';
 urlLabel.textContent='Include URLs';
 urlLabel.style.marginLeft='5px';
 addTooltip(urlLabel,'Include full Wikipedia URLs for each item');

 buttonsDiv.appendChild(urlCheckbox);
 buttonsDiv.appendChild(urlLabel);
 container.appendChild(buttonsDiv);

 conststatusText=document.createElement('div');
 Object.assign(statusText.style,{
 marginTop:'10px',
 color:'#555'
 });
 container.appendChild(statusText);

 constinsertLocation=insertTarget||document.querySelector('#content');
 if(insertTarget){
 insertTarget.parentNode.insertBefore(container,insertTarget.nextSibling);
 }else{
 insertLocation.prepend(container);
 }

 return{container,buttonsDiv,urlCheckbox,statusText};
 }

 functioncreateButton(text,tooltip,buttonsDiv,urlCheckbox){
 constbtn=document.createElement('button');
 btn.textContent=text;
 Object.assign(btn.style,{
 marginRight:'10px',
 padding:'8px 12px',
 cursor:'pointer'
 });
 addTooltip(btn,tooltip);
 buttonsDiv.insertBefore(btn,urlCheckbox);
 returnbtn;
 }

 // Generic button action handler
 asyncfunctionhandleButtonAction(config,statusText,urlCheckbox){
 statusText.innerHTML=config.startMessage;
 try{
 constitems=awaitconfig.fetchFunction();
 if(items.length===0){
 statusText.innerHTML=config.emptyMessage;
 return;
 }

 constincludeUrls=urlCheckbox.checked;
 constformattedText=formatItems(items,includeUrls);
 constcopySuccess=awaitcopyToClipboardOrDownload(formattedText,config.filename,statusText);

 if(copySuccess){
 statusText.innerHTML=`Successfully copied ${items.length}${config.itemType} to clipboard.`;
 }
 }catch(error){
 statusText.innerHTML=`Error: ${error.message}`;
 }
 }

 // ===== PAGE HANDLERS =====

 functioninitializeCategoryPage(){
 constcategoryName=decodeURIComponent(window.location.pathname.split('/Category:')[1]);
 console.log("Category Name:",categoryName);

 constpageTitleHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('Category Tools',pageTitleHeading);

 constbuttons=[
 {
 text:'Copy items',
 tooltip:'Copy all items in this category. Not recursive.',
 action:()=>handleButtonAction({
 startMessage:'Gathering items from this category via API...',
 fetchFunction:()=>fetchCategoryMembers(categoryName),
 emptyMessage:'No items found in this category.',
 filename:categoryName,
 itemType:'items'
 },statusText,urlCheckbox)
 },
 {
 text:'Copy items recursively',
 tooltip:'Copy all items in this category AND all items in its subcategories.',
 action:()=>handleButtonAction({
 startMessage:'Gathering items from this category and all subcategories recursively via API...',
 fetchFunction:()=>fetchCategoryMembersRecursive(categoryName,statusText),
 emptyMessage:'No items found in this category or its subcategories.',
 filename:`${categoryName}_all_recursive`,
 itemType:'items'
 },statusText,urlCheckbox)
 },
 {
 text:'Copy subcats',
 tooltip:'Copy all subcategories of this category. Not recursive.',
 action:()=>handleButtonAction({
 startMessage:'Gathering direct subcategories from this category via API...',
 fetchFunction:()=>fetchCategorySubcategories(categoryName),
 emptyMessage:'No direct subcategories found in this category.',
 filename:`${categoryName}_direct_subcats`,
 itemType:'subcategories'
 },statusText,urlCheckbox)
 },
 {
 text:'Copy subcategories recursively',
 tooltip:'Copy all subcategories of this category and its subcategories.',
 action:()=>handleButtonAction({
 startMessage:'Gathering all subcategories recursively via API...',
 fetchFunction:()=>fetchCategorySubcategoriesRecursive(categoryName,statusText),
 emptyMessage:'No subcategories found.',
 filename:`${categoryName}_subcategories`,
 itemType:'subcategories'
 },statusText,urlCheckbox)
 },
 {
 text:'Copy both',
 tooltip:'Copy all items and subcategories from this category. Not recursive.',
 action:()=>handleButtonAction({
 startMessage:'Gathering both items and subcategories from this category via API...',
 fetchFunction:()=>fetchCategoryBoth(categoryName),
 emptyMessage:'No items or subcategories found in this category.',
 filename:`${categoryName}_both`,
 itemType:'items and subcategories'
 },statusText,urlCheckbox)
 },
 {
 text:'Copy both recursively',
 tooltip:'Copy all items and subcategories from this category and all its subcategories.',
 action:()=>handleButtonAction({
 startMessage:'Gathering both items and subcategories recursively via API...',
 fetchFunction:()=>fetchCategoryBothRecursive(categoryName,statusText),
 emptyMessage:'No items or subcategories found in this category or its subcategories.',
 filename:`${categoryName}_both_recursive`,
 itemType:'items and subcategories'
 },statusText,urlCheckbox)
 }
 ];

 buttons.forEach(({text,tooltip,action})=>{
 constbtn=createButton(text,tooltip,buttonsDiv,urlCheckbox);
 btn.addEventListener('click',action);
 });
 }

 functioninitializeWhatLinksHerePage(){
 consttargetTitle=extractTargetTitle();
 console.log("Target Title:",targetTitle);

 consttargetHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('What Links Here Tools',targetHeading);

 constbuttons=[
 {
 text:'Copy all links',
 tooltip:'Copy all pages that link to this page',
 namespace:null,
 type:'all backlinks'
 },
 {
 text:'Copy mainspace links',
 tooltip:'Copy only mainspace (article) pages that link to this page',
 namespace:'0',
 type:'mainspace backlinks'
 }
 ];

 buttons.forEach(({text,tooltip,namespace,type})=>{
 constbtn=createButton(text,tooltip,buttonsDiv,urlCheckbox);
 btn.addEventListener('click',()=>handleButtonAction({
 startMessage:`Gathering ${type} via API...`,
 fetchFunction:()=>fetchBacklinks(targetTitle,namespace,statusText),
 emptyMessage:namespace==='0'?'No mainspace pages link to this page.':'No pages link to this page.',
 filename:namespace==='0'?'mainspace_backlinks':'all_backlinks',
 itemType:'backlinks'
 },statusText,urlCheckbox));
 });

 // Non-mainspace button (special case)
 constnonMainspaceBtn=createButton('Copy non-mainspace links','Copy only non-mainspace pages (talk, user, etc.) that link to this page',buttonsDiv,urlCheckbox);
 nonMainspaceBtn.addEventListener('click',()=>handleButtonAction({
 startMessage:'Gathering non-mainspace backlinks via API...',
 fetchFunction:async()=>{
 constallBacklinks=awaitfetchBacklinks(targetTitle,null,statusText);
 statusText.innerHTML='Filtering out mainspace backlinks...';
 constmainspaceBacklinks=awaitfetchBacklinks(targetTitle,'0',statusText);
 constmainspaceSet=newSet(mainspaceBacklinks);
 returnallBacklinks.filter(link=>!mainspaceSet.has(link));
 },
 emptyMessage:'No non-mainspace pages link to this page.',
 filename:'non_mainspace_backlinks',
 itemType:'non-mainspace backlinks'
 },statusText,urlCheckbox));
 }

 functioninitializePrefixPage(){
 consturlParams=newURLSearchParams(window.location.search);
 letprefix=urlParams.get('prefix')||urlParams.get('from')||'';
 letnamespace=urlParams.get('namespace')||'0';

 // Extract prefix from URL path for Special:PrefixIndex/PREFIX format
 if(!prefix&&window.location.pathname.includes('Special:PrefixIndex/')){
 constpathParts=window.location.pathname.split('Special:PrefixIndex/');
 if(pathParts.length>1){
 constfullPrefix=decodeURIComponent(pathParts[1]);

 // Handle namespace prefixes like "User:Polygnotus"
 if(fullPrefix.includes(':')){
 const[namespaceName,actualPrefix]=fullPrefix.split(':',2);
 constnamespaceMap={
 'User':'2',
 'Wikipedia':'4',
 'File':'6',
 'MediaWiki':'8',
 'Template':'10',
 'Help':'12',
 'Category':'14',
 'Portal':'100',
 'Draft':'118'
 };

 if(namespaceMap[namespaceName]){
 namespace=namespaceMap[namespaceName];
 prefix=actualPrefix;
 }else{
 prefix=fullPrefix;
 }
 }else{
 prefix=fullPrefix;
 }
 }
 }

 console.log("Prefix:",prefix,"Namespace:",namespace);

 consttargetHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('Prefix Search Tools',targetHeading);

 constbtn=createButton('Copy all pages','Copy all pages with this prefix using API',buttonsDiv,urlCheckbox);
 btn.addEventListener('click',()=>{
 if(!prefix){
 statusText.innerHTML='Error: No prefix found in URL parameters or path.';
 return;
 }

 handleButtonAction({
 startMessage:'Gathering all pages with this prefix via API...',
 fetchFunction:()=>fetchPrefixPages(prefix,namespace,statusText),
 emptyMessage:`No pages found with prefix "${prefix}" in namespace ${namespace}.`,
 filename:`prefix_${prefix.replace(/[^a-zA-Z0-9]/g,'_')}`,
 itemType:'pages'
 },statusText,urlCheckbox);
 });
 }

 functioninitializeWatchlistPage(){
 consttargetHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('Watchlist Tools',targetHeading);

 constbtn=createButton('Copy all watchlist items','Copy all pages from your watchlist by scraping the page',buttonsDiv,urlCheckbox);
 btn.addEventListener('click',()=>handleButtonAction({
 startMessage:'Scraping watchlist items from page...',
 fetchFunction:()=>scrapeWatchlistFromPage(),
 emptyMessage:'No items found in your watchlist.',
 filename:'complete_watchlist',
 itemType:'watchlist items'
 },statusText,urlCheckbox));
 }

 functioninitializeSearchPage(){
 consturlParams=newURLSearchParams(window.location.search);
 constsearchQuery=urlParams.get('search')||'';

 console.log("Search Query:",searchQuery);

 consttargetHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('Search Results Tools',targetHeading);

 constbtn=createButton('Copy all search results','Copy all search results using API',buttonsDiv,urlCheckbox);
 btn.addEventListener('click',()=>{
 if(!searchQuery){
 statusText.innerHTML='Error: No search query found in URL parameters.';
 return;
 }

 handleButtonAction({
 startMessage:'Gathering all search results via API...',
 fetchFunction:()=>fetchSearchResults(searchQuery,statusText),
 emptyMessage:`No search results found for "${searchQuery}".`,
 filename:`search_${searchQuery.replace(/[^a-zA-Z0-9]/g,'_')}`,
 itemType:'search results'
 },statusText,urlCheckbox);
 });
 }

 functioninitializeArticlePage(){
 consttargetHeading=document.querySelector('.mw-first-heading');
 const{buttonsDiv,urlCheckbox,statusText}=createControlBox('Article Links Tools',targetHeading);

 constbtn=createButton('Copy wikitext links','Copy all wikilink targets from this article\'s source',buttonsDiv,urlCheckbox);
 btn.addEventListener('click',()=>handleButtonAction({
 startMessage:'Fetching article wikitext...',
 fetchFunction:()=>fetchArticleLinks(statusText),
 emptyMessage:'No wikilinks found in this article.',
 filename:'article_wikilinks',
 itemType:'wikilinks'
 },statusText,urlCheckbox));
 }

 // ===== INITIALIZATION =====

 functioninitializePageHandler(){
 constcurrentUrl=window.location.href;
 constcurrentPath=window.location.pathname;

 if(currentUrl.includes('/wiki/Category:')){
 initializeCategoryPage();
 }elseif(currentUrl.includes('Special:WhatLinksHere')||currentPath.includes('Special:WhatLinksHere')){
 initializeWhatLinksHerePage();
 }elseif(currentUrl.includes('Special:PrefixIndex')||currentPath.includes('Special:PrefixIndex')||currentUrl.includes('Special:AllPages')){
 initializePrefixPage();
 }elseif(currentUrl.includes('Special:Watchlist')){
 initializeWatchlistPage();
 }elseif(currentUrl.includes('Special:Search')||currentPath.includes('Special:Search')||currentUrl.includes('search=')){
 initializeSearchPage();
 }elseif(currentPath.startsWith('/wiki/')&&!currentPath.includes(':')){
 initializeArticlePage();
 }
 }

 if(!mw.config.get('wgIsMainPage')){
 initializePageHandler();
 }
 console.log('Universal Wikipedia List Copier script loaded successfully!');

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