PageSourceSearch

https://wine2go.co/wp-content/plugins/optin-monster/assets/js/api_ver-2.1.5.js

js wine2go.co collected 2026-10-09 21:53:38 UTC 70,922 bytes, 1,647 lines download raw bytes

1/* ==========================================================
2 * api.js
3 * http://optinmonster.com/
4 * ==========================================================
5 * Copyright 2014 Thomas Griffin.
6 *
7 * Use of this file is bound by the Terms of Service agreed
8 * upon when purchasing OptinMonster.
9 * http://optinmonster.com/terms/
10 * ========================================================== */
11// Global variable to hold optins and determine their visibility.
12var OptinMonsterOptins = {};
13
14// Main OptinMonster API class for handling optin operations.
15function OptinMonster(){
16    // Holds all of the class properties.
17    this.public = {},
18
19    // The init method that loads the object class.
20    this.init = function(params){
21        // Set the optin properties.
22        for ( key in params ) {
23            this.public[key] = params[key];
24        }
25
26        // Only check for popup-type optins.
27        if ( 'sidebar' !== this.getProp('type') && 'post' !== this.getProp('type') ) {
28            // Only check against cookies if this is in live mode.
29            if ( ! this.getProp('preview') ) {
30                // Only process if this is a normal loading optin. If manually triggered, ignore cookie settings.
31                if ( ! this.getProp('click') ) {
32                    // If cookies are not enabled, we can't reliably determine optin visibility, so return early.
33                    if ( ! this.cookiesEnabled() ) {
34                        if ( ! this.getProp('test') ) {
35                            return;
36                        }
37                    }
38
39                    // If we have a cookie set and it is valid, bail out and do nothing.
40                    var global_cookie = this.getCookie('om-global-cookie'),
41                        cookie        = this.getCookie('om-' + this.getProp('id')),
42                        second        = this.getProp('second'),
43                        test          = this.getProp('test'),
44                        type          = this.getProp('type');
45
46                    // If on a mobile device and not a mobile type of optin, return early regardless of any other settings.
47                    if ( this.isMobile() && ! this.getProp('mobile') ) {
48                        return;
49                    }
50
51                    // If not on a mobile device but a mobile optin is present, return early.
52                    if ( ! this.isMobile() && this.getProp('mobile') ) {
53                        return;
54                    }
55
56                    // Check for 2nd pageview, and return early if it is the first pageview (meaning the "second" cookie does not exist yet).
57                    if ( second && ! test ) {
58                        if ( ! this.getCookie('om-second-' + this.getProp('id')) ) {
59                            return this.createCookie('om-second-' + this.getProp('id'), true, this.getProp('cookie'));
60                        }
61                    }
62
63                    // Now run our other optin-specific checks.
64                    if ( global_cookie || cookie ) {
65                        if ( ! test ) {
66                            if ( 'slide' !== type ) {
67                                return;
68                            }
69                        }
70                    }
71                }
72            }
73        }
74
75        // Load the optin now that the checks are complete.
76        this.run();
77    },
78
79    // Loads the optin.
80    this.run = function(){
81        // Prepare variables.
82        var self = this,
83            type = self.getProp('type');
84
85        // If this is a slide-in, set a handler to toggle its current visible state.
86        if ( 'slide' == type ) {
87            this.setProp('slide_open', false);
88        }
89
90        // Store the optin in the global variable and set its visibility to false by default.
91        OptinMonsterOptins[this.getProp('optin_js')] = { type: type, visible: false };
92
93        // Possibly load jQuery and handle the rest of the output based on response.
94        this.loadjQuery();
95    },
96
97    // Checks to see if jQuery is loaded and if it is a high enough version; if not, jQuery is loaded.
98    this.loadjQuery = function(){
99        // Store localized copy of our main object instance.
100        var self   = this,
101            loaded = false;
102
103        // If jQuery is not present or not the correct version, load it asynchronously and fire the rest of the app once jQuery has loaded.
104        if ( window.jQuery === undefined ) {
105            var om    = document.createElement('script');
106            om.src    = 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js';
107            om.onload = om.onreadystatechange = function(){
108                var s = this.readyState;
109                if (s) if (s != 'complete') if (s != 'loaded') return;
110                try {
111                    if ( ! loaded ) {
112                        self.loadjQueryHandler(false);
113                        loaded = true;
114                    }
115                } catch(e){}
116            };
117
118            // Attempt to append it to the <head>, otherwise append to the document.
119            (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(om);
120        } else if ( window.jQuery.fn.jquery !== '1.11.1' ) {
121            // Set the window jQuery property for event triggering.
122            this.public.ejQuery = window.jQuery;
123
124            // jQuery exists, but it is not the version we want, so we need to manage duplicate jQuery objects.
125            var om    = document.createElement('script');
126            om.src    = 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js';
127            om.onload = om.onreadystatechange = function(){
128                var s = this.readyState;
129                if (s) if (s != 'complete') if (s != 'loaded') return;
130                try {
131                    if ( ! loaded ) {
132                        self.loadjQueryHandler(true);
133                        loaded = true;
134                    }
135                } catch(e){}
136            };
137
138            // Attempt to append it to the <head>, otherwise append to the document.
139            (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(om);
140        } else {
141            // The version of jQuery loaded into the window is what we want to use, so we can just load the handler and output content.
142            self.public.$ = self.public.ejQuery = window.jQuery;
143            self.loadApp();
144        }
145    },
146
147    // Stores a localized copy of jQuery and removes any potential conflicts with other jQuery libraries.
148    this.loadjQueryHandler = function(exists){
149        // If jQuery already exists, don't overwrite the global but set noConflict to properly handle multiple versions.
150        if ( exists ) {
151            // Don't set global jQuery object - just store in our property.
152            this.public.$ = window.jQuery.noConflict(true);
153            this.loadApp();
154        } else {
155            // Store the global jQuery object since it does not exist yet.
156            jQuery = window.jQuery.noConflict(true);
157            this.public.$ = this.public.ejQuery = jQuery;
158            this.loadApp();
159        }
160    },
161
162    // Callback to load the content of our app into the page.
163    this.loadApp = function(){
164        // Store localized copy of our main object instance.
165        var self = this;
166
167        // Woot, we now have jQuery! Run our application inside of our jQuery callback to have full access to jQuery.
168        self.public.$(document).ready(function($){
169            self.runOptinMonster();
170        });
171    },
172
173    // Runs the OptinMonster JS engine!
174    this.runOptinMonster = function(){
175        // Store localized copy of our main object instance.
176        var self  = this,
177            click = self.getProp('click');
178
179        // Trigger event to say OptinMonster is initialized.
180        self.trigger('OptinMonsterInit');
181
182        // Initialize based on click or normal load.
183        if ( click ) {
184            self.manual();
185        } else {
186            self.load();
187        }
188    },
189
190    // Processes loading optins in manually via MonsterLinks.
191    this.manual = function(){
192        // Prepare variables.
193        var self = this,
194            data = {
195                optin_monster_ajax_action: 'get_optinmonster',
196                slug: self.getProp('optin')
197            },
198            success = self.manualSuccess(self),
199            error   = self.manualError(self);
200
201        // Make the request to retrieve the optin.
202        self.request(data, success, error);
203    },
204
205    // Processes the success callback for manually loading an optin on click.
206    this.manualSuccess = function(self){
207        // Prepare variables.
208        var $      = self.getProp('$'),
209            loaded = false;
210
211        // Return the callback.
212        return function(params){
213            // Set the optin properties.
214            for ( key in params.success ) {
215                self.public[key] = params.success[key];
216            }
217
218            // Set the global optin object with the proper type and set some property values (we want this to load immediately).
219            OptinMonsterOptins[self.getProp('optin_js')].type = self.getProp('type');
220            self.setProp('delay', 0);
221            self.setProp('exit', false);
222
223            // Load the WebFont loader and then proceed with the optin output.
224            var wf    = document.createElement('script');
225            wf.src    = 'http://ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js';
226            wf.onload = wf.onreadystatechange = function(){
227                var s = this.readyState;
228                if (s) if (s != 'complete') if (s != 'loaded') return;
229                try {
230                    // Only apply once.
231                    if ( ! loaded ) {
232                        // Place the optin HTML output into the DOM.
233                        $('body').append(self.getProp('html'));
234
235                        // Trigger event to say OptinMonster has been loaded successfully via click.
236                        self.trigger('OptinMonsterManualOptinSuccess');
237
238                        // Now proceed with loading the optin.
239                        self.load();
240
241                        // Set the loaded flag to true.
242                        loaded = true;
243                    }
244                } catch(e){}
245            };
246
247            // Attempt to append it to the <head>, otherwise append to the document.
248            (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(wf);
249        }
250    },
251
252    // Processes the error callback for manually loading an optin on click.
253    this.manualError = function(self){
254        // Return the callback.
255        return function(err, xhr, message){
256            // Trigger event to say OptinMonster has encountered an error processing the optin.
257            self.trigger('OptinMonsterManualOptinError');
258        };
259    },
260
261    // Loads an optin.
262    this.load = function(){
263        // Prepare variables.
264        var self = this;
265
266        // Sanitize the form.
267        self.sanitize();
268
269        // Runs fixes for IE.
270        self.iehotfix();
271
272        // Open the optin.
273        self.open();
274    },
275
276    // Sanitize form fields to ensure they will submit properly.
277    this.sanitize = function(){
278        // Prepare variables.
279        var self         = this,
280            $            = self.getProp('$'),
281            form_html    = $('#om-' + self.getProp('optin')),
282            submit_field = $('#om-' + self.getProp('optin')).find(':submit'),
283            name_attr    = submit_field.attr('name'),
284            name_id      = submit_field.attr('id');
285
286        // Fix any name attributes on the submit button.
287        if ( 'submit' == name_attr ) {
288            form_html.find(':submit').attr('name', 'submit-om');
289        }
290
291        // Fix any ID attributes on the submit button.
292        if ( 'submit' == name_id ) {
293            form_html.find(':submit').attr('id', 'submit-om');
294        }
295    },
296
297    // Adds hotfixes for IE bugs.
298    this.iehotfix = function(){
299        // If not IE, return early.
300        if ( ! this.isIE() ) {
301            return;
302        }
303
304        // Load the placeholder shim for IE.
305        this.loadPlaceholder();
306
307        // Apply the placeholder shim.
308        this.doPlaceholder();
309    },
310
311    // Opens the optin.
312    this.open = function(onclick){
313        // Prepare variables.
314        var self     = this,
315            exit     = self.getProp('exit'),
316            click    = self.getProp('click'),
317            optin_js = self.getProp('optin_js'),
318            delay    = 'slide' == self.getProp('type') ? 0 : self.getProp('delay'),
319            onclick  = onclick || false;
320
321        // If the popup is already opened, don't do anything.
322        if ( OptinMonsterOptins.hasOwnProperty(optin_js) && true === OptinMonsterOptins[optin_js].visible ) {
323	        return;
324        }
325
326        // Set delay to 0 if forced click or exit intent.
327        if ( onclick || exit ) {
328	        delay = 0;
329        }
330
331        // Only load if not a manual click optin.
332        if ( ! click || onclick ) {
333            // Wrap everything in a timeout to catch any optin loading delays.
334            setTimeout(function(){
335                // Possibly append the optin holder to the body and style.
336                if ( 'mobile' !== self.getProp('type') ) {
337                	self.appendHolder();
338                }
339
340                // If we have a custom HTML optin, we need to prepare it now.
341                if ( self.getProp('custom') ) {
342                    self.prepareCustomOptin();
343                }
344
345                // Trigger event that OptinMonster is now fully loaded and about to fire the open mechanism.
346                self.trigger('OptinMonsterLoaded');
347
348                // Handle the type of open.
349                if ( exit && ! click && ! onclick ) {
350                    self.exitOpen();
351                } else {
352                    self.normalOpen();
353                }
354            }, delay || 0);
355        }
356    },
357
358    // Handle the opening of exit intent optins.
359    this.exitOpen = function(){
360        // Prepare variables.
361        var self     = this,
362            $        = self.getProp('$'),
363            optin_js = self.getProp('optin_js'),
364            opened   = false;
365
366        // Load the exit intent handler.
367        $(document).on('mouseleave', function(e){
368            // Only trigger if leaving near the top of the page, a cookie has not been set or the optin is not yet open.
369            if ( e.clientY > (self.getProp('exit_sensitivity') || 20) || self.getCookie('om-' + self.getProp('id')) || self.getCookie('om-global-cookie') || OptinMonsterOptins.hasOwnProperty(optin_js) && true === OptinMonsterOptins[optin_js].visible || opened ) {
370                return;
371            }
372
373            // Set the flag that the optin has been opened once and cannot be opened again,
374            opened = true;
375
376            // Show (and possibly animate showing) the optin.
377            self.show(true);
378        });
379    },
380
381    // Handle the opening of normal optins.
382    this.normalOpen = function(){
383        // Prepare variables.
384    	var self = this,
385    		type = self.getProp('type'),
386    		$	 = self.getProp('$');
387
388        // Show (and possibly animate showing) the optin.
389        // Make a check for mobile optins to check the window scrolling feature first before showing the optin.
390        if ( 'mobile' == type && ! self.getProp('preview') ) {
391            self.setProp('dw', $(document).width());
392        	if ( ! $(window).scrollTop() ) {
393	        	self.show();
394        	} else {
395		        $(window).on('scroll.omMobile', function(){
396    		        clearTimeout($.data(this, 'omScrollTimer'));
397            	    $.data(this, 'omScrollTimer', setTimeout(function(){
398            	        self.show();
399            	    }, 300));
400		        });
401		    }
402        } else {
403	        self.show();
404        }
405    },
406
407    // Handle actually displaying the optin.
408    this.show = function(exit){
409        // Prepare variables.
410        var self     = this,
411            $        = self.getProp('$'),
412            id       = self.getProp('id'),
413            optin    = self.getProp('optin'),
414            optin_js = self.getProp('optin_js'),
415            type     = self.getProp('type'),
416            theme    = self.getProp('theme'),
417            preview  = self.getProp('preview'),
418            exit     = exit || false;
419
420        // If the popup is already opened, don't do anything.
421        if ( OptinMonsterOptins.hasOwnProperty(optin_js) && true === OptinMonsterOptins[optin_js].visible ) {
422	        return;
423        }
424
425        // If the global cookie has been set at some point between the time loading the page and actually showing this optin (and this is not a click event or preview), don't show it.
426        if ( self.getCookie('om-global-cookie') && ! self.getProp('click') && ! preview ) {
427            if ( 'sidebar' !== type && 'post' !== type ) {
428                return;
429            }
430        }
431
432        // Trigger event to say OptinMonster is about to be shown.
433        self.trigger('OptinMonsterBeforeShow');
434
435        // Determine the type of loading pattern based on exit intent or not.
436        if ( exit ) {
437            // Only process for lightbox and canvas optin types.
438            if ( 'lightbox' == type || 'canvas' == type ) {
439                // Check optin visibility to ensure no other popup optins are showing on the page at the same time.
440                if ( ! self.hasVisiblePopup() ) {
441                    // Immediately display the optin.
442                    $('#om-' + optin).show().css('display', 'block');
443                    $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').show().css('display', 'block');
444                    self.positionOptin();
445
446                    // Set the visibility of the optin to open.
447                    OptinMonsterOptins[self.getProp('optin_js')].visible = true;
448
449                    // Fix focus jumping.
450					self.fixFocusJumping();
451
452                    // Trigger event to say OptinMonster is now open.
453                    self.trigger('OptinMonsterOnShow');
454                }
455            } else if ( 'footer' == type || 'slide' == type ) {
456                // If an optin is successful with the slide-in, don't show it at all.
457                if ( ! self.getCookie('om-' + id + '-closed') ) {
458                    // Make the optin visible.
459                    $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').show().css('display', 'block');
460                    var position = preview ? 78 : 0;
461
462                    // Display the optin.
463                    $('#om-' + optin).css('bottom', '-' + $('#om-' + optin).outerHeight() + 'px').show().animate({ 'bottom' : parseInt(position) }, 300, function(){
464                        // Set the visibility of the optin to open.
465                        OptinMonsterOptins[self.getProp('optin_js')].visible = true;
466
467                        // Trigger event to say OptinMonster is now open.
468                        self.trigger('OptinMonsterOnShow');
469
470                        // Do some extra custom opening/closing magic for slide-in optins.
471                        if ( 'slide' == type ) {
472                        	// Register open/close handlers now.
473                            self.slideHandlers();
474
475                            setTimeout(function(){
476                               self.showSlide();
477                            }, 0);
478                        }
479                    });
480                }
481            }
482        } else {
483            if ( 'lightbox' == type || 'canvas' == type || 'mobile' == type ) {
484                // Check optin visibility to ensure no other popup optins are showing on the page at the same time.
485                if ( ! self.hasVisiblePopup() ) {
486                	if ( 'mobile' == type ) {
487			            // Style other items necessary for mobile optins.
488			            $('#om-' + optin + ', #om-' + optin + '-overlay').appendTo('body');
489			            $('#om-' + optin + '-overlay').height($(document).height()).show().css('display', 'block');
490			            $('#om-' + optin).show().css('display', 'block');
491
492			            // Fix scaling.
493			            if ( ! preview ) {
494			            	self.fixMobileScaling();
495			            }
496
497	                	// Fade the optin into view.
498	                    $('#om-' + type + '-' + theme + '-optin').hide().fadeIn(300, function(){
499	                        // Set the proper position of the optin.
500	                        $('#om-' + optin).css('top', $(document).scrollTop());
501
502	                        // Set the visibility of the optin to open.
503	                        OptinMonsterOptins[self.getProp('optin_js')].visible = true;
504
505	                        // Trigger event to say OptinMonster is now open.
506	                        self.trigger('OptinMonsterOnShow');
507	                    });
508                	} else {
509	                    // Fade the optin into view.
510	                    $('#om-' + optin).fadeIn(300, function(){
511	                        // Show the optin.
512	                        $(this).find('#om-' + type + '-' + theme + '-optin').show().css('display', 'block');
513	                        self.positionOptin();
514
515	                        // Set the visibility of the optin to open.
516	                        OptinMonsterOptins[self.getProp('optin_js')].visible = true;
517
518	                        // Fix focus jumping.
519							self.fixFocusJumping();
520
521	                        // Trigger event to say OptinMonster is now open.
522	                        self.trigger('OptinMonsterOnShow');
523	                    });
524	                }
525                }
526            } else if ( 'footer' == type || 'slide' == type ) {
527                // If an optin is successful with the slide-in, don't show it at all.
528                if ( ! self.getCookie('om-' + id + '-closed') || preview ) {
529                    // Make the optin visible.
530                    $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').show().css('display', 'block');
531                    var position = preview ? 78 : 0;
532
533                    // Display the optin.
534                    $('#om-' + optin).css('bottom', '-' + $('#om-' + optin).outerHeight() + 'px').show().animate({ 'bottom' : parseInt(position) }, 300, function(){
535                        // Set the visibility of the optin to open.
536                        OptinMonsterOptins[self.getProp('optin_js')].visible = true;
537
538                        // Trigger event to say OptinMonster is now open.
539                        self.trigger('OptinMonsterOnShow');
540
541                        // Do some extra custom opening/closing magic for slide-in optins.
542                        if ( 'slide' == type ) {
543                            // Register open/close handlers now.
544                            self.slideHandlers();
545
546                            // Open the slide-in optin.
547                            setTimeout(function(){
548                               self.showSlide();
549                            }, self.getProp('delay') || 0);
550                        }
551                    });
552                }
553            } else {
554                // Trigger event to say OptinMonster is now open.
555                self.trigger('OptinMonsterOnShow');
556            }
557        }
558
559        // Register the submit handler.
560        self.submit();
561
562        // Register the close handler.
563        self.close();
564
565        // Track the impression stats.
566        self.track();
567    },
568
569    // Fixes mobile scaling.
570    this.fixMobileScaling = function(){
571    	// Prepare variables.
572    	var self  = this,
573    		type  = this.getProp('type'),
574    		optin = this.getProp('optin'),
575    		$     = this.getProp('$');
576
577    	// If the meta viewport tag exists, return. This is a responsive site.
578    	var meta_exists = $('meta[name="viewport"]');
579    	if ( meta_exists.length > 0 ) {
580	    	return;
581    	}
582
583    	// Append our tag and start doing things.
584    	$('head').append('<meta id="optin-monster-viewport" name="viewport" content="width=device-width, initial-scale=1.0">');
585    	$('html, body').css('overflow', 'hidden');
586    },
587
588    // Fixes focus jumping.
589    this.fixFocusJumping = function(){
590	    // Prepare variables.
591	    var self  = this,
592	    	optin = self.getProp('optin'),
593	    	type  = self.getProp('type'),
594	    	$	  = self.getProp('$'),
595	    	pos   = $('body').css('position');
596
597	    // If this is not a mobile device, do nothing.
598	    if ( ! self.isMobile() ) {
599		    return;
600	    }
601
602	    // Do nothing if not the proper optin types.
603	    if ( 'lightbox' !== type && 'canvas' !== type ) {
604		    return;
605	    }
606
607	    // Store current position of window.
608	    self.setProp('dt', $(document).scrollTop());
609
610	    // Fix focus scrolling.
611	    $('html, body').css('overflow', 'hidden');
612	    window.scrollTo(0, 0);
613
614	    // Prevent window shifting on input, select and textarea blurs.
615	    $(document).on('focus.omFocusJump', 'input, select, textarea', function(){
616			$('#om-' + optin).css({ position: 'absolute', height: $(document).height() });
617		}).on('blur.omFocusJump', 'input, select, textarea', function(){
618			$('#om-' + optin).css({ position: 'fixed', height: '100%' });
619			$('html, body').css('overflow', 'hidden');
620		});
621    },
622
623    // Positions an optin according to the optin type.
624    this.positionOptin = function(){
625        // Prepare variables.
626        var self    = this,
627            $       = self.getProp('$'),
628            id      = self.getProp('id'),
629            optin   = self.getProp('optin'),
630            type    = self.getProp('type'),
631            theme   = self.getProp('theme'),
632            preview = self.getProp('preview'),
633            width   = $('#om-' + optin + ' .om-theme-' + theme).width(),
634            height  = $('#om-' + optin + ' .om-theme-' + theme).height(),
635            wheight = $(window).height(),
636            dims    = preview ? ((wheight - height) / 2) - 39 : (wheight - height) / 2;
637
638        // Position based on type and if the optin is taller than the window or not.
639        if ( height >= wheight ) {
640	        if ( 'lightbox' == type || 'canvas' == type ) {
641		        $('#om-' + optin).css({ overflow: 'scroll' });
642		        $('#om-' + optin + ' .optin-monster-powered-by').css({ bottom: -55, paddingBottom: 20 });
643	            $('#om-' + optin + ' .om-theme-' + theme + ', #om-' + optin + ' .optin-monster-success-overlay').css({
644	                top: 20,
645	                left: ($(window).width() - width) / 2,
646	                position: 'absolute'
647	            });
648	            $(window).resize(function(){
649		            $('#om-' + optin).css({ overflow: 'scroll' });
650		            $('#om-' + optin + ' .optin-monster-powered-by').css({ bottom: -55, paddingBottom: 20 });
651	                $('#om-' + optin + ' .om-theme-' + theme + ', #om-' + optin + ' .optin-monster-success-overlay').css({
652	                    top: 20,
653	                    left: ($(window).width() - $('#om-' + optin + ' .om-theme-' + theme).width()) / 2,
654	                    position: 'absolute'
655	                });
656	            });
657
658	            // Trigger event to say OptinMonster has now been positioned.
659	            self.trigger('OptinMonsterPositionOptin');
660	        } else {
661	            // Trigger event to say OptinMonster has now been positioned.
662	            self.trigger('OptinMonsterPositionOptin');
663	        }
664        } else {
665	        if ( 'lightbox' == type || 'canvas' == type ) {
666	            $('#om-' + optin + ' .om-theme-' + theme + ', #om-' + optin + ' .optin-monster-success-overlay').css({
667	                top: dims,
668	                left: ($(window).width() - width) / 2
669	            });
670	            $(window).resize(function(){
671		            var height  = $('#om-' + optin + ' .om-theme-' + theme).height(),
672						wheight = $(window).height();
673					if ( height >= wheight ) {
674						$('#om-' + optin).css({ overflow: 'scroll' });
675			            $('#om-' + optin + ' .optin-monster-powered-by').css({ bottom: -55, paddingBottom: 20 });
676		                $('#om-' + optin + ' .om-theme-' + theme + ', #om-' + optin + ' .optin-monster-success-overlay').css({
677		                    top: 20,
678		                    left: ($(window).width() - $('#om-' + optin + ' .om-theme-' + theme).width()) / 2,
679		                    position: 'absolute'
680		                });
681					} else {
682						dims = preview ? (($(window).height() - $('#om-' + optin + ' .om-theme-' + theme).height()) / 2) - 39 : ($(window).height() - $('#om-' + optin + ' .om-theme-' + theme).height()) / 2;
683		                $('#om-' + optin + ' .om-theme-' + theme + ', #om-' + optin + ' .optin-monster-success-overlay').css({
684		                    top: dims,
685		                    left: ($(window).width() - $('#om-' + optin + ' .om-theme-' + theme).width()) / 2
686		                });
687					}
688	            });
689
690	            // Trigger event to say OptinMonster has now been positioned.
691	            self.trigger('OptinMonsterPositionOptin');
692	        } else {
693	            // Trigger event to say OptinMonster has now been positioned.
694	            self.trigger('OptinMonsterPositionOptin');
695	        }
696	    }
697    },
698
699    // Registers the open/close slide-in handlers.
700    this.slideHandlers = function(){
701        // Prepare variables.
702        var self  = this,
703            $     = self.getProp('$'),
704            id    = self.getProp('id'),
705            optin = self.getProp('optin'),
706            type  = self.getProp('type'),
707            theme = self.getProp('theme');
708
709        // Register handler to close the optin.
710        $(document).on('click.closeOptin', '#om-' + optin + ' .om-slide-close-content, #om-' + optin + ' .om-close', function(e){
711            // Don't allow event bubbling.
712            if ( e.target !== this ) {
713                return;
714            }
715
716            e.preventDefault();
717
718            // Trigger event to say OptinMonster is about to close.
719            self.trigger('OptinMonsterBeforeClose');
720
721            // Set the optin to closed.
722            $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').removeClass('om-slide-open').addClass('om-slide-closed');
723
724            // Remove any success messages.
725            $('#om-' + optin).find('.optin-monster-success-overlay').remove();
726
727            // Run the cleanup method.
728            self.cleanup();
729        });
730
731        // Register handler to open the optin.
732        $(document).on('click.openOptin', '#om-' + optin + ' .om-slide-open-content', function(e){
733            // Don't allow event bubbling.
734            if ( e.target !== this ) {
735                return;
736            }
737
738            e.preventDefault();
739
740            // Trigger event to say OptinMonster is about to open.
741            self.trigger('OptinMonsterBeforeOpen');
742
743            // Set the optin to open.
744            $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').removeClass('om-slide-closed').addClass('om-slide-open');
745
746            // Set the visibility to open.
747            self.setProp('slide_open', true);
748        });
749    },
750
751    // Displays the slide-in optin.
752    this.showSlide = function(){
753        // Prepare variables.
754        var self  = this,
755            $     = self.getProp('$'),
756            id    = self.getProp('id'),
757            optin = self.getProp('optin'),
758            type  = self.getProp('type'),
759            theme = self.getProp('theme');
760
761        // Open up the optin if the cookie has not been set.
762        if ( ! self.getCookie('om-' + id) && ! self.getProp('slide_open') || self.getProp('preview') ) {
763            $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin').removeClass('om-slide-closed').addClass('om-slide-open');
764            self.setProp('slide_open', true);
765        }
766    },
767
768    // Handles optin submissions.
769    this.submit = function(){
770        // Prepare variables.
771        var self   = this,
772            $      = self.getProp('$'),
773            optin  = self.getProp('optin'),
774            type   = self.getProp('type'),
775            theme  = self.getProp('theme'),
776            custom = self.getProp('custom');
777
778        // Prevent submitting if in Preview mode.
779        if ( self.getProp('preview') ) {
780            return;
781        }
782
783        // Handle the submission process based on custom or native implementation.
784        if ( custom ) {
785            // Create flag to test if submitted yet or not.
786            var submitted = false;
787
788            // Register event on custom form submission.
789            $(document).on('submit.doCustomOptin', '.om-custom-html-form form', function(e){
790                if ( ! submitted ) {
791                    // Set submitted flag to true.
792                    submitted = true;
793
794                    // Trigger event to say OptinMonster is about to process an optin.
795                    self.trigger('OptinMonsterBeforeOptin');
796
797                    // Run a custom ajax request to capture the conversion for custom HTML forms.
798                    self.optin(e.target, true);
799
800                    // Prevent the default action AND return false to prevent form submission.
801                    e.preventDefault();
802                    return false;
803                } else {
804                    // Close out the optin based on the type of optin.
805                    if ( 'lightbox' == type || 'canvas' == type ) {
806                        $('#om-' + optin).fadeOut(300, self.onClose(self));
807                    } else if ( 'footer' == type || 'slide' == type ) {
808                        $('#om-' + optin).animate({ 'bottom' : '-' + $('#om-' + optin).outerHeight() + 'px' }, 300, self.onClose(self));
809                    }
810                }
811            });
812        } else {
813            // Process the native submission
814            $(document).on('click.doOptin', '#om-' + optin + ' #om-' + type + '-' + theme + '-optin-submit', function(e){
815                // Prevent the default event from occurring.
816                e.preventDefault();
817
818                // Trigger event to say OptinMonster is about to process an optin.
819                self.trigger('OptinMonsterBeforeOptin');
820
821                // Handle the action.
822                self.optin(e.target);
823            });
824        }
825    },
826
827    // Handles closing the optin.
828    this.close = function(close){
829        // Prepare variables.
830        var self  = this,
831            $     = self.getProp('$'),
832            optin = self.getProp('optin'),
833            type  = self.getProp('type'),
834            close = close || false;
835
836        // Prevent closing if in Preview mode.
837        if ( self.getProp('preview') ) {
838            return;
839        }
840
841        // If close is true, force closing the optin instead of registering it to a click event.
842        if ( close ) {
843            // Close out the optin based on the type of optin.
844            if ( 'lightbox' == type || 'canvas' == type || 'mobile' == type ) {
845                $('#om-' + optin).fadeOut(300, self.onClose);
846            } else if ( 'footer' == type || 'slide' == type ) {
847                $('#om-' + optin).animate({ 'bottom' : '-' + $('#om-' + optin).outerHeight() + 'px' }, 300, self.onClose);
848            }
849        } else {
850            // Close out the optin.
851            $(document).on('click.closeOptin', '#om-' + optin + ' .om-close, #om-' + optin + '.optin-monster-overlay', function(e){
852                // Don't allow event bubbling or closing by clicking on the overlay for mobile optins.
853                if ( e.target !== this || 'mobile' == type && $(e.target).hasClass('optin-monster-overlay') ) {
854                    return;
855                }
856
857                // Prevent the default from occurring.
858                e.preventDefault();
859
860                // Trigger event to say OptinMonster is about to close.
861                self.trigger('OptinMonsterBeforeClose');
862
863                // Close out the optin based on the type of optin.
864                if ( 'lightbox' == type || 'canvas' == type || 'mobile' == type ) {
865                    $('#om-' + optin).fadeOut(300, self.onClose(self));
866                } else if ( 'footer' == type ) {
867                    $('#om-' + optin).animate({ 'bottom' : '-' + $('#om-' + optin).outerHeight() + 'px' }, 300, self.onClose(self));
868                }
869            });
870        }
871    },
872
873    // Handles all of the close operations for optins, including setting cookies and visibility.
874    this.onClose = function(self){
875        return function(){
876	        // Prepare variables.
877	        var $ = self.getProp('$');
878
879            // Set cookies and visibility.
880            self.cleanup();
881
882            // If on a mobile optin, we need to do some extra cleanup.
883            if ( 'mobile' == self.getProp('type') ) {
884                // Prepare variables.
885            	var $ = self.getProp('$'),
886            		w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
887                    d = self.getProp('dw'),
888                    s = Math.round((w/d) * 100) / 100;
889
890                // Unbind our scroll event.
891                $(window).off('scroll.omMobile');
892
893                // If our custom viewport tag exists, reset scaling back to the proper state.
894                if ( $('#optin-monster-viewport').length > 0 ) {
895	            $('#optin-monster-viewport').attr('content', 'width=device-width, initial-scale=' + s + ', minimum-scale=' + s + ', maximum-scale=' + s);
896	                $('html, body').css('overflow', '');
897
898	                // Reset user zooming.
899	                setTimeout(function(){
900    	                $('#optin-monster-viewport').attr('content', 'width=device-width, maximum-scale=10.0');
901	                }, 1000);
902                }
903
904                // Hide the overlay.
905	            $('#om-' + self.getProp('optin') + '-overlay').hide();
906            }
907
908            // Unbind our focus fix jump handler.
909			if ( self.isMobile() ) {
910				if ( 'lightbox' == self.getProp('type') || 'canvas' == self.getProp('type') ) {
911					$(document).scrollTop(self.getProp('dt'));
912				}
913
914				$(document).off('focus.omFocusJump');
915				$(document).off('blur.omFocusJump');
916				$('html, body').css('overflow', '');
917			}
918
919            // Trigger the optin as closed.
920            self.trigger('OptinMonsterOnClose');
921        };
922    },
923
924    // Run some cleanup to set cookies and optin visibility.
925    this.cleanup = function(success){
926        // Prepare variables.
927        var self  = this,
928            $     = self.getProp('$'),
929            id    = self.getProp('id'),
930            scs   = success || false;
931
932        // Set the visibility of the optin back to closed.
933        OptinMonsterOptins[self.getProp('optin_js')].visible = false;
934
935        // If on a mobile optin, make sure we unbind our scroll event at all times.
936        if ( 'mobile' == self.getProp('type') ) {
937            $(window).off('scroll.omMobile');
938        }
939
940        // If the cookie value is 0, don't set any cookies.
941        if ( 0 === self.getProp('cookie') ) {
942            return;
943        }
944
945        // Set the cookie for the optin.
946        self.createCookie('om-' + id, true, self.getProp('cookie'));
947
948        // If using a clone, make sure the clone has a cookie as well to prevent it from displaying.
949        if ( self.getProp('clones') ) {
950            $.each(self.getProp('clones'), function(i, id){
951                if ( 0 === id.length ) {
952                    return;
953                }
954                self.createCookie('om-' + id, true, self.getProp('cookie'));
955            });
956        }
957
958        // If the global setting is populated (and this is a success cleanup), set a global cookie.
959        if ( self.getProp('global_cookie') && scs ) {
960            self.createCookie('om-global-cookie');
961        }
962
963        // If a success cleanup and the optin type is slide, set another cookie to prevent it from displaying period.
964        if ( scs && 'slide' == self.getProp('type') ) {
965            self.createCookie('om-' + id + '-closed', true, self.getProp('cookie'));
966        }
967    },
968
969    // Track impression stats for optins.
970    this.track = function(conversion){
971        // If we have already tracked this optin, are in preview mode or test mode, don't do anything.
972        if ( this.getProp('tracked') || this.getProp('preview') ) {
973            return;
974        }
975
976        // Prepare variables.
977        var self       = this,
978            $          = self.getProp('$'),
979            optin      = self.getProp('optin'),
980            ga         = self.getProp('ga_uaid'),
981            conversion = conversion || false,
982            data       = {
983                optin_monster_ajax_action: 'track_optinmonster',
984                optin_id:                  self.getProp('id'),
985                post_id:                   self.getProp('post_id'),
986                referrer:                  window.location.href,
987                user_agent:                navigator.userAgent,
988                previous:                  document.referer
989            };
990
991        // Make the ajax request to track the data. If using Google Analytics, send to GA, otherwise track locally.
992        if ( ga ) {
993            self.trackGoogleAnalytics(ga, conversion);
994        } else {
995            self.request(data);
996        }
997
998        // Fire an event to say the OptinMonster is about to track stats.
999        self.trigger('OptinMonsterTracked');
1000    },
1001
1002    // Method for tracking impression data via Google Analytics.
1003    this.trackGoogleAnalytics = function(id, track){
1004        // Prepare variables.
1005        var self     = this,
1006            type     = track ? 'conversion' : 'impression',
1007            campaign = self.getProp('campaign') || self.getProp('optin'),
1008            init     = self.getProp('ga_init');
1009
1010        // Create a custom event tracker and dimensions if it has not been initialized.
1011        if ( ! init ) {
1012            ga('create', id, 'auto', { 'name' : 'omTracker' });
1013            ga('omTracker.set', {
1014                'appName':    self.getProp('app_name'),
1015                'appId':      self.getProp('app_id'),
1016                'appVersion': self.getProp('app_version')
1017            });
1018            self.setProp('ga_init', true);
1019        }
1020
1021        // Send the event tracking data to Google Analytics.
1022        ga('omTracker.send', 'event', campaign, type, self.getProp('id').toString());
1023
1024        // Trigger event for type of tracking that has just occurred.
1025        if ( 'impression' == type ) {
1026	        self.trigger('OptinMonsterTrackedImpression');
1027        } else {
1028	        self.trigger('OptinMonsterTrackedConversion');
1029        }
1030    },
1031
1032    // Handles the actual optin process for any type of optin.
1033    this.optin = function(target, custom){
1034        // Prepare variables.
1035        var self   = this,
1036            $      = self.getProp('$'),
1037            optin  = self.getProp('optin'),
1038            custom = custom || false;
1039
1040        // Prevent submitting if in Preview mode.
1041        if ( self.getProp('preview') ) {
1042            return;
1043        }
1044
1045        // Output the loading icon and styles.
1046        self.loading(target);
1047
1048        // Prepare the ajax data variable and callbacks.
1049        var data = {
1050                optin_monster_ajax_action: 'do_optinmonster',
1051                optin_id:                  self.getProp('id'),
1052                post_id:                   self.getProp('post_id'),
1053                referrer:                  window.location.href,
1054                user_agent:                navigator.userAgent,
1055                previous:                  document.referrer,
1056                email:                     $('#om-' + optin + ' #om-' + self.getProp('type') + '-' + self.getProp('theme') + '-optin-email').val(),
1057                name:                      $('#om-' + optin + ' #om-' + self.getProp('type') + '-' + self.getProp('theme') + '-optin-name').val()
1058            },
1059            success = false,
1060            error   = false;
1061
1062        // Handle the submission differently based on custom vs native implementation.
1063        if ( custom ) {
1064            // Prepare the callbacks.
1065            success = self.optinCustomSuccess(self, target);
1066        } else {
1067            // Verify the fields. If there is an error, output the error.
1068            var error = self.verify();
1069            if ( error ) {
1070                // Return and output the error response.
1071                return self.error(target, error);
1072            }
1073
1074            // Prepare the callbacks.
1075            success = self.optinSuccess(self, target);
1076            error   = self.optinError(self, target);
1077        }
1078
1079        // Make the request.
1080        self.request(data, success, error);
1081    },
1082
1083    // Handle any errors with the optin output.
1084    this.error = function(target, error){
1085        // Prepare variables.
1086        var self   = this,
1087            $      = self.getProp('$'),
1088            submit = $(target),
1089            optin  = self.getProp('optin');
1090
1091        // Remove the loading icon.
1092        self.removeLoading(target);
1093
1094        // Output the error message on the screen.
1095        submit.parent().append('<p class="optin-monster-error" style="font-family:Georgia;font-size:13px;font-style:italic;color:#ff0000;margin:10px 0;text-align:center;line-height:18px;">' + error + '</p>');
1096
1097        // Trigger the error event.
1098        self.trigger('OptinMonsterOnError');
1099    },
1100
1101    // Output the loading icon and overlay.
1102    this.loading = function(target){
1103        // Prepare variables.
1104        var self     = this,
1105            $        = self.getProp('$'),
1106            submit   = $(target),
1107            position = submit.position(),
1108            margin   = parseInt(submit.css('marginTop')),
1109            width    = submit.outerWidth(),
1110            height   = submit.outerHeight();
1111
1112        // Remove any error messages.
1113        $('#om-' + self.getProp('optin')).find('.optin-monster-error').remove();
1114
1115        // Add the loading icon overlay on the button.
1116        submit.after('<span class="optin-monster-loading"></span>').css('opacity', '.25');
1117        $('#om-' + self.getProp('optin')).find('.optin-monster-loading').css({ width: width, height: height, top: position.top + margin, left: position.left, background: 'url(' + self.getProp('preloader') + ') no-repeat 50% 50%', position: 'absolute', zIndex: 84736365452, backgroundSize: '20px' });
1118    },
1119
1120    // Verifies that all fields are populated correctly before proceeding to process the optin.
1121    this.verify = function(){
1122        // Prepare variables.
1123        var self   = this,
1124            $      = self.getProp('$'),
1125            optin  = self.getProp('optin'),
1126            type   = self.getProp('type'),
1127            theme  = self.getProp('theme'),
1128            name   = $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin-name'),
1129            email  = $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin-email'),
1130            honeye = $('#om-' + type + '-' + theme + '-optin').find('input[name="email"]').val(),
1131            honeyw = $('#om-' + type + '-' + theme + '-optin').find('input[name="website"]').val(),
1132            ret    = false;
1133
1134        // If the name field is present, verify that it is filled out.
1135        if ( name && name.length > 0 ) {
1136            if ( name.val().length == 0 ) {
1137                ret = self.getProp('name_error') || self.getProp('error');
1138            }
1139        }
1140
1141        // If the email field is present, verify that the email address is correct.
1142        if ( email && email.length > 0 ) {
1143            if ( email.val().length == 0 || ! self.isValidEmail(email.val()) ) {
1144                ret = self.getProp('email_error') || self.getProp('error');
1145            }
1146        }
1147
1148        // If either of the honeypot fields are filled in, return an error.
1149        if ( honeye && honeye.length > 0 || honeyw && honeyw.length > 0 ) {
1150	        ret = self.getProp('bot_error') || self.getProp('error');
1151        }
1152
1153        // Return the error response.
1154        return ret;
1155    },
1156
1157    // Remove the loading icon from view.
1158    this.removeLoading = function(target){
1159        // Prepare variables.
1160        var self   = this,
1161            $      = self.getProp('$'),
1162            submit = $(target);
1163
1164        // Remove the loading icon helper and holder.
1165        submit.css('opacity', '1');
1166        $('#om-' + self.getProp('optin')).find('.optin-monster-loading').remove();
1167    },
1168
1169    // Handle the optin success callback.
1170    this.optinSuccess = function(self, target){
1171        // Prepare variables.
1172        var $     = self.getProp('$'),
1173            optin = self.getProp('optin'),
1174            type  = self.getProp('type'),
1175            theme = self.getProp('theme');
1176
1177        // Return the callback.
1178        return function(res){
1179            // If for some reason we do not receive a response or the response is empty, return with an error.
1180            if ( ! res || $.isEmptyObject(res) ) {
1181                return self.error(target, self.getProp('error'));
1182            }
1183
1184            // If we have an error, output the error message.
1185            if ( res && res.error ) {
1186                return self.error(target, res.error);
1187            }
1188
1189            // Handle the success pieces of the optin.
1190            self.cleanup(true);
1191
1192            // Trigger event to say OptinMonster has processed the optin successfully.
1193            self.trigger('OptinMonsterOptinSuccess');
1194
1195            // If using GA, track the conversion.
1196            if ( self.getProp('ga_id') ) {
1197                self.trackGoogleAnalytics(self.getProp('ga_uaid'), true);
1198            }
1199
1200            // If a redirect is specified, redirect to the specified page.
1201            if ( self.getProp('redirect') ) {
1202                // Trigger event to say OptinMonster is about to redirect to the success page.
1203                self.trigger('OptinMonsterOnRedirect');
1204
1205                // Possibly append lead data to the redirect url.
1206                var redirect = self.getProp('redirect'),
1207                	pass 	 = self.getProp('redirect_pass');
1208                if ( pass && res && res.success && ! $.isEmptyObject(res.success) ) {
1209                	var i   = 0,
1210                		sep = '&';
1211	                for ( key in res.success ) {
1212		                if ( 0 == i ) {
1213			                if ( redirect.indexOf('?') < 0 ) {
1214				                sep = '?';
1215			                }
1216		                } else {
1217			                sep = '&';
1218		                }
1219			            redirect = redirect + sep + key + '=' + res.success[key];
1220			            i++;
1221	                }
1222                }
1223
1224                // Redirect the user.
1225                window.location.href = redirect;
1226            } else {
1227                // If we have a success message, fade in the success message, otherwise close the optin.
1228                if ( self.getProp('success') ) {
1229                    self.successMessage(target);
1230                } else {
1231                    self.close(true);
1232
1233                    // Remove the loading icon.
1234                    self.removeLoading(target);
1235                }
1236
1237                // Trigger event to say OptinMonster has processed the optin successfully and has closed.
1238                self.trigger('OptinMonsterOptinSuccessClose');
1239            }
1240        };
1241    },
1242
1243    // Handle outputting success messages for the optin.
1244    this.successMessage = function(target){
1245        // Prepare variables.
1246        var self      = this,
1247            $         = self.getProp('$'),
1248            optin     = self.getProp('optin'),
1249            type      = self.getProp('type'),
1250            theme     = self.getProp('theme'),
1251            container = $('#om-' + optin + ' #om-' + type + '-' + theme + '-optin'),
1252            position  = container.position(),
1253            width     = container.outerWidth(),
1254            height    = container.outerHeight(),
1255            zindex    = 'sidebar' == type || 'post' == type ? 7271832 : 1000098373462;
1256
1257        // Remove the old close button.
1258        if ( 'slide' !== type ) {
1259            $('#om-' + optin).find('.om-close').remove();
1260        }
1261
1262        // Prepare the success message overlay and actual success message.
1263        var overlay = ( 'sidebar' == type || 'post' == type ) ? '<div class="optin-monster-success-overlay" style="display:none;"></div>' : '<div class="optin-monster-success-overlay" style="display:none;"><a href="#" class="om-close om-success-close">&times;</a></div>',
1264            message = self.getProp('success');
1265
1266        // Output the overlay.
1267        container.after(overlay);
1268
1269        // Style the new overlay.
1270        $('#om-' + optin).find('.optin-monster-success-overlay').css({ width: width, height: height, top: position.top, left: position.left, background: '#fff', position: 'absolute', zIndex: zindex, padding: '0px 20px', opacity: 0, display: 'block' }).append('<div class="optin-monster-success-message">' + message + '</div>');
1271
1272        // Position the content inside of the div to be vertically centered.
1273        $('#om-' + optin).find('.optin-monster-success-message').css({ 'margin-top': (height - $('#om-' + optin).find('.optin-monster-success-message').height()) / 2 });
1274
1275        // Display the overlay.
1276        $('#om-' + optin).find('.optin-monster-success-overlay').fadeTo(300, 1, function(){
1277            // Remove the loading icon.
1278            self.removeLoading(target);
1279
1280            // Initialize social services if neeeded.
1281            self.socialServices();
1282        });
1283
1284        // Bind to window resize to ensure the success message is always the proper dimensions.
1285        $(window).resize(function(){
1286            $('.optin-monster-success-overlay').css({ width: $('#om-' + type + '-' + theme + '-optin').outerWidth(), height: $('#om-' + type + '-' + theme + '-optin').outerHeight(), top: $('#om-' + type + '-' + theme + '-optin').position().top, left: $('#om-' + type + '-' + theme + '-optin').position().left });
1287            $('.optin-monster-success-message').css({ 'margin-top': ($('#om-' + type + '-' + theme + '-optin').outerHeight() - $('.optin-monster-success-message').height()) / 2 });
1288        });
1289    },
1290
1291    // Handle the custom HTML optin success callback.
1292    this.optinCustomSuccess = function(self, target){
1293        // Prepare variables.
1294        var $ = self.getProp('$');
1295
1296        // Return the callback.
1297        return function(res){
1298            // Trigger event to say OptinMonster has processed the optin.
1299            self.trigger('OptinMonsterOptinSuccess');
1300
1301            // If using GA, track the conversion.
1302            if ( self.getProp('ga_id') ) {
1303                self.trackGoogleAnalytics(self.getProp('ga_uaid'), true);
1304            }
1305
1306            // Resubmit the form with extra data passed to it.
1307            $(target).submit();
1308        };
1309    },
1310
1311    // Handle the optin error callback.
1312    this.optinError = function(self, target){
1313        // Prepare variables.
1314        var $     = self.getProp('$'),
1315            optin = self.getProp('optin'),
1316            type  = self.getProp('type'),
1317            theme = self.getProp('theme');
1318
1319        // Return the callback.
1320        return function(err, xhr, message){
1321            // Trigger event to say OptinMonster has encountered an error processing the optin.
1322            self.trigger('OptinMonsterOptinError');
1323
1324            return self.error(target, self.getProp('ajax_error') + message);
1325        };
1326    },
1327
1328    // Utility method for making ajax requests.
1329    this.request = function(data, success_cb, error_cb){
1330        // Prepare variables.
1331        var self       = this,
1332            $          = self.getProp('$'),
1333            ajax       = {
1334                url:      self.getProp('ajax'),
1335                data:     data,
1336                cache:    false,
1337                type:     'POST',
1338                dataType: 'json',
1339                timeout:  30000
1340            },
1341            success_cb = success_cb || false,
1342            error_cb   = error_cb   || false;
1343
1344        // Set success callback if supplied.
1345        if ( success_cb ) {
1346            ajax.success = success_cb;
1347        }
1348
1349        // Set error callback if supplied.
1350        if ( error_cb ) {
1351            ajax.error = error_cb;
1352        }
1353
1354        // Make the ajax request.
1355        $.ajax(ajax);
1356    },
1357
1358    // Appends the optin holder to the <body> tag on the page.
1359    this.appendHolder = function(){
1360        var $      = this.getProp('$')
1361            type   = this.getProp('type'),
1362            styles = false;
1363
1364        // Prepare the styles.
1365        if ( 'lightbox' == type || 'canvas' == type ) {
1366            styles = { 'position' : 'fixed', 'z-index' : '7371832', 'top' : '0', 'left' : '0', 'zoom' : '1', 'width' : '100%', 'height' : '100%', 'margin' : '0', 'padding' : '0' };
1367        } else if ( 'footer' == type ) {
1368            styles = { 'position' : 'fixed', 'z-index' : '7371832', 'bottom' : '0', 'left' : '0', 'zoom' : '1', 'width' : '100%', 'margin' : '0', 'padding' : '0' };
1369        }
1370
1371        // If we have styles, output them now.
1372        if ( styles ) {
1373            $('#om-' + this.getProp('optin')).css(styles).appendTo('body');
1374        }
1375
1376        // Fire event for handling styles.
1377        this.trigger('OptinMonsterAppendHolder');
1378    },
1379
1380    // Prepare custom optin output.
1381    this.prepareCustomOptin = function(){
1382        // Store localized copy of our main object instance.
1383        var self   = this,
1384            optin  = self.getProp('optin'),
1385            $      = self.getProp('$'),
1386            inputs = $('#om-' + optin + ' input[data-om-render=label]');
1387
1388        // Only proceed if we have inputs to parse.
1389        if ( inputs.length > 0 ) {
1390            // Load the element changer.
1391            self.loadElementChange();
1392
1393            // Loop through each input and make adjustments as necessary.
1394            inputs.each(function(){
1395                if ( $.fn.changeElementType ) {
1396                    $(this).changeElementType('label');
1397                }
1398            });
1399
1400            // Now convert the labels to their proper format.
1401            $('#om-' + optin + ' label[data-om-render=label]').each(function(){
1402                $(this).text($(this).attr('value')).removeAttr('value type');
1403            });
1404        }
1405
1406        // Trigger event to say OptinMonster has finished preparing custom optins.
1407        self.trigger('OptinMonsterCustomDone');
1408    },
1409
1410    // Polling helper for executing at certain intervals.
1411    this.poll = (function(){
1412        var timer = 0;
1413        return function(callback, ms){
1414            clearInterval(timer);
1415            timer = setInterval(callback, ms);
1416        };
1417    })(),
1418
1419    // Tests the validity of an email address entered by the user.
1420    this.isValidEmail = function(email){
1421        return (new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i)).test(email);
1422    },
1423
1424    // Sets cookies.
1425    this.createCookie = function(name, value, days){
1426        // If test mode, do nothing.
1427        if ( this.getProp('test') ) {
1428            return;
1429        }
1430
1431        // If we have a days value, set it in the expiry of the cookie.
1432        if ( days ) {
1433            var date = new Date();
1434            date.setTime(date.getTime() + (days*24*60*60*1000));
1435            var expires = '; expires=' + date.toGMTString();
1436        } else {
1437            var expires = '';
1438        }
1439
1440        // Write the cookie.
1441        document.cookie = name + '=' + value + expires + '; path=/';
1442    },
1443
1444    // Retrieves cookies.
1445    this.getCookie = function(name){
1446        var nameEQ = name + '=';
1447        var ca = document.cookie.split(';');
1448        for ( var i = 0; i < ca.length; i++ ) {
1449            var c = ca[i];
1450            while ( c.charAt(0) == ' ' ) {
1451                c = c.substring(1, c.length);
1452            }
1453            if ( c.indexOf(nameEQ) == 0 ) {
1454                return c.substring(nameEQ.length, c.length);
1455            }
1456        }
1457
1458        return null;
1459    },
1460
1461    // Removes cookies.
1462    this.removeCookie = function(name){
1463        this.createCookie(name, '', -1);
1464    },
1465
1466    // Generic logging utility.
1467    this.log = function(text){
1468        (typeof console === 'object') ? console.log(text) : '';
1469    },
1470
1471    // Generic event triggering utility for OptinMonster.
1472    this.trigger = function(event_name){
1473        var self = this;
1474        self.public.ejQuery(document).trigger(event_name, [self.public, self]);
1475    },
1476
1477    // Loads the element changer.
1478    this.loadElementChange = function(){
1479        (function(a){a.fn.changeElementType=function(c){var b={};a.each(this[0].attributes,function(e,d){b[d.nodeName]=d.nodeValue});this.replaceWith(function(){return a('<'+c+'/>',b).append(a(this).contents())})}})(this.getProp('$'));
1480    }
1481
1482    // Checks to ensure cookies are enabled for the current visitor.
1483    this.cookiesEnabled = function(){
1484        var cookieEnabled = (navigator.cookieEnabled) ? true : false;
1485        if ( typeof navigator.cookieEnabled == 'undefined' && ! cookieEnabled ) {
1486            document.cookie = 'testcookie';
1487            cookieEnabled   = (document.cookie.indexOf('testcookie') != -1) ? true : false;
1488        }
1489        return (cookieEnabled);
1490    },
1491
1492    // Retrieves properties inside of the class.
1493    this.getProp = function(name){
1494        return this.public.hasOwnProperty(name) ? this.public[name] : false;
1495    },
1496
1497    // Set properties inside of the class.
1498    this.setProp = function(name, value){
1499        this.public[name] = value;
1500    },
1501
1502    // Mobile device check.
1503    this.isMobile = function(){
1504        var check = false;
1505        (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check=true})(navigator.userAgent||navigator.vendor||window.opera);
1506        return check;
1507    },
1508
1509    // Checks to see if a popup is visible or not.
1510    this.hasVisiblePopup = function(){
1511        // Get all optins currently visible and check against their type.
1512        var visible = [],
1513            $       = this.getProp('$'),
1514            i       = 0;
1515
1516        // Loop through and grab all visible optins.
1517        for ( var prop in OptinMonsterOptins ) {
1518            if ( OptinMonsterOptins[prop].hasOwnProperty('visible') ) {
1519                if ( true === OptinMonsterOptins[prop]['visible'] ) {
1520                    visible[i] = OptinMonsterOptins[prop]['type'];
1521                    i++;
1522                }
1523            }
1524        }
1525
1526        // Return the flag based on if the type of optin is visible or not.
1527        return $.inArray('lightbox', visible) > -1 || $.inArray('canvas', visible) > -1 || false;
1528    },
1529
1530    // Placeholder polyfill for IE 8/9.
1531    this.loadPlaceholder = function(){
1532        var self = this,
1533            $    = self.getProp('$');
1534        !function(e,a,t){function l(e){var a={},l=/^jQuery\d+$/;return t.each(e.attributes,function(e,t){t.specified&&!l.test(t.name)&&(a[t.name]=t.value)}),a}function r(e,a){var l=this,r=t(l);if(l.value==r.attr("placeholder")&&r.hasClass("placeholder"))if(r.data("placeholder-password")){if(r=r.hide().next().show().attr("id",r.removeAttr("id").data("placeholder-id")),e===!0)return r[0].value=a;r.focus()}else l.value="",r.removeClass("placeholder"),l==d()&&l.select()}function o(){var e,a=this,o=t(a),d=this.id;if(""==a.value){if("password"==a.type){if(!o.data("placeholder-textinput")){try{e=o.clone().attr({type:"text"})}catch(c){e=t("<input>").attr(t.extend(l(this),{type:"text"}))}e.removeAttr("name").data({"placeholder-password":o,"placeholder-id":d}).bind("focus.placeholder",r),o.data({"placeholder-textinput":e,"placeholder-id":d}).before(e)}o=o.removeAttr("id").hide().prev().attr("id",d).show()}o.addClass("placeholder"),o[0].value=o.attr("placeholder")}else o.removeClass("placeholder")}function d(){try{return a.activeElement}catch(e){}}var c,n,i="[object OperaMini]"==Object.prototype.toString.call(e.operamini),p="placeholder"in a.createElement("input")&&!i,u="placeholder"in a.createElement("textarea")&&!i,h=t.fn,s=t.valHooks,v=t.propHooks;p&&u?(n=h.placeholder=function(){return this},n.input=n.textarea=!0):(n=h.placeholder=function(){var e=this;return e.filter((p?"textarea":":input")+"[placeholder]").not(".placeholder").bind({"focus.placeholder":r,"blur.placeholder":o}).data("placeholder-enabled",!0).trigger("blur.placeholder"),e},n.input=p,n.textarea=u,c={get:function(e){var a=t(e),l=a.data("placeholder-password");return l?l[0].value:a.data("placeholder-enabled")&&a.hasClass("placeholder")?"":e.value}
1534,set:function(e,a){var l=t(e),c=l.data("placeholder-password");return c?c[0].value=a:l.data("placeholder-enabled")?(""==a?(e.value=a,e!=d()&&o.call(e)):l.hasClass("placeholder")?r.call(e,!0,a)||(e.value=a):e.value=a,l):e.value=a}},p||(s.input=c,v.value=c),u||(s.textarea=c,v.value=c),t(function(){t(a).delegate("form","submit.placeholder",function(){var e=t(".placeholder",this).each(r);setTimeout(function(){e.each(o)},10)})}),t(e).bind("beforeunload.placeholder",function(){t(".placeholder").each(function(){this.value=""})}))}(this,document,$);
1535    },
1536
1537    // Ensure that the placeholder polyfill is added.
1538    this.doPlaceholder = function(){
1539        // Store localized copy of our main object instance.
1540        var self   = this,
1541            $      = self.getProp('$'),
1542            fields = $('#om-' + self.getProp('optin') + ' input');
1543
1544        if ( fields.length > 0 && $.fn.placeholder ) {
1545            fields.each(function(){
1546                $(this).placeholder();
1547            });
1548        }
1549
1550        // Trigger event to say OptinMonster placeholders are set.
1551        self.trigger('OptinMonsterPlaceholderDone');
1552    },
1553
1554    // Helper to see if we are using IE8 or 9.
1555    this.isIE = function(){
1556        return typeof om_ie_browser != 'undefined';
1557    },
1558
1559    // Helper for some custom social services.
1560    this.socialServices = function(){
1561        // Prepare variables.
1562        var self = this,
1563            $    = self.getProp('$');
1564
1565        // Facebook helper.
1566        if ( typeof(FB) != 'undefined' && FB != null ) {
1567            FB.XFBML.parse();
1568        }
1569
1570        // Twitter helper.
1571        if ( typeof(twttr) != 'undefined' && twttr != null ) {
1572            twttr.widgets.load();
1573        }
1574
1575        // Trigger an event for social services.
1576        self.trigger('OptinMonsterSocial');
1577    }
1578}
1579
1580// Handle loading manual trigger optins.
1581jQuery(document).ready(function($){
1582    var OptinMonsterLinkSlugs = {};
1583    $(document).find('.manual-optin-trigger, .om-monster-link').each(function(i, el){
1584        var $this  = $(this),
1585            slug   = $this.data('optin-slug');
1586
1587        // If the slug is not found, return early.
1588        if ( ! slug ) {
1589            return;
1590        }
1591
1592		// Prepare the JS checker.
1593        var slugjs = slug.replace('-', '_'),
1594            optin  = $('#om-' + slug);
1595
1596        // If the slug already exists in the global variable, return early.
1597        if ( OptinMonsterLinkSlugs.hasOwnProperty(slugjs) ) {
1598            return;
1599        }
1600
1601        // If the optin already exists on the page and it is defined in the global scope, set our holder to it, otherwise remove the optin because it won't be used (a cookie has been set).
1602        if ( 0 !== optin.length ) {
1603            if ( typeof OptinMonsterOptins != 'undefined' && OptinMonsterOptins.hasOwnProperty(slugjs) ) {
1604                OptinMonsterLinkSlugs[slugjs] = window[slugjs];
1605                return;
1606            } else {
1607                // Remove the optin to pave the way for the proper one to be loaded.
1608                $(optin).remove();
1609            }
1610        }
1611
1612        // Load the optin on the page.
1613        var monsterlink = new OptinMonster();
1614        monsterlink.init({
1615            optin:    slug,
1616            optin_js: slugjs,
1617            click:    true
1618        });
1619        OptinMonsterLinkSlugs[slugjs] = monsterlink;
1620    });
1621
1622    // Register the click handler to open the optin.
1623    $(document).on('click', '.manual-optin-trigger, .om-monster-link', function(e){
1624        e.preventDefault();
1625
1626        // Prepare variables.
1627        var $this  = $(this),
1628            slug   = $this.data('optin-slug');
1629
1630        // If the slug is not found, return early.
1631        if ( ! slug ) {
1632            return;
1633        }
1634
1635		// Prepare the JS checker.
1636        var slugjs = slug.replace('-', '_'),
1637            optin  = $('#om-' + slug);
1638
1639        // If the slug does not exist in the global variable, return early.
1640        if ( ! OptinMonsterLinkSlugs.hasOwnProperty(slugjs) ) {
1641            return;
1642        }
1643
1644        // Open the optin.
1645        OptinMonsterLinkSlugs[slugjs].open(true);
1646    });
1647});

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.