PageSourceSearch

https://www.paulaschoice.co.uk/on/demandware.static/Sites-paulasch…/emailsuggestion/emailsuggestiondropdown.js

js paulaschoice.co.uk collected 2026-09-26 05:12:19 UTC 11,017 bytes, 342 lines download raw bytes

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.