1/** 2 * @file 3 */ 4 5(function ($) { 6 7 'use strict'; 8 9 Drupal.extlink = Drupal.extlink || {}; 10 11 Drupal.extlink.attach = function (context, settings) { 12 if (!settings.hasOwnProperty('extlink')) { 13 return; 14 } 15 16 // Strip the host name down, removing ports, subdomains, or www. 17 var pattern = /^(([^\/:]+?\.)*)([^\.:]{1,})((\.[a-z0-9]{1,253})*)(:[0-9]{1,5})?$/; 18 var host = window.location.host.replace(pattern, '$2$3$6'); 19 var subdomain = window.location.host.replace(host, ''); 20 21 // Determine what subdomains are considered internal. 22 var subdomains; 23 if (settings.extlink.extSubdomains) { 24 subdomains = '([^/]*\\.)?'; 25 } 26 else if (subdomain === 'www.' || subdomain === '') { 27 subdomains = '(www\\.)?'; 28 } 29 else { 30 subdomains = subdomain.replace('.', '\\.'); 31 } 32 33 // Build regular expressions that define an internal link. 34 var internal_link = new RegExp('^https?://([^@]*@)?' + subdomains + host, 'i'); 35 36 // Extra internal link matching. 37 var extInclude = false; 38 if (settings.extlink.extInclude) { 39 extInclude = new RegExp(settings.extlink.extInclude.replace(/\\/, '\\'), 'i'); 40 } 41 42 // Extra external link matching. 43 var extExclude = false; 44 if (settings.extlink.extExclude) { 45 extExclude = new RegExp(settings.extlink.extExclude.replace(/\\/, '\\'), 'i'); 46 } 47 48 // Extra external link CSS selector exclusion. 49 var extCssExclude = false; 50 if (settings.extlink.extCssExclude) { 51 extCssExclude = settings.extlink.extCssExclude; 52 } 53 54 // Extra external link CSS selector explicit. 55 var extCssExplicit = false; 56 if (settings.extlink.extCssExplicit) { 57 extCssExplicit = settings.extlink.extCssExplicit; 58 } 59 60 // Define the jQuery method (either 'append' or 'prepend') of placing the icon, defaults to 'append'. 61 var extIconPlacement = settings.extlink.extIconPlacement || 'append'; 62 63 // Find all links which are NOT internal and begin with http as opposed 64 // to ftp://, javascript:, etc. other kinds of links. 65 // When operating on the 'this' variable, the host has been appended to 66 // all links by the browser, even local ones. 67 // In jQuery 1.1 and higher, we'd use a filter method here, but it is not 68 // available in jQuery 1.0 (Drupal 5 default). 69 var external_links = []; 70 var mailto_links = []; 71 $('a:not([data-extlink]), area:not([data-extlink])', context).each(function (el) { 72 try { 73 var url = ''; 74 if (typeof this.href == 'string') { 75 url = this.href.toLowerCase(); 76 } 77 // Handle SVG links (xlink:href). 78 else if (typeof this.href == 'object') { 79 url = this.href.baseVal; 80 } 81 if (url.indexOf('http') === 0 82 && ((!url.match(internal_link) && !(extExclude && url.match(extExclude))) || (extInclude && url.match(extInclude))) 83 && !(extCssExclude && $(this).is(extCssExclude)) 84 && !(extCssExclude && $(this).parents(extCssExclude).length > 0) 85 && !(extCssExplicit && $(this).parents(extCssExplicit).length < 1)) { 86 external_links.push(this); 87 } 88 // Do not include area tags with begin with mailto: (this prohibits 89 // icons from being added to image-maps). 90 else if (this.tagName !== 'AREA' 91 && url.indexOf('mailto:') === 0 92 && !(extCssExclude && $(this).parents(extCssExclude).length > 0) 93 && !(extCssExplicit && $(this).parents(extCssExplicit).length < 1)) { 94 mailto_links.push(this); 95 } 96 } 97 // IE7 throws errors often when dealing with irregular links, such as: 98 // <a href="node/10"></a> Empty tags. 99 // <a href="http://user:[email protected]">example</a> User:pass syntax. 100 catch (error) { 101 return false; 102 } 103 }); 104 105 if (settings.extlink.extClass) { 106 Drupal.extlink.applyClassAndSpan(external_links, settings.extlink.extClass, extIconPlacement); 107 } 108 109 if (settings.extlink.mailtoClass) { 110 Drupal.extlink.applyClassAndSpan(mailto_links, settings.extlink.mailtoClass, extIconPlacement); 111 } 112 113 if (settings.extlink.extTarget) { 114 // Apply the target attribute to all links. 115 $(external_links).attr('target', settings.extlink.extTarget);
116 // Add rel attributes noopener and noreferrer. 117 $(external_links).attr('rel', function (i, val) { 118 // If no rel attribute is present, create one with the values noopener and noreferrer. 119 if (val == null) { 120 return 'noopener noreferrer'; 121 } 122 // Check to see if rel contains noopener or noreferrer. Add what doesn't exist. 123 if (val.indexOf('noopener') > -1 || val.indexOf('noreferrer') > -1) { 124 if (val.indexOf('noopener') === -1) { 125 return val + ' noopener'; 126 } 127 if (val.indexOf('noreferrer') === -1) { 128 return val + ' noreferrer'; 129 } 130 // Both noopener and noreferrer exist. Nothing needs to be added. 131 else { 132 return val; 133 } 134 } 135 // Else, append noopener and noreferrer to val. 136 else { 137 return val + ' noopener noreferrer'; 138 } 139 }); 140 } 141 142 Drupal.extlink = Drupal.extlink || {}; 143 144 // Set up default click function for the external links popup. This should be 145 // overridden by modules wanting to alter the popup. 146 Drupal.extlink.popupClickHandler = Drupal.extlink.popupClickHandler || function () { 147 if (settings.extlink.extAlert) { 148 return confirm(settings.extlink.extAlertText); 149 } 150 }; 151 152 $(external_links).click(function (e) { 153 return Drupal.extlink.popupClickHandler(e, this); 154 }); 155 }; 156 157 /** 158 * Apply a class and a trailing <span> to all links not containing images. 159 * 160 * @param {object[]} links 161 * An array of DOM elements representing the links. 162 * @param {string} class_name 163 * The class to apply to the links. 164 * @param {string} icon_placement 165 * 'append' or 'prepend' the icon to the link. 166 */ 167 Drupal.extlink.applyClassAndSpan = function (links, class_name, icon_placement) { 168 var $links_to_process; 169 if (Drupal.settings.extlink.extImgClass) { 170 $links_to_process = $(links); 171 } 172 else { 173 var links_with_images = $(links).find('img').parents('a'); 174 $links_to_process = $(links).not(links_with_images); 175 } 176 // Add data-extlink attribute. 177 $links_to_process.attr('data-extlink', ''); 178 var i; 179 var length = $links_to_process.length; 180 for (i = 0; i < length; i++) { 181 var $link = $($links_to_process[i]); 182 if ($link.css('display') === 'inline' || $link.css('display') === 'inline-block') { 183 if (Drupal.settings.extlink.extUseFontAwesome) { 184 if (class_name === Drupal.settings.extlink.mailtoClass) { 185 $link[icon_placement]('<span class="fa-' + class_name + ' extlink"><span class="fa fa-envelope-o" title="' + Drupal.settings.extlink.mailtoLabel + '"></span><span class="element-invisible">' + Drupal.settings.extlink.mailtoLabel + '</span></span>'); 186 } 187 else { 188 $link[icon_placement]('<span class="fa-' + class_name + ' extlink"><span class="fa fa-external-link" title="' + Drupal.settings.extlink.extLabel + '"></span><span class="element-invisible">' + Drupal.settings.extlink.extLabel + '</span></span>'); 189 } 190 } 191 else { 192 if (class_name === Drupal.settings.extlink.mailtoClass) { 193 $link[icon_placement]('<span class="' + class_name + '"><span class="element-invisible">' + Drupal.settings.extlink.mailtoLabel + '</span></span>'); 194 } 195 else { 196 $link[icon_placement]('<span class="' + class_name + '"><span class="element-invisible">' + Drupal.settings.extlink.extLabel + '</span></span>'); 197 } 198 } 199 } 200 } 201 }; 202 203 Drupal.behaviors.extlink = Drupal.behaviors.extlink || {}; 204 Drupal.behaviors.extlink.attach = function (context, settings) { 205 // Backwards compatibility, for the benefit of modules overriding extlink 206 // functionality by defining an "extlinkAttach" global function. 207 if (typeof extlinkAttach === 'function') { 208 extlinkAttach(context); 209 } 210 else { 211 Drupal.extlink.attach(context, settings); 212 } 213 }; 214 215})(jQuery);
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.