PluginProbe
Boxzilla – WordPress Popup Builder / 3.2.18
Boxzilla – WordPress Popup Builder v3.2.18
3.4.11 3.4.10 3.4.9 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 trunk 3.0 3.0.1 3.0.2 3.0.3 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 All 72 releases
boxzilla / assets / js / script.js

script.js in Boxzilla – WordPress Popup Builder 3.2.18, at assets/js/script.js

1,637 lines 48.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () { var require = undefined; var module = undefined; var exports = undefined; var define = undefined; (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2 "use strict";
3
4 function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
5
6 (function () {
7 'use strict';
8
9 var Boxzilla = require('boxzilla');
10
11 var options = window.boxzilla_options; // expose Boxzilla object to window
12
13 window.Boxzilla = Boxzilla; // helper function for setting CSS styles
14
15 function css(element, styles) {
16 if (styles.background_color) {
17 element.style.background = styles.background_color;
18 }
19
20 if (styles.color) {
21 element.style.color = styles.color;
22 }
23
24 if (styles.border_color) {
25 element.style.borderColor = styles.border_color;
26 }
27
28 if (styles.border_width) {
29 element.style.borderWidth = parseInt(styles.border_width) + "px";
30 }
31
32 if (styles.border_style) {
33 element.style.borderStyle = styles.border_style;
34 }
35
36 if (styles.width) {
37 element.style.maxWidth = parseInt(styles.width) + "px";
38 }
39 }
40
41 function createBoxesFromConfig() {
42 // failsafe against including script twice.
43 if (options.inited) {
44 return;
45 } // create boxes from options
46
47
48 for (var key in options.boxes) {
49 // get opts
50 var boxOpts = options.boxes[key];
51 boxOpts.testMode = isLoggedIn && options.testMode; // find box content element, bail if not found
52
53 var boxContentElement = document.getElementById('boxzilla-box-' + boxOpts.id + '-content');
54
55 if (!boxContentElement) {
56 continue;
57 } // use element as content option
58
59
60 boxOpts.content = boxContentElement; // create box
61
62 var box = Boxzilla.create(boxOpts.id, boxOpts); // add box slug to box element as classname
63
64 box.element.className = box.element.className + ' boxzilla-' + boxOpts.post.slug; // add custom css to box
65
66 css(box.element, boxOpts.css);
67
68 try {
69 box.element.firstChild.firstChild.className += " first-child";
70 box.element.firstChild.lastChild.className += " last-child";
71 } catch (e) {} // maybe show box right away
72
73
74 if (box.fits() && locationHashRefersBox(box)) {
75 box.show();
76 }
77 } // set flag to prevent initialising twice
78
79
80 options.inited = true; // trigger "done" event.
81
82 Boxzilla.trigger('done'); // maybe open box with MC4WP form in it
83
84 maybeOpenMailChimpForWordPressBox();
85 }
86
87 function locationHashRefersBox(box) {
88 if (!window.location.hash || 0 === window.location.hash.length) {
89 return false;
90 } // parse "boxzilla-{id}" from location hash
91
92
93 var match = window.location.hash.match(/[#&](boxzilla-\d+)/);
94
95 if (!match || _typeof(match) !== "object" || match.length < 2) {
96 return false;
97 }
98
99 var elementId = match[1];
100
101 if (elementId === box.element.id) {
102 return true;
103 } else if (box.element.querySelector('#' + elementId)) {
104 return true;
105 }
106
107 return false;
108 }
109
110 function maybeOpenMailChimpForWordPressBox() {
111 if (_typeof(window.mc4wp_forms_config) !== "object" || !window.mc4wp_forms_config.submitted_form) {
112 return;
113 }
114
115 var selector = '#' + window.mc4wp_forms_config.submitted_form.element_id;
116 var boxes = Boxzilla.boxes;
117
118 for (var boxId in boxes) {
119 if (!boxes.hasOwnProperty(boxId)) {
120 continue;
121 }
122
123 var box = boxes[boxId];
124
125 if (box.element.querySelector(selector)) {
126 box.show();
127 return;
128 }
129 }
130 } // print message when test mode is enabled
131
132
133 var isLoggedIn = document.body.className.indexOf('logged-in') > -1;
134
135 if (isLoggedIn && options.testMode) {
136 console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\'re done testing.');
137 } // init boxzilla
138
139
140 Boxzilla.init(); // on window.load, create DOM elements for boxes
141
142 window.addEventListener('load', createBoxesFromConfig);
143 })();
144
145 },{"boxzilla":4}],2:[function(require,module,exports){
146 'use strict';
147
148 var duration = 320;
149
150 function css(element, styles) {
151 for (var property in styles) {
152 if (!styles.hasOwnProperty(property)) {
153 continue;
154 }
155
156 element.style[property] = styles[property];
157 }
158 }
159
160 function initObjectProperties(properties, value) {
161 var newObject = {};
162
163 for (var i = 0; i < properties.length; i++) {
164 newObject[properties[i]] = value;
165 }
166
167 return newObject;
168 }
169
170 function copyObjectProperties(properties, object) {
171 var newObject = {};
172
173 for (var i = 0; i < properties.length; i++) {
174 newObject[properties[i]] = object[properties[i]];
175 }
176
177 return newObject;
178 }
179 /**
180 * Checks if the given element is currently being animated.
181 *
182 * @param element
183 * @returns {boolean}
184 */
185
186
187 function animated(element) {
188 return !!element.getAttribute('data-animated');
189 }
190 /**
191 * Toggles the element using the given animation.
192 *
193 * @param element
194 * @param animation Either "fade" or "slide"
195 * @param callbackFn
196 */
197
198
199 function toggle(element, animation, callbackFn) {
200 var nowVisible = element.style.display !== 'none' || element.offsetLeft > 0; // create clone for reference
201
202 var clone = element.cloneNode(true);
203
204 var cleanup = function cleanup() {
205 element.removeAttribute('data-animated');
206 element.setAttribute('style', clone.getAttribute('style'));
207 element.style.display = nowVisible ? 'none' : '';
208
209 if (callbackFn) {
210 callbackFn();
211 }
212 }; // store attribute so everyone knows we're animating this element
213
214
215 element.setAttribute('data-animated', "true"); // toggle element visiblity right away if we're making something visible
216
217 if (!nowVisible) {
218 element.style.display = '';
219 }
220
221 var hiddenStyles;
222 var visibleStyles; // animate properties
223
224 if (animation === 'slide') {
225 hiddenStyles = initObjectProperties(["height", "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"], 0);
226 visibleStyles = {};
227
228 if (!nowVisible) {
229 var computedStyles = window.getComputedStyle(element);
230 visibleStyles = copyObjectProperties(["height", "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"], computedStyles); // in some browsers, getComputedStyle returns "auto" value. this falls back to getBoundingClientRect() in those browsers since we need an actual height.
231
232 if (!isFinite(visibleStyles.height)) {
233 var clientRect = element.getBoundingClientRect();
234 visibleStyles.height = clientRect.height;
235 }
236
237 css(element, hiddenStyles);
238 } // don't show a scrollbar during animation
239
240
241 element.style.overflowY = 'hidden';
242 animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);
243 } else {
244 hiddenStyles = {
245 opacity: 0
246 };
247 visibleStyles = {
248 opacity: 1
249 };
250
251 if (!nowVisible) {
252 css(element, hiddenStyles);
253 }
254
255 animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);
256 }
257 }
258
259 function animate(element, targetStyles, fn) {
260 var last = +new Date();
261 var initialStyles = window.getComputedStyle(element);
262 var currentStyles = {};
263 var propSteps = {};
264
265 for (var property in targetStyles) {
266 if (!targetStyles.hasOwnProperty(property)) {
267 continue;
268 } // make sure we have an object filled with floats
269
270
271 targetStyles[property] = parseFloat(targetStyles[property]); // calculate step size & current value
272
273 var to = targetStyles[property];
274 var current = parseFloat(initialStyles[property]); // is there something to do?
275
276 if (current == to) {
277 delete targetStyles[property];
278 continue;
279 }
280
281 propSteps[property] = (to - current) / duration; // points per second
282
283 currentStyles[property] = current;
284 }
285
286 var tick = function tick() {
287 var now = +new Date();
288 var timeSinceLastTick = now - last;
289 var done = true;
290 var step, to, increment, newValue;
291
292 for (var _property in targetStyles) {
293 if (!targetStyles.hasOwnProperty(_property)) {
294 continue;
295 }
296
297 step = propSteps[_property];
298 to = targetStyles[_property];
299 increment = step * timeSinceLastTick;
300 newValue = currentStyles[_property] + increment;
301
302 if (step > 0 && newValue >= to || step < 0 && newValue <= to) {
303 newValue = to;
304 } else {
305 done = false;
306 } // store new value
307
308
309 currentStyles[_property] = newValue;
310 var suffix = _property !== "opacity" ? "px" : "";
311 element.style[_property] = newValue + suffix;
312 }
313
314 last = +new Date(); // keep going until we're done for all props
315
316 if (!done) {
317 window.requestAnimationFrame && requestAnimationFrame(tick) || setTimeout(tick, 32);
318 } else {
319 // call callback
320 fn && fn();
321 }
322 };
323
324 tick();
325 }
326
327 module.exports = {
328 'toggle': toggle,
329 'animate': animate,
330 'animated': animated
331 };
332
333 },{}],3:[function(require,module,exports){
334 'use strict';
335
336 var defaults = {
337 'animation': 'fade',
338 'rehide': false,
339 'content': '',
340 'cookie': null,
341 'icon': '&times',
342 'screenWidthCondition': null,
343 'position': 'center',
344 'testMode': false,
345 'trigger': false,
346 'closable': true
347 };
348
349 var events = require('./events.js');
350
351 var Animator = require('./animator.js');
352 /**
353 * Merge 2 objects, values of the latter overwriting the former.
354 *
355 * @param obj1
356 * @param obj2
357 * @returns {*}
358 */
359
360
361 function merge(obj1, obj2) {
362 var obj3 = {}; // add obj1 to obj3
363
364 for (var attrname in obj1) {
365 if (obj1.hasOwnProperty(attrname)) {
366 obj3[attrname] = obj1[attrname];
367 }
368 } // add obj2 to obj3
369
370
371 for (var _attrname in obj2) {
372 if (obj2.hasOwnProperty(_attrname)) {
373 obj3[_attrname] = obj2[_attrname];
374 }
375 }
376
377 return obj3;
378 }
379 /**
380 * Get the real height of entire document.
381 * @returns {number}
382 */
383
384
385 function getDocumentHeight() {
386 var body = document.body;
387 var html = document.documentElement;
388 return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
389 } // Box Object
390
391
392 function Box(id, config) {
393 this.id = id; // store config values
394
395 this.config = merge(defaults, config); // store ref to overlay
396
397 this.overlay = document.getElementById('boxzilla-overlay'); // state
398
399 this.visible = false;
400 this.dismissed = false;
401 this.triggered = false;
402 this.triggerHeight = this.calculateTriggerHeight();
403 this.cookieSet = this.isCookieSet();
404 this.element = null;
405 this.contentElement = null;
406 this.closeIcon = null; // create dom elements for this box
407
408 this.dom(); // further initialise the box
409
410 this.events();
411 }
412
413 ; // initialise the box
414
415 Box.prototype.events = function () {
416 var box = this; // attach event to "close" icon inside box
417
418 if (this.closeIcon) {
419 this.closeIcon.addEventListener('click', function (evt) {
420 evt.preventDefault();
421 box.dismiss();
422 });
423 }
424
425 this.element.addEventListener('click', function (evt) {
426 if (evt.target.tagName === 'A') {
427 events.trigger('box.interactions.link', [box, evt.target]);
428 }
429 }, false);
430 this.element.addEventListener('submit', function (evt) {
431 box.setCookie();
432 events.trigger('box.interactions.form', [box, evt.target]);
433 }, false);
434 }; // generate dom elements for this box
435
436
437 Box.prototype.dom = function () {
438 var wrapper = document.createElement('div');
439 wrapper.className = 'boxzilla-container boxzilla-' + this.config.position + '-container';
440 var box = document.createElement('div');
441 box.setAttribute('id', 'boxzilla-' + this.id);
442 box.className = 'boxzilla boxzilla-' + this.id + ' boxzilla-' + this.config.position;
443 box.style.display = 'none';
444 wrapper.appendChild(box);
445 var content;
446
447 if (typeof this.config.content === "string") {
448 content = document.createElement('div');
449 content.innerHTML = this.config.content;
450 } else {
451 content = this.config.content; // make sure element is visible
452
453 content.style.display = '';
454 }
455
456 content.className = 'boxzilla-content';
457 box.appendChild(content);
458
459 if (this.config.closable && this.config.icon) {
460 var closeIcon = document.createElement('span');
461 closeIcon.className = "boxzilla-close-icon";
462 closeIcon.innerHTML = this.config.icon;
463 box.appendChild(closeIcon);
464 this.closeIcon = closeIcon;
465 }
466
467 document.body.appendChild(wrapper);
468 this.contentElement = content;
469 this.element = box;
470 }; // set (calculate) custom box styling depending on box options
471
472
473 Box.prototype.setCustomBoxStyling = function () {
474 // reset element to its initial state
475 var origDisplay = this.element.style.display;
476 this.element.style.display = '';
477 this.element.style.overflowY = 'auto';
478 this.element.style.maxHeight = 'none'; // get new dimensions
479
480 var windowHeight = window.innerHeight;
481 var boxHeight = this.element.clientHeight; // add scrollbar to box and limit height
482
483 if (boxHeight > windowHeight) {
484 this.element.style.maxHeight = windowHeight + "px";
485 this.element.style.overflowY = 'scroll';
486 } // set new top margin for boxes which are centered
487
488
489 if (this.config.position === 'center') {
490 var newTopMargin = (windowHeight - boxHeight) / 2;
491 newTopMargin = newTopMargin >= 0 ? newTopMargin : 0;
492 this.element.style.marginTop = newTopMargin + "px";
493 }
494
495 this.element.style.display = origDisplay;
496 }; // toggle visibility of the box
497
498
499 Box.prototype.toggle = function (show, animate) {
500 show = typeof show === "undefined" ? !this.visible : show;
501 animate = typeof animate === "undefined" ? true : animate; // is box already at desired visibility?
502
503 if (show === this.visible) {
504 return false;
505 } // is box being animated?
506
507
508 if (Animator.animated(this.element)) {
509 return false;
510 } // if box should be hidden but is not closable, bail.
511
512
513 if (!show && !this.config.closable) {
514 return false;
515 } // set new visibility status
516
517
518 this.visible = show; // calculate new styling rules
519
520 this.setCustomBoxStyling(); // trigger event
521
522 events.trigger('box.' + (show ? 'show' : 'hide'), [this]); // show or hide box using selected animation
523
524 if (this.config.position === 'center') {
525 this.overlay.classList.toggle('boxzilla-' + this.id + '-overlay');
526
527 if (animate) {
528 Animator.toggle(this.overlay, "fade");
529 } else {
530 this.overlay.style.display = show ? '' : 'none';
531 }
532 }
533
534 if (animate) {
535 Animator.toggle(this.element, this.config.animation, function () {
536 if (this.visible) {
537 return;
538 }
539
540 this.contentElement.innerHTML = this.contentElement.innerHTML;
541 }.bind(this));
542 } else {
543 this.element.style.display = show ? '' : 'none';
544 }
545
546 return true;
547 }; // show the box
548
549
550 Box.prototype.show = function (animate) {
551 return this.toggle(true, animate);
552 }; // hide the box
553
554
555 Box.prototype.hide = function (animate) {
556 return this.toggle(false, animate);
557 }; // calculate trigger height
558
559
560 Box.prototype.calculateTriggerHeight = function () {
561 var triggerHeight = 0;
562
563 if (this.config.trigger) {
564 if (this.config.trigger.method === 'element') {
565 var triggerElement = document.body.querySelector(this.config.trigger.value);
566
567 if (triggerElement) {
568 var offset = triggerElement.getBoundingClientRect();
569 triggerHeight = offset.top;
570 }
571 } else if (this.config.trigger.method === 'percentage') {
572 triggerHeight = this.config.trigger.value / 100 * getDocumentHeight();
573 }
574 }
575
576 return triggerHeight;
577 };
578
579 Box.prototype.fits = function () {
580 if (!this.config.screenWidthCondition || !this.config.screenWidthCondition.value) {
581 return true;
582 }
583
584 switch (this.config.screenWidthCondition.condition) {
585 case "larger":
586 return window.innerWidth > this.config.screenWidthCondition.value;
587
588 case "smaller":
589 return window.innerWidth < this.config.screenWidthCondition.value;
590 } // meh.. condition should be "smaller" or "larger", just return true.
591
592
593 return true;
594 };
595
596 Box.prototype.onResize = function () {
597 this.triggerHeight = this.calculateTriggerHeight();
598 this.setCustomBoxStyling();
599 }; // is this box enabled?
600
601
602 Box.prototype.mayAutoShow = function () {
603 if (this.dismissed) {
604 return false;
605 } // check if box fits on given minimum screen width
606
607
608 if (!this.fits()) {
609 return false;
610 } // if trigger empty or error in calculating triggerHeight, return false
611
612
613 if (!this.config.trigger) {
614 return false;
615 } // rely on cookie value (show if not set, don't show if set)
616
617
618 return !this.cookieSet;
619 };
620
621 Box.prototype.mayRehide = function () {
622 return this.config.rehide && this.triggered;
623 };
624
625 Box.prototype.isCookieSet = function () {
626 // always show on test mode or when no auto-trigger is configured
627 if (this.config.testMode || !this.config.trigger) {
628 return false;
629 } // if either cookie is null or trigger & dismiss are both falsey, don't bother checking.
630
631
632 if (!this.config.cookie || !this.config.cookie.triggered && !this.config.cookie.dismissed) {
633 return false;
634 }
635
636 var cookieSet = document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + 'boxzilla_box_' + this.id + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1") === "true";
637 return cookieSet;
638 }; // set cookie that disables automatically showing the box
639
640
641 Box.prototype.setCookie = function (hours) {
642 var expiryDate = new Date();
643 expiryDate.setHours(expiryDate.getHours() + hours);
644 document.cookie = 'boxzilla_box_' + this.id + '=true; expires=' + expiryDate.toUTCString() + '; path=/';
645 };
646
647 Box.prototype.trigger = function () {
648 var shown = this.show();
649
650 if (!shown) {
651 return;
652 }
653
654 this.triggered = true;
655
656 if (this.config.cookie && this.config.cookie.triggered) {
657 this.setCookie(this.config.cookie.triggered);
658 }
659 };
660 /**
661 * Dismisses the box and optionally sets a cookie.
662 * @param animate
663 * @returns {boolean}
664 */
665
666
667 Box.prototype.dismiss = function (animate) {
668 // only dismiss box if it's currently open.
669 if (!this.visible) {
670 return false;
671 } // hide box element
672
673
674 this.hide(animate); // set cookie
675
676 if (this.config.cookie && this.config.cookie.dismissed) {
677 this.setCookie(this.config.cookie.dismissed);
678 }
679
680 this.dismissed = true;
681 events.trigger('box.dismiss', [this]);
682 return true;
683 };
684
685 module.exports = Box;
686
687 },{"./animator.js":2,"./events.js":5}],4:[function(require,module,exports){
688 'use strict';
689
690 var Timer = require('./timer.js');
691
692 var Boxzilla = require('./events.js');
693
694 var Box = require('./box.js');
695
696 var boxes = [];
697 var overlay;
698 var scrollElement = window;
699 var siteTimer;
700 var pageTimer;
701 var pageViews;
702 var initialised = false;
703
704 var styles = require('./styles.js');
705
706 var ExitIntent = require('./triggers/exit-intent.js');
707
708 function throttle(fn, threshhold, scope) {
709 threshhold || (threshhold = 250);
710 var last, deferTimer;
711 return function () {
712 var context = scope || this;
713 var now = +new Date(),
714 args = arguments;
715
716 if (last && now < last + threshhold) {
717 // hold on to it
718 clearTimeout(deferTimer);
719 deferTimer = setTimeout(function () {
720 last = now;
721 fn.apply(context, args);
722 }, threshhold);
723 } else {
724 last = now;
725 fn.apply(context, args);
726 }
727 };
728 } // "keyup" listener
729
730
731 function onKeyUp(e) {
732 if (e.keyCode === 27) {
733 Boxzilla.dismiss();
734 }
735 } // check "pageviews" criteria for each box
736
737
738 function checkPageViewsCriteria() {
739 // don't bother if another box is currently open
740 if (isAnyBoxVisible()) {
741 return;
742 }
743
744 boxes.forEach(function (box) {
745 if (!box.mayAutoShow()) {
746 return;
747 }
748
749 if (box.config.trigger.method === 'pageviews' && pageViews >= box.config.trigger.value) {
750 box.trigger();
751 }
752 });
753 } // check time trigger criteria for each box
754
755
756 function checkTimeCriteria() {
757 // don't bother if another box is currently open
758 if (isAnyBoxVisible()) {
759 return;
760 }
761
762 boxes.forEach(function (box) {
763 if (!box.mayAutoShow()) {
764 return;
765 } // check "time on site" trigger
766
767
768 if (box.config.trigger.method === 'time_on_site' && siteTimer.time >= box.config.trigger.value) {
769 box.trigger();
770 } // check "time on page" trigger
771
772
773 if (box.config.trigger.method === 'time_on_page' && pageTimer.time >= box.config.trigger.value) {
774 box.trigger();
775 }
776 });
777 } // check triggerHeight criteria for all boxes
778
779
780 function checkHeightCriteria() {
781 var scrollY = scrollElement.hasOwnProperty('pageYOffset') ? scrollElement.pageYOffset : scrollElement.scrollTop;
782 scrollY = scrollY + window.innerHeight * 0.9;
783 boxes.forEach(function (box) {
784 if (!box.mayAutoShow() || box.triggerHeight <= 0) {
785 return;
786 }
787
788 if (scrollY > box.triggerHeight) {
789 // don't bother if another box is currently open
790 if (isAnyBoxVisible()) {
791 return;
792 } // trigger box
793
794
795 box.trigger();
796 } // if box may auto-hide and scrollY is less than triggerHeight (with small margin of error), hide box
797
798
799 if (box.mayRehide() && scrollY < box.triggerHeight - 5) {
800 box.hide();
801 }
802 });
803 } // recalculate heights and variables based on height
804
805
806 function recalculateHeights() {
807 boxes.forEach(function (box) {
808 box.onResize();
809 });
810 }
811
812 function onOverlayClick(e) {
813 var x = e.offsetX;
814 var y = e.offsetY; // calculate if click was less than 40px outside box to avoid closing it by accident
815
816 boxes.forEach(function (box) {
817 var rect = box.element.getBoundingClientRect();
818 var margin = 40; // if click was not anywhere near box, dismiss it.
819
820 if (x < rect.left - margin || x > rect.right + margin || y < rect.top - margin || y > rect.bottom + margin) {
821 box.dismiss();
822 }
823 });
824 }
825
826 function showBoxesWithExitIntentTrigger() {
827 // do nothing if already triggered OR another box is visible.
828 if (isAnyBoxVisible()) {
829 return;
830 }
831
832 boxes.forEach(function (box) {
833 if (box.mayAutoShow() && box.config.trigger.method === 'exit_intent') {
834 box.trigger();
835 }
836 });
837 }
838
839 function isAnyBoxVisible() {
840 return boxes.filter(function (b) {
841 return b.visible;
842 }).length > 0;
843 }
844
845 function onElementClick(e) {
846 // find <a> element in up to 3 parent elements
847 var el = e.target || e.srcElement;
848 var depth = 3;
849
850 for (var i = 0; i <= depth; i++) {
851 if (!el || el.tagName === 'A') {
852 break;
853 }
854
855 el = el.parentElement;
856 }
857
858 if (!el || el.tagName !== 'A' || !el.getAttribute('href')) {
859 return;
860 }
861
862 var href = el.getAttribute('href').toLowerCase();
863 var match = href.match(/[#&]boxzilla-(\d+)/);
864
865 if (match && match.length > 1) {
866 var boxId = match[1];
867 Boxzilla.toggle(boxId);
868 }
869 }
870
871 var timers = {
872 start: function start() {
873 try {
874 var sessionTime = sessionStorage.getItem('boxzilla_timer');
875 if (sessionTime) siteTimer.time = sessionTime;
876 } catch (e) {}
877
878 siteTimer.start();
879 pageTimer.start();
880 },
881 stop: function stop() {
882 sessionStorage.setItem('boxzilla_timer', siteTimer.time);
883 siteTimer.stop();
884 pageTimer.stop();
885 }
886 }; // initialise & add event listeners
887
888 Boxzilla.init = function () {
889 if (initialised) {
890 return;
891 }
892
893 document.body.addEventListener('click', onElementClick, true);
894
895 try {
896 pageViews = sessionStorage.getItem('boxzilla_pageviews') || 0;
897 } catch (e) {
898 pageViews = 0;
899 }
900
901 siteTimer = new Timer(0);
902 pageTimer = new Timer(0); // insert styles into DOM
903
904 var styleElement = document.createElement('style');
905 styleElement.setAttribute("type", "text/css");
906 styleElement.innerHTML = styles;
907 document.head.appendChild(styleElement); // add overlay element to dom
908
909 overlay = document.createElement('div');
910 overlay.style.display = 'none';
911 overlay.id = 'boxzilla-overlay';
912 document.body.appendChild(overlay); // init exit intent trigger
913
914 new ExitIntent(showBoxesWithExitIntentTrigger); // start timers
915
916 timers.start();
917 scrollElement.addEventListener('touchstart', throttle(checkHeightCriteria), true);
918 scrollElement.addEventListener('scroll', throttle(checkHeightCriteria), true);
919 window.addEventListener('resize', throttle(recalculateHeights));
920 window.addEventListener('load', recalculateHeights);
921 overlay.addEventListener('click', onOverlayClick);
922 window.setInterval(checkTimeCriteria, 1000);
923 window.setTimeout(checkPageViewsCriteria, 1000);
924 document.addEventListener('keyup', onKeyUp); // stop timers when leaving page or switching to other tab
925
926 document.addEventListener("visibilitychange", function () {
927 document.hidden ? timers.stop() : timers.start();
928 });
929 window.addEventListener('beforeunload', function () {
930 timers.stop();
931 sessionStorage.setItem('boxzilla_pageviews', ++pageViews);
932 });
933 Boxzilla.trigger('ready');
934 initialised = true; // ensure this function doesn't run again
935 };
936 /**
937 * Create a new Box
938 *
939 * @param string id
940 * @param object opts
941 *
942 * @returns Box
943 */
944
945
946 Boxzilla.create = function (id, opts) {
947 // preserve backwards compat for minimumScreenWidth option
948 if (typeof opts.minimumScreenWidth !== "undefined") {
949 opts.screenWidthCondition = {
950 condition: "larger",
951 value: opts.minimumScreenWidth
952 };
953 }
954
955 var box = new Box(id, opts);
956 boxes.push(box);
957 return box;
958 };
959
960 Boxzilla.get = function (id) {
961 for (var i = 0; i < boxes.length; i++) {
962 var box = boxes[i];
963
964 if (box.id == id) {
965 return box;
966 }
967 }
968
969 throw new Error("No box exists with ID " + id);
970 }; // dismiss a single box (or all by omitting id param)
971
972
973 Boxzilla.dismiss = function (id, animate) {
974 // if no id given, dismiss all current open boxes
975 if (id) {
976 Boxzilla.get(id).dismiss(animate);
977 } else {
978 boxes.forEach(function (box) {
979 box.dismiss(animate);
980 });
981 }
982 };
983
984 Boxzilla.hide = function (id, animate) {
985 if (id) {
986 Boxzilla.get(id).hide(animate);
987 } else {
988 boxes.forEach(function (box) {
989 box.hide(animate);
990 });
991 }
992 };
993
994 Boxzilla.show = function (id, animate) {
995 if (id) {
996 Boxzilla.get(id).show(animate);
997 } else {
998 boxes.forEach(function (box) {
999 box.show(animate);
1000 });
1001 }
1002 };
1003
1004 Boxzilla.toggle = function (id, animate) {
1005 if (id) {
1006 Boxzilla.get(id).toggle(animate);
1007 } else {
1008 boxes.forEach(function (box) {
1009 box.toggle(animate);
1010 });
1011 }
1012 }; // expose each individual box.
1013
1014
1015 Boxzilla.boxes = boxes; // expose boxzilla object
1016
1017 window.Boxzilla = Boxzilla;
1018
1019 if (typeof module !== 'undefined' && module.exports) {
1020 module.exports = Boxzilla;
1021 }
1022
1023 },{"./box.js":3,"./events.js":5,"./styles.js":6,"./timer.js":7,"./triggers/exit-intent.js":8}],5:[function(require,module,exports){
1024 'use strict';
1025
1026 var EventEmitter = require('wolfy87-eventemitter');
1027
1028 module.exports = Object.create(EventEmitter.prototype);
1029
1030 },{"wolfy87-eventemitter":9}],6:[function(require,module,exports){
1031 "use strict";
1032
1033 var styles = "#boxzilla-overlay{position:fixed;background:rgba(0,0,0,.65);width:100%;height:100%;left:0;top:0;z-index:10000}.boxzilla-center-container{position:fixed;top:0;left:0;right:0;height:0;text-align:center;z-index:11000;line-height:0}.boxzilla-center-container .boxzilla{display:inline-block;text-align:left;position:relative;line-height:normal}.boxzilla{position:fixed;z-index:12000;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background:#fff;padding:25px}.boxzilla.boxzilla-top-left{top:0;left:0}.boxzilla.boxzilla-top-right{top:0;right:0}.boxzilla.boxzilla-bottom-left{bottom:0;left:0}.boxzilla.boxzilla-bottom-right{bottom:0;right:0}.boxzilla-content>:first-child{margin-top:0;padding-top:0}.boxzilla-content>:last-child{margin-bottom:0;padding-bottom:0}.boxzilla-close-icon{position:absolute;right:0;top:0;text-align:center;padding:6px;cursor:pointer;-webkit-appearance:none;font-size:28px;font-weight:700;line-height:20px;color:#000;opacity:.5}.boxzilla-close-icon:focus,.boxzilla-close-icon:hover{opacity:.8}";
1034 module.exports = styles;
1035
1036 },{}],7:[function(require,module,exports){
1037 'use strict';
1038
1039 var Timer = function Timer(start) {
1040 this.time = start;
1041 this.interval = 0;
1042 };
1043
1044 Timer.prototype.tick = function () {
1045 this.time++;
1046 };
1047
1048 Timer.prototype.start = function () {
1049 if (!this.interval) {
1050 this.interval = window.setInterval(this.tick.bind(this), 1000);
1051 }
1052 };
1053
1054 Timer.prototype.stop = function () {
1055 if (this.interval) {
1056 window.clearInterval(this.interval);
1057 this.interval = 0;
1058 }
1059 };
1060
1061 module.exports = Timer;
1062
1063 },{}],8:[function(require,module,exports){
1064 'use strict';
1065
1066 module.exports = function (callback) {
1067 var timeout = null;
1068 var touchStart = {};
1069
1070 function triggerCallback() {
1071 document.documentElement.removeEventListener('mouseleave', onMouseLeave);
1072 document.documentElement.removeEventListener('mouseenter', onMouseEnter);
1073 document.documentElement.removeEventListener('click', clearTimeout);
1074 window.removeEventListener('touchstart', onTouchStart);
1075 window.removeEventListener('touchend', onTouchEnd);
1076 callback();
1077 }
1078
1079 function clearTimeout() {
1080 if (timeout === null) {
1081 return;
1082 }
1083
1084 window.clearTimeout(timeout);
1085 timeout = null;
1086 }
1087
1088 function onMouseEnter(evt) {
1089 clearTimeout();
1090 }
1091
1092 function getAddressBarY() {
1093 if (document.documentMode || /Edge\//.test(navigator.userAgent)) {
1094 return 5;
1095 }
1096
1097 return 0;
1098 }
1099
1100 function onMouseLeave(evt) {
1101 clearTimeout(); // did mouse leave at top of window?
1102 // add small exception space in the top-right corner
1103
1104 if (evt.clientY <= getAddressBarY() && evt.clientX < 0.80 * window.innerWidth) {
1105 timeout = window.setTimeout(triggerCallback, 400);
1106 }
1107 }
1108
1109 function onTouchStart(evt) {
1110 clearTimeout();
1111 touchStart = {
1112 timestamp: performance.now(),
1113 scrollY: window.scrollY,
1114 windowHeight: window.innerHeight
1115 };
1116 }
1117
1118 function onTouchEnd(evt) {
1119 clearTimeout(); // did address bar appear?
1120
1121 if (window.innerHeight > touchStart.windowHeight) {
1122 return;
1123 } // allow a tiny tiny margin for error, to not fire on clicks
1124
1125
1126 if (window.scrollY + 20 >= touchStart.scrollY) {
1127 return;
1128 }
1129
1130 if (performance.now() - touchStart.timestamp > 300) {
1131 return;
1132 }
1133
1134 if (['A', 'INPUT', 'BUTTON'].indexOf(evt.target.tagName) > -1) {
1135 return;
1136 }
1137
1138 timeout = window.setTimeout(triggerCallback, 800);
1139 }
1140
1141 window.addEventListener('touchstart', onTouchStart);
1142 window.addEventListener('touchend', onTouchEnd);
1143 document.documentElement.addEventListener('mouseenter', onMouseEnter);
1144 document.documentElement.addEventListener('mouseleave', onMouseLeave);
1145 document.documentElement.addEventListener('click', clearTimeout);
1146 };
1147
1148 },{}],9:[function(require,module,exports){
1149 /*!
1150 * EventEmitter v5.2.8 - git.io/ee
1151 * Unlicense - http://unlicense.org/
1152 * Oliver Caldwell - https://oli.me.uk/
1153 * @preserve
1154 */
1155
1156 ;(function (exports) {
1157 'use strict';
1158
1159 /**
1160 * Class for managing events.
1161 * Can be extended to provide event functionality in other classes.
1162 *
1163 * @class EventEmitter Manages event registering and emitting.
1164 */
1165 function EventEmitter() {}
1166
1167 // Shortcuts to improve speed and size
1168 var proto = EventEmitter.prototype;
1169 var originalGlobalValue = exports.EventEmitter;
1170
1171 /**
1172 * Finds the index of the listener for the event in its storage array.
1173 *
1174 * @param {Function[]} listeners Array of listeners to search through.
1175 * @param {Function} listener Method to look for.
1176 * @return {Number} Index of the specified listener, -1 if not found
1177 * @api private
1178 */
1179 function indexOfListener(listeners, listener) {
1180 var i = listeners.length;
1181 while (i--) {
1182 if (listeners[i].listener === listener) {
1183 return i;
1184 }
1185 }
1186
1187 return -1;
1188 }
1189
1190 /**
1191 * Alias a method while keeping the context correct, to allow for overwriting of target method.
1192 *
1193 * @param {String} name The name of the target method.
1194 * @return {Function} The aliased method
1195 * @api private
1196 */
1197 function alias(name) {
1198 return function aliasClosure() {
1199 return this[name].apply(this, arguments);
1200 };
1201 }
1202
1203 /**
1204 * Returns the listener array for the specified event.
1205 * Will initialise the event object and listener arrays if required.
1206 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
1207 * Each property in the object response is an array of listener functions.
1208 *
1209 * @param {String|RegExp} evt Name of the event to return the listeners from.
1210 * @return {Function[]|Object} All listener functions for the event.
1211 */
1212 proto.getListeners = function getListeners(evt) {
1213 var events = this._getEvents();
1214 var response;
1215 var key;
1216
1217 // Return a concatenated array of all matching events if
1218 // the selector is a regular expression.
1219 if (evt instanceof RegExp) {
1220 response = {};
1221 for (key in events) {
1222 if (events.hasOwnProperty(key) && evt.test(key)) {
1223 response[key] = events[key];
1224 }
1225 }
1226 }
1227 else {
1228 response = events[evt] || (events[evt] = []);
1229 }
1230
1231 return response;
1232 };
1233
1234 /**
1235 * Takes a list of listener objects and flattens it into a list of listener functions.
1236 *
1237 * @param {Object[]} listeners Raw listener objects.
1238 * @return {Function[]} Just the listener functions.
1239 */
1240 proto.flattenListeners = function flattenListeners(listeners) {
1241 var flatListeners = [];
1242 var i;
1243
1244 for (i = 0; i < listeners.length; i += 1) {
1245 flatListeners.push(listeners[i].listener);
1246 }
1247
1248 return flatListeners;
1249 };
1250
1251 /**
1252 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
1253 *
1254 * @param {String|RegExp} evt Name of the event to return the listeners from.
1255 * @return {Object} All listener functions for an event in an object.
1256 */
1257 proto.getListenersAsObject = function getListenersAsObject(evt) {
1258 var listeners = this.getListeners(evt);
1259 var response;
1260
1261 if (listeners instanceof Array) {
1262 response = {};
1263 response[evt] = listeners;
1264 }
1265
1266 return response || listeners;
1267 };
1268
1269 function isValidListener (listener) {
1270 if (typeof listener === 'function' || listener instanceof RegExp) {
1271 return true
1272 } else if (listener && typeof listener === 'object') {
1273 return isValidListener(listener.listener)
1274 } else {
1275 return false
1276 }
1277 }
1278
1279 /**
1280 * Adds a listener function to the specified event.
1281 * The listener will not be added if it is a duplicate.
1282 * If the listener returns true then it will be removed after it is called.
1283 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
1284 *
1285 * @param {String|RegExp} evt Name of the event to attach the listener to.
1286 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
1287 * @return {Object} Current instance of EventEmitter for chaining.
1288 */
1289 proto.addListener = function addListener(evt, listener) {
1290 if (!isValidListener(listener)) {
1291 throw new TypeError('listener must be a function');
1292 }
1293
1294 var listeners = this.getListenersAsObject(evt);
1295 var listenerIsWrapped = typeof listener === 'object';
1296 var key;
1297
1298 for (key in listeners) {
1299 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
1300 listeners[key].push(listenerIsWrapped ? listener : {
1301 listener: listener,
1302 once: false
1303 });
1304 }
1305 }
1306
1307 return this;
1308 };
1309
1310 /**
1311 * Alias of addListener
1312 */
1313 proto.on = alias('addListener');
1314
1315 /**
1316 * Semi-alias of addListener. It will add a listener that will be
1317 * automatically removed after its first execution.
1318 *
1319 * @param {String|RegExp} evt Name of the event to attach the listener to.
1320 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
1321 * @return {Object} Current instance of EventEmitter for chaining.
1322 */
1323 proto.addOnceListener = function addOnceListener(evt, listener) {
1324 return this.addListener(evt, {
1325 listener: listener,
1326 once: true
1327 });
1328 };
1329
1330 /**
1331 * Alias of addOnceListener.
1332 */
1333 proto.once = alias('addOnceListener');
1334
1335 /**
1336 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
1337 * You need to tell it what event names should be matched by a regex.
1338 *
1339 * @param {String} evt Name of the event to create.
1340 * @return {Object} Current instance of EventEmitter for chaining.
1341 */
1342 proto.defineEvent = function defineEvent(evt) {
1343 this.getListeners(evt);
1344 return this;
1345 };
1346
1347 /**
1348 * Uses defineEvent to define multiple events.
1349 *
1350 * @param {String[]} evts An array of event names to define.
1351 * @return {Object} Current instance of EventEmitter for chaining.
1352 */
1353 proto.defineEvents = function defineEvents(evts) {
1354 for (var i = 0; i < evts.length; i += 1) {
1355 this.defineEvent(evts[i]);
1356 }
1357 return this;
1358 };
1359
1360 /**
1361 * Removes a listener function from the specified event.
1362 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
1363 *
1364 * @param {String|RegExp} evt Name of the event to remove the listener from.
1365 * @param {Function} listener Method to remove from the event.
1366 * @return {Object} Current instance of EventEmitter for chaining.
1367 */
1368 proto.removeListener = function removeListener(evt, listener) {
1369 var listeners = this.getListenersAsObject(evt);
1370 var index;
1371 var key;
1372
1373 for (key in listeners) {
1374 if (listeners.hasOwnProperty(key)) {
1375 index = indexOfListener(listeners[key], listener);
1376
1377 if (index !== -1) {
1378 listeners[key].splice(index, 1);
1379 }
1380 }
1381 }
1382
1383 return this;
1384 };
1385
1386 /**
1387 * Alias of removeListener
1388 */
1389 proto.off = alias('removeListener');
1390
1391 /**
1392 * Adds listeners in bulk using the manipulateListeners method.
1393 * If you pass an object as the first argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
1394 * You can also pass it a regular expression to add the array of listeners to all events that match it.
1395 * Yeah, this function does quite a bit. That's probably a bad thing.
1396 *
1397 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
1398 * @param {Function[]} [listeners] An optional array of listener functions to add.
1399 * @return {Object} Current instance of EventEmitter for chaining.
1400 */
1401 proto.addListeners = function addListeners(evt, listeners) {
1402 // Pass through to manipulateListeners
1403 return this.manipulateListeners(false, evt, listeners);
1404 };
1405
1406 /**
1407 * Removes listeners in bulk using the manipulateListeners method.
1408 * If you pass an object as the first argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
1409 * You can also pass it an event name and an array of listeners to be removed.
1410 * You can also pass it a regular expression to remove the listeners from all events that match it.
1411 *
1412 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
1413 * @param {Function[]} [listeners] An optional array of listener functions to remove.
1414 * @return {Object} Current instance of EventEmitter for chaining.
1415 */
1416 proto.removeListeners = function removeListeners(evt, listeners) {
1417 // Pass through to manipulateListeners
1418 return this.manipulateListeners(true, evt, listeners);
1419 };
1420
1421 /**
1422 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
1423 * The first argument will determine if the listeners are removed (true) or added (false).
1424 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
1425 * You can also pass it an event name and an array of listeners to be added/removed.
1426 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
1427 *
1428 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
1429 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
1430 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
1431 * @return {Object} Current instance of EventEmitter for chaining.
1432 */
1433 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
1434 var i;
1435 var value;
1436 var single = remove ? this.removeListener : this.addListener;
1437 var multiple = remove ? this.removeListeners : this.addListeners;
1438
1439 // If evt is an object then pass each of its properties to this method
1440 if (typeof evt === 'object' && !(evt instanceof RegExp)) {
1441 for (i in evt) {
1442 if (evt.hasOwnProperty(i) && (value = evt[i])) {
1443 // Pass the single listener straight through to the singular method
1444 if (typeof value === 'function') {
1445 single.call(this, i, value);
1446 }
1447 else {
1448 // Otherwise pass back to the multiple function
1449 multiple.call(this, i, value);
1450 }
1451 }
1452 }
1453 }
1454 else {
1455 // So evt must be a string
1456 // And listeners must be an array of listeners
1457 // Loop over it and pass each one to the multiple method
1458 i = listeners.length;
1459 while (i--) {
1460 single.call(this, evt, listeners[i]);
1461 }
1462 }
1463
1464 return this;
1465 };
1466
1467 /**
1468 * Removes all listeners from a specified event.
1469 * If you do not specify an event then all listeners will be removed.
1470 * That means every event will be emptied.
1471 * You can also pass a regex to remove all events that match it.
1472 *
1473 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
1474 * @return {Object} Current instance of EventEmitter for chaining.
1475 */
1476 proto.removeEvent = function removeEvent(evt) {
1477 var type = typeof evt;
1478 var events = this._getEvents();
1479 var key;
1480
1481 // Remove different things depending on the state of evt
1482 if (type === 'string') {
1483 // Remove all listeners for the specified event
1484 delete events[evt];
1485 }
1486 else if (evt instanceof RegExp) {
1487 // Remove all events matching the regex.
1488 for (key in events) {
1489 if (events.hasOwnProperty(key) && evt.test(key)) {
1490 delete events[key];
1491 }
1492 }
1493 }
1494 else {
1495 // Remove all listeners in all events
1496 delete this._events;
1497 }
1498
1499 return this;
1500 };
1501
1502 /**
1503 * Alias of removeEvent.
1504 *
1505 * Added to mirror the node API.
1506 */
1507 proto.removeAllListeners = alias('removeEvent');
1508
1509 /**
1510 * Emits an event of your choice.
1511 * When emitted, every listener attached to that event will be executed.
1512 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
1513 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
1514 * So they will not arrive within the array on the other side, they will be separate.
1515 * You can also pass a regular expression to emit to all events that match it.
1516 *
1517 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
1518 * @param {Array} [args] Optional array of arguments to be passed to each listener.
1519 * @return {Object} Current instance of EventEmitter for chaining.
1520 */
1521 proto.emitEvent = function emitEvent(evt, args) {
1522 var listenersMap = this.getListenersAsObject(evt);
1523 var listeners;
1524 var listener;
1525 var i;
1526 var key;
1527 var response;
1528
1529 for (key in listenersMap) {
1530 if (listenersMap.hasOwnProperty(key)) {
1531 listeners = listenersMap[key].slice(0);
1532
1533 for (i = 0; i < listeners.length; i++) {
1534 // If the listener returns true then it shall be removed from the event
1535 // The function is executed either with a basic call or an apply if there is an args array
1536 listener = listeners[i];
1537
1538 if (listener.once === true) {
1539 this.removeListener(evt, listener.listener);
1540 }
1541
1542 response = listener.listener.apply(this, args || []);
1543
1544 if (response === this._getOnceReturnValue()) {
1545 this.removeListener(evt, listener.listener);
1546 }
1547 }
1548 }
1549 }
1550
1551 return this;
1552 };
1553
1554 /**
1555 * Alias of emitEvent
1556 */
1557 proto.trigger = alias('emitEvent');
1558
1559 /**
1560 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
1561 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
1562 *
1563 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
1564 * @param {...*} Optional additional arguments to be passed to each listener.
1565 * @return {Object} Current instance of EventEmitter for chaining.
1566 */
1567 proto.emit = function emit(evt) {
1568 var args = Array.prototype.slice.call(arguments, 1);
1569 return this.emitEvent(evt, args);
1570 };
1571
1572 /**
1573 * Sets the current value to check against when executing listeners. If a
1574 * listeners return value matches the one set here then it will be removed
1575 * after execution. This value defaults to true.
1576 *
1577 * @param {*} value The new value to check for when executing listeners.
1578 * @return {Object} Current instance of EventEmitter for chaining.
1579 */
1580 proto.setOnceReturnValue = function setOnceReturnValue(value) {
1581 this._onceReturnValue = value;
1582 return this;
1583 };
1584
1585 /**
1586 * Fetches the current value to check against when executing listeners. If
1587 * the listeners return value matches this one then it should be removed
1588 * automatically. It will return true by default.
1589 *
1590 * @return {*|Boolean} The current value to check for or the default, true.
1591 * @api private
1592 */
1593 proto._getOnceReturnValue = function _getOnceReturnValue() {
1594 if (this.hasOwnProperty('_onceReturnValue')) {
1595 return this._onceReturnValue;
1596 }
1597 else {
1598 return true;
1599 }
1600 };
1601
1602 /**
1603 * Fetches the events object and creates one if required.
1604 *
1605 * @return {Object} The events storage object.
1606 * @api private
1607 */
1608 proto._getEvents = function _getEvents() {
1609 return this._events || (this._events = {});
1610 };
1611
1612 /**
1613 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
1614 *
1615 * @return {Function} Non conflicting EventEmitter class.
1616 */
1617 EventEmitter.noConflict = function noConflict() {
1618 exports.EventEmitter = originalGlobalValue;
1619 return EventEmitter;
1620 };
1621
1622 // Expose the class either via AMD, CommonJS or the global object
1623 if (typeof define === 'function' && define.amd) {
1624 define(function () {
1625 return EventEmitter;
1626 });
1627 }
1628 else if (typeof module === 'object' && module.exports){
1629 module.exports = EventEmitter;
1630 }
1631 else {
1632 exports.EventEmitter = EventEmitter;
1633 }
1634 }(typeof window !== 'undefined' ? window : this || {}));
1635
1636 },{}]},{},[1]);
1637 ; })();