1/** 2 * Link Behavior Enhancements 3 * - Optionally adds icon to external links 4 * - Ensures PDFs open in a new tab 5 * - Normalizes mailto: links to use target="_self" 6 * - Adds "(opens in new tab)" to aria-label for links opening in a new tab 7 */ 8jQuery(document).ready(function($) { 9 const settings = window.pcwLinkBehaviorSettings || {}; 10 const enableExternalIcon = !!settings.enableExternalIcon; 11 const forceExternalNewTab = !!settings.forceExternalNewTab; 12 const newTabSuffix = ' (opens in new tab)'; 13 14 const ensureRelTokens = function($link, requiredTokens) { 15 const existingRel = ($link.attr('rel') || '').trim(); 16 const parts = existingRel ? existingRel.split(/\s+/) : []; 17 const lower = parts.map(token => token.toLowerCase()); 18 19 requiredTokens.forEach(token => { 20 if (!lower.includes(token)) { 21 parts.push(token); 22 } 23 }); 24 25 $link.attr('rel', parts.join(' ').trim()); 26 }; 27 28 const addNewTabAriaLabel = function($link) { 29 const existing = ($link.attr('aria-label') || '').trim(); 30 if (existing) { 31 if (!/opens in new tab/i.test(existing)) { 32 $link.attr('aria-label', existing + newTabSuffix); 33 } 34 return; 35 } 36 37 const text = ($link.text() || '').trim(); 38 const labelBase = text ? text : 'Link'; 39 $link.attr('aria-label', labelBase + newTabSuffix); 40 }; 41 42 if (forceExternalNewTab) { 43 $('a[href]').each(function() { 44 const $link = $(this); 45 const href = ($link.attr('href') || '').trim(); 46 47 // Only force normal web links (http/https and protocol-relative) 48 if (!/^(https?:)?\/\//i.test(href)) { 49 return; 50 } 51 52 const isExternal = this.hostname && this.hostname !== window.location.hostname; 53 if (!isExternal) { 54 return; 55 } 56 57 $link.attr('target', '_blank'); 58 ensureRelTokens($link, ['noopener', 'noreferrer']); 59 }); 60 } 61 62 $('a[target="_blank"]').each(function() { 63 const $link = $(this); 64 addNewTabAriaLabel($link); 65 66 if (!enableExternalIcon) { 67 return; 68 } 69 70 const isExternal = this.hostname !== window.location.hostname; 71 if (isExternal && !$link.hasClass('external-icon')) { 72 const icon = $('<span aria-hidden="true">â</span>').css({marginLeft: '4px'}); 73 $link.addClass('external-icon').append(icon); 74 } 75 }); 76 77 $('a[href$=".pdf"]').each(function() { 78 const $link = $(this); 79 $link.attr('target', '_blank'); 80 ensureRelTokens($link, ['noopener', 'noreferrer']); 81 addNewTabAriaLabel($link); 82 }); 83 84 $('a[href^="mailto:"]').each(function() { 85 $(this).attr('target', '_self'); 86 }); 87});
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.