1(function () { 2 'use strict'; 3 4 var COOKIE_NAME = 'linkmod_replacements'; 5 var COOKIE_DAYS = 90; 6 7 function getCookie(name) { 8 var match = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^;]*)')); 9 return match ? decodeURIComponent(match[1]) : null; 10 } 11 12 function setCookie(name, value, days) { 13 var expires = new Date(Date.now() + days * 864e5).toUTCString(); 14 document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires + '; path=/; SameSite=Lax'; 15 } 16 17 function getReplacements() { 18 var raw = getCookie(COOKIE_NAME); 19 if (!raw) return []; 20 try { 21 var parsed = JSON.parse(raw); 22 return Array.isArray(parsed) ? parsed : []; 23 } catch (e) { 24 return []; 25 } 26 } 27 28 function saveReplacements(replacements) { 29 setCookie(COOKIE_NAME, JSON.stringify(replacements), COOKIE_DAYS); 30 } 31 32 function addReplacement(find, replace) { 33 var replacements = getReplacements(); 34 var found = false; 35 for (var i = 0; i < replacements.length; i++) { 36 if (replacements[i].find === find) { 37 replacements[i].replace = replace; 38 found = true; 39 break; 40 } 41 } 42 if (!found) { 43 replacements.push({ find: find, replace: replace }); 44 } 45 saveReplacements(replacements); 46 return replacements; 47 } 48 49 function splitUrl(url) { 50 var idx = url.indexOf('?'); 51 if (idx === -1) return { base: url, params: new URLSearchParams() }; 52 return { base: url.substring(0, idx), params: new URLSearchParams(url.substring(idx + 1)) }; 53 } 54 55 function mergeUrls(replaceUrl, originalParams) { 56 var parts = splitUrl(replaceUrl); 57 // Add original params that don't conflict with the replacement URL's params 58 originalParams.forEach(function (value, key) { 59 if (!parts.params.has(key)) { 60 parts.params.set(key, value); 61 } 62 }); 63 var qs = parts.params.toString(); 64 return qs ? parts.base + '?' + qs : parts.base; 65 } 66 67 function applyReplacements(replacements) { 68 if (!replacements.length) return; 69 var links = document.querySelectorAll('a[href]'); 70 for (var i = 0; i < links.length; i++) { 71 var href = links[i].href; // fully resolved absolute URL 72 var hrefParts = splitUrl(href); 73 for (var j = 0; j < replacements.length; j++) { 74 var findBase = splitUrl(replacements[j].find).base; 75 if (hrefParts.base === findBase) { 76 links[i].href = mergeUrls(replacements[j].replace, hrefParts.params); 77 break; 78 } 79 } 80 } 81 } 82 83 // Parse the linkmod parameters from the current URL 84 function parseLinkmodParam() { 85 var params = new URLSearchParams(window.location.search); 86 var findUrl = params.get('linkmod_find'); 87 var replaceUrl = params.get('linkmod_replace'); 88 89 if (!findUrl || !replaceUrl) return null; 90 return { find: findUrl, replace: replaceUrl }; 91 } 92 93 // Main logic 94 function init() { 95 var param = parseLinkmodParam(); 96 var replacements; 97 98 if (param) { 99 replacements = addReplacement(param.find, param.replace); 100 } else { 101 replacements = getReplacements(); 102 } 103 104 applyReplacements(replacements); 105 } 106 107 if (document.readyState === 'loading') { 108 document.addEventListener('DOMContentLoaded', init); 109 } else { 110 init(); 111 } 112})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.