bookmarklet: javascript:(function()%7Bjavascript%3A(function()%7B%0A let debugCount %3D 0%3B%0A let scale %3D 1%3B%0A %0A function debug(msg) %7B%0A console.log(%60%5BWikiLinker %24%7BdebugCount%2B%2B%7D%5D %24%7Bmsg%7D%60)%3B%0A %7D%0A%0A function createWikiLink(word) %7B%0A const capitalizedWord %3D word.charAt(0).toUpperCase() %2B word.slice(1)%3B%0A return %60https%3A%2F%2Fen.wikipedia.org%2Fwiki%2F%24%7BencodeURIComponent(capitalizedWord)%7D%60%3B%0A %7D%0A%0A function isCommonWord(word) %7B%0A const commonWords %3D new Set(%5B%0A 'the'%2C 'be'%2C 'to'%2C 'of'%2C 'and'%2C 'a'%2C 'in'%2C 'that'%2C 'have'%2C 'i'%2C%0A 'it'%2C 'for'%2C 'not'%2C 'on'%2C 'with'%2C 'he'%2C 'as'%2C 'you'%2C 'do'%2C 'at'%2C%0A 'this'%2C 'but'%2C 'his'%2C 'by'%2C 'from'%2C 'they'%2C 'we'%2C 'say'%2C 'her'%2C 'she'%2C%0A 'is'%2C 'are'%2C 'was'%2C 'were'%2C 'will'%2C 'would'%2C 'could'%2C 'should'%2C 'has'%2C%0A 'have'%2C 'had'%2C 'been'%2C 'may'%2C 'might'%2C 'must'%2C 'can'%2C 'when'%2C 'where'%2C%0A 'what'%2C 'who'%2C 'which'%2C 'why'%2C 'how'%2C 'its'%2C 'also'%2C 'or'%2C 'if'%2C 'an'%0A %5D)%3B%0A return commonWords.has(word.toLowerCase())%3B%0A %7D%0A%0A function shouldLinkWord(word) %7B%0A if (!word %7C%7C typeof word !%3D%3D 'string') %7B%0A debug(%60Skipping word%3A %24%7Bword%7D - invalid type%60)%3B%0A return false%3B%0A %7D%0A %0A const trimmed %3D word.trim()%3B%0A if (trimmed.length < 3) %7B%0A debug(%60Skipping word%3A %24%7Bword%7D - too short%60)%3B%0A return false%3B%0A %7D%0A %0A if (trimmed.includes('_') %7C%7C trimmed.includes('%25')) %7B%0A debug(%60Skipping word%3A %24%7Bword%7D - contains special characters%60)%3B%0A return false%3B%0A %7D%0A%0A if (!(%2F%5E%5Ba-zA-Z%5D%2B%24%2F.test(trimmed))) %7B%0A debug(%60Skipping word%3A %24%7Bword%7D - contains non-letters%60)%3B%0A return false%3B%0A %7D%0A%0A if (isCommonWord(trimmed)) %7B%0A debug(%60Skipping word%3A %24%7Bword%7D - common word%60)%3B%0A return false%3B%0A %7D%0A%0A debug(%60Accepting word%3A %24%7Bword%7D%60)%3B%0A return true%3B%0A %7D%0A%0A function applyRainbowStyle(link) %7B%0A link.style.color %3D %60hsl(%24%7BMath.random() * 360%7D%2C 100%25%2C 50%25)%60%3B%0A link.style.transition %3D 'font-size 0.5s ease%2C color 0.5s ease'%3B%0A link.addEventListener('mouseenter'%2C () %3D> %7B%0A link.style.fontSize %3D %60%24%7Bscale%7Dvw%60%3B%0A scale %3D scale %2B 1%3B%0A %7D)%3B%0A %7D%0A%0A function processTextNode(textNode) %7B%0A const parent %3D textNode.parentNode%3B%0A debug(%60Processing text node%3A %24%7BtextNode.nodeValue.substring(0%2C 50)%7D...%60)%3B%0A %0A const skipTags %3D new Set(%5B%0A 'A'%2C 'SCRIPT'%2C 'STYLE'%2C 'NOSCRIPT'%2C 'HEAD'%2C 'TITLE'%2C 'META'%0A %5D)%3B%0A%0A if (skipTags.has(parent.tagName)) %7B%0A debug(%60Skipping due to tag%3A %24%7Bparent.tagName%7D%60)%3B%0A return%3B%0A %7D%0A%0A if (parent.closest('.reference') %7C%7C parent.closest('.mw-editsection')) %7B%0A debug('Skipping due to being in reference or edit section')%3B%0A return%3B%0A %7D%0A%0A const text %3D textNode.nodeValue%3B%0A if (!text %7C%7C !text.trim()) %7B%0A debug('Skipping empty text node')%3B%0A return%3B%0A %7D%0A%0A const words %3D text.split(%2F(%5Cb%5Ba-zA-Z%5D%2B%5Cb%7C%5Cs%2B%7C%5B%5Ea-zA-Z%5Cs%5D%2B)%2F)%3B%0A debug(%60Found %24%7Bwords.length%7D potential words%60)%3B%0A %0A const fragment %3D document.createDocumentFragment()%3B%0A let linksCreated %3D 0%3B%0A%0A words.forEach(word %3D> %7B%0A if (shouldLinkWord(word)) %7B%0A const link %3D document.createElement('a')%3B%0A link.href %3D createWikiLink(word)%3B%0A link.textContent %3D word%3B%0A link.className %3D 'wikilinker-added'%3B%0A applyRainbowStyle(link)%3B%0A link.target %3D '_blank'%3B%0A fragment.appendChild(link)%3B%0A linksCreated%2B%2B%3B%0A debug(%60Created link for%3A %24%7Bword%7D%60)%3B%0A %7D else %7B%0A fragment.appendChild(document.createTextNode(word))%3B%0A %7D%0A %7D)%3B%0A%0A if (linksCreated > 0) %7B%0A parent.replaceChild(fragment%2C textNode)%3B%0A debug(%60Replaced node with %24%7BlinksCreated%7D links%60)%3B%0A %7D%0A %7D%0A%0A function walkTextNodes(node) %7B%0A if (node.nodeType %3D%3D%3D Node.TEXT_NODE) %7B%0A processTextNode(node)%3B%0A return%3B%0A %7D%0A %0A const children %3D Array.from(node.childNodes)%3B%0A debug(%60Walking through %24%7Bchildren.length%7D child nodes%60)%3B%0A children.forEach(walkTextNodes)%3B%0A %7D%0A%0A debug('Starting Wikipedia Auto-Linker with Rainbow Colors')%3B%0A%0A const article %3D document.querySelector('.mw-parser-output') %7C%7C %0A document.querySelector('%23mw-content-text') %7C%7C %0A document.querySelector('.mw-body-content') %7C%7C %0A document.querySelector('%23bodyContent') %7C%7C%0A document.querySelector('article') %7C%7C%0A document.body%3B%0A%0A if (article) %7B%0A debug(%60Found content container%3A %24%7Barticle.className %7C%7C article.id %7C%7C article.tagName%7D%60)%3B%0A %0A %2F%2F Remove old links first%0A const oldLinks %3D document.querySelectorAll('.wikilinker-added')%3B%0A oldLinks.forEach(link %3D> %7B%0A const text %3D document.createTextNode(link.textContent)%3B%0A link.parentNode.replaceChild(text%2C link)%3B%0A %7D)%3B%0A debug(%60Removed %24%7BoldLinks.length%7D existing links%60)%3B%0A%0A walkTextNodes(article)%3B%0A %0A %2F%2F Apply rainbow colors to existing links too%0A document.querySelectorAll('a%3Anot(.wikilinker-added)').forEach(applyRainbowStyle)%3B%0A %0A const totalLinks %3D document.querySelectorAll('.wikilinker-added').length%3B%0A debug(%60Processing complete! Added %24%7BtotalLinks%7D links%60)%3B%0A alert(%60Wikipedia Auto-Linker%3A Added %24%7BtotalLinks%7D new rainbow links to the page! Check console (F12) for details.%60)%3B%0A %7D else %7B%0A debug('Could not find Wikipedia article content')%3B%0A alert('Wikipedia Auto-Linker%3A Could not find Wikipedia article content on this page.')%3B%0A %7D%0A%7D)()%3B%7D)()%3B