1var emailInput = $('input[type="email"]'); 2var scriptURL = 'https://cdnjs.cloudflare.com/ajax/libs/mailcheck/1.1.2/mailcheck.min.js'; 3var hasBeenInitiated = false; 4 5function initEmailSuggestions() { 6 emailInput.after('<p id="hint" class="emailsuggestions-hint"></p>'); 7 8 var emailList = ''; 9 if ( !emailInput.data('emailsuggestions') ) { 10 var countryCode = window.location.hostname.split('.').reverse()[0]; 11 if (countryCode=='com') countryCode = 'eu'; 12 else if (countryCode=='uk') countryCode = 'gb'; 13 $.ajax({ 14 url: Urls.getEmailSuggestionList, 15 data: {'countryCode':countryCode}, 16 async: false, 17 success: function(response){ 18 if(response){ 19 emailInput.attr('data-emailsuggestions',response); 20 } 21 } 22 }); 23 } 24 if(emailInput.data('emailsuggestions')) { 25 emailList = emailInput.data('emailsuggestions').split(','); 26 } 27 28 (function ($){ 29 // invalid email char test regexp 30 var INVALIDEMAILRE = 31 /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 32 // is support oninput event 33 var hasInputEvent = 'oninput' in document.createElement('input'); 34 // is IE 9 35 var ISIE9 = /MSIE 9.0/i.test(window.navigator.appVersion || window.navigator.userAgent); 36 37 /** 38 * is a number 39 * @param value 40 * @returns {boolean} 41 */ 42 function isNumber(value){ 43 return typeof value === 'number' && isFinite(value); 44 } 45 46 /** 47 * create popup tip 48 * @param input 49 * @param config 50 * @returns {*} 51 */ 52 function createTip(input, config){ 53 var tip = null; 54 55 // only create tip and binding event once 56 if (!input.data('data-mailtip')) { 57 var wrap = input.parent(); 58 59 // set parent node position 60 !/absolute|relative/i.test(wrap.css('position')) && wrap.css('position', 'relative'); 61 // off input autocomplete 62 input.attr('autocomplete', 'off'); 63 64 var offset = input.offset(); 65 var wrapOffset = wrap.offset(); 66 67 tip = $('<ul class="ui-mailtip" style="display: none; float: none; ' 68 + 'position:absolute; margin: 0; padding: 0; z-index: ' 69 + config.zIndex + '"></ul>'); 70 71 // insert tip after input 72 input.after(tip); 73 74 // set tip style 75 tip.css({ 76 top: offset.top - wrapOffset.top + input.outerHeight() + config.offsetTop, 77 left: offset.left - wrapOffset.left + config.offsetLeft, 78 width: config.width === 'input' ? input.outerWidth() - tip.outerWidth() + tip.width() : config.width 79 }); 80 81 // when width is auto, set min width equal input width 82 if (config.width === 'auto') { 83 tip.css('min-width', input.outerWidth() - tip.outerWidth() + tip.width()); 84 } 85 86 // binding event 87 tip.on('mouseenter mouseleave click', 'li', function (e){ 88 var selected = $(this); 89 90 switch (e.type) { 91 case 'mouseenter': 92 selected.addClass('hover'); 93 break; 94 case 'click': 95 var mail = selected.attr('title'); 96 97 input.val(mail).focus(); 98 config.onselected.call(input[0], mail); 99 break; 100 case 'mouseleave': 101 selected.removeClass('hover'); 102 break; 103 default: 104 break; 105 } 106 }); 107 108 // when on click if the target element not input, hide tip 109 $(document).on('click', function (e){ 110 if (e.target === input[0]) return; 111 tip.hide(); 112 }); 113 input.data('data-mailtip', tip); 114 } 115 return tip || input.data('data-mailtip'); 116 } 117 118 /** 119 * create mail list item 120 * @param value 121 * @param mails 122 * @returns {*} 123 */ 124 function createItems(value, mails){ 125 value = encodeURI(value); 126 var mail; 127 var domain; 128 var items = ''; 129 var atIndex = value.indexOf('@'); 130 var hasAt = atIndex !== -1; 131 var max = 3; 132 133 134 if (hasAt) { 135 domain = value.substring(atIndex + 1); 136 value = value.substring(0, atIndex); 137 } 138 139 for (var i = 0, len = mails.length; i < len; i++) { 140 mail = mails[i]; 141 if (hasAt && mail.indexOf(domain) !== 0) continue; 142 143 items += '<li title="' + value + '@' + mail + '"><p>' + value + '@' + mail + '</p></li>'; 144 145 if(i > max){ 146 break; 147 } 148 } 149 150 // active first item 151 return items.replace('<li', '<li class="active"'); 152 } 153 154 /** 155 * change list active state 156 * @param tip 157 * @param up 158 */ 159 function changeActive(tip, up){ 160 var itemActive = tip.find('li.active'); 161 162 if (up) { 163 var itemPrev = itemActive.prev(); 164 itemPrev = itemPrev.length ? itemPrev : tip.find('li:last'); 165 itemActive.removeClass('active'); 166 itemPrev.addClass('active'); 167 } else { 168 var itemNext = itemActive.next(); 169 itemNext = itemNext.length ? itemNext : tip.find('li:first'); 170 itemActive.removeClass('active'); 171 itemNext.addClass('active'); 172 } 173 } 174 175 /** 176 * toggle tip 177 * @param tip 178 * @param value 179 * @param mails 180 */ 181 function toggleTip(tip, value, mails){ 182 var atIndex = value.indexOf('@'); 183
184 // if input text is empty or has invalid char or begin with @ or more than two @, hide tip 185 if (!value 186 || atIndex === 0 187 || atIndex !== value.lastIndexOf('@') 188 || INVALIDEMAILRE.test(atIndex === -1 ? value : value.substring(0, atIndex))) { 189 tip.hide(); 190 } else { 191 var items = createItems(value, mails); 192 // if has match mails show tip 193 if (items) { 194 tip.html(items).show(); 195 } else { 196 tip.hide(); 197 } 198 } 199 } 200 201 /** 202 * exports 203 * @param config 204 * @returns {*} 205 */ 206 $.fn.mailtip = function (config) { 207 var defaults = { 208 mails: emailList, 209 onselected: $.noop, 210 width: 'auto', 211 offsetTop: -1, 212 offsetLeft: 0, 213 zIndex: 10 214 }; 215 216 config = $.extend({}, defaults, config); 217 config.zIndex = isNumber(config.zIndex) ? config.zIndex : defaults.zIndex; 218 config.offsetTop = isNumber(config.offsetTop) ? config.offsetTop : defaults.offsetTop; 219 config.offsetLeft = isNumber(config.offsetLeft) ? config.offsetLeft : defaults.offsetLeft; 220 config.onselected = $.isFunction(config.onselected) ? config.onselected : defaults.onselected; 221 config.width = config.width === 'input' || isNumber(config.width) ? config.width : defaults.width; 222 223 return this.each(function () { 224 var input = $(this); // input 225 var tip = createTip(input, config); // tip 226 227 // binding key down event 228 input.on('keydown', function (e) { 229 // if tip is visible do nothing 230 if (tip.css('display') === 'none') return; 231 232 switch (e.keyCode) { 233 // backspace 234 case 8: 235 // shit! ie9 input event has a bug, backspace do not trigger input event 236 if (ISIE9) { 237 input.trigger('input'); 238 } 239 break; 240 // tab 241 case 9: 242 tip.hide(); 243 break; 244 // up 245 case 38: 246 e.preventDefault(); 247 changeActive(tip, true); 248 break; 249 // down 250 case 40: 251 e.preventDefault(); 252 changeActive(tip); 253 break; 254 // enter 255 case 13: 256 e.preventDefault(); 257 var mail = tip.find('li.active').attr('title'); 258 259 input.val(mail).focus(); 260 tip.hide(); 261 config.onselected.call(this, mail); 262 break; 263 default: 264 break; 265 } 266 }); 267 268 // binding input or propertychange event 269 if (hasInputEvent) { 270 input.on('input', function (){ 271 toggleTip(tip, this.value, config.mails); 272 }); 273 } else { 274 input.on('propertychange', function (e){ 275 if (e.originalEvent.propertyName === 'value') { 276 toggleTip(tip, this.value, config.mails); 277 } 278 }); 279 } 280 281 // shit! ie9 input event has a bug, backspace do not trigger input event 282 if (ISIE9) { 283 input.on('keyup', function (e){ 284 if (e.keyCode === 8) { 285 toggleTip(tip, this.value, config.mails); 286 } 287 }); 288 } 289 }); 290 }; 291 }(jQuery)); 292 $(function (){ 293 emailInput.mailtip({ 294 onselected: function (mail){ // this is called when a suggestion is selected from the dropdown 295 $(this).change(); 296 $(this).blur(); 297 } 298 }); 299 }); 300 $.getScript(scriptURL, function() { 301 var hint = jQuery("#hint"); 302 303 emailInput.on('blur',function() { 304 hint.css('display', 'none').empty(); // hide hint initially 305 jQuery(this).mailcheck({ 306 suggested: function(element, suggestion) { 307 if(!hint.html()) { 308 // misspell - display hint element 309 var suggestion = window.Resources.EMAIL_AUTOCOMPLETE + " <span class='suggestion'>" + 310 "<span class='address'>" + suggestion.address + "</span>" 311 + "@<a href='#' class='domain'>" + suggestion.domain + 312 "</a></span>?"; 313 hint.html(suggestion).fadeIn(150); 314 } else { 315 // Subsequent errors 316 jQuery(".address").html(suggestion.address); 317 jQuery(".domain").html(suggestion.domain); 318 } 319 } 320 }); 321 }); 322 323 hint.on('click', '.domain', function() { 324 // Display with the suggestion and remove the hint 325 emailInput.val(jQuery(".suggestion").text()); 326 hint.fadeOut(200, function() { 327 jQuery(this).empty(); 328 }); 329 emailInput.change(); 330 emailInput.blur(); 331 return false;
332 }); 333 }).fail(function() { 334 console.error('Script file ' + scriptURL + ' has not loaded. Check if URL has to be updated'); 335 }); 336} 337 338emailInput.one('focusin', () => { 339 if (hasBeenInitiated) return; 340 initEmailSuggestions(); 341 hasBeenInitiated = true; 342});
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.