PluginProbe
Boxzilla – WordPress Popup Builder / 3.2.13
Boxzilla – WordPress Popup Builder v3.2.13
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.13, at assets/js/script.js

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