User:Polygnotus/Scripts/ListGenerator.js
Appearance
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 code will be executed when previewing this page.
Documentation for this user script can be added at User:Polygnotus/Scripts/ListGenerator.
// 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&¶ms.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!');