PluginProbe
Boxzilla – WordPress Popup Builder / 3.2.21
Boxzilla – WordPress Popup Builder v3.2.21
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.21, at assets/js/script.js

1,122 lines 29.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 var Boxzilla = require('boxzilla');
8
9 var options = window.boxzilla_options; // helper function for setting CSS styles
10
11 function css(element, styles) {
12 if (styles.background_color) {
13 element.style.background = styles.background_color;
14 }
15
16 if (styles.color) {
17 element.style.color = styles.color;
18 }
19
20 if (styles.border_color) {
21 element.style.borderColor = styles.border_color;
22 }
23
24 if (styles.border_width) {
25 element.style.borderWidth = parseInt(styles.border_width) + 'px';
26 }
27
28 if (styles.border_style) {
29 element.style.borderStyle = styles.border_style;
30 }
31
32 if (styles.width) {
33 element.style.maxWidth = parseInt(styles.width) + 'px';
34 }
35 }
36
37 function createBoxesFromConfig() {
38 // failsafe against including script twice.
39 if (options.inited) {
40 return;
41 } // create boxes from options
42
43
44 for (var key in options.boxes) {
45 // get opts
46 var boxOpts = options.boxes[key];
47 boxOpts.testMode = isLoggedIn && options.testMode; // find box content element, bail if not found
48
49 var boxContentElement = document.getElementById('boxzilla-box-' + boxOpts.id + '-content');
50
51 if (!boxContentElement) {
52 continue;
53 } // use element as content option
54
55
56 boxOpts.content = boxContentElement; // create box
57
58 var box = Boxzilla.create(boxOpts.id, boxOpts); // add box slug to box element as classname
59
60 box.element.className = box.element.className + ' boxzilla-' + boxOpts.post.slug; // add custom css to box
61
62 css(box.element, boxOpts.css);
63
64 try {
65 box.element.firstChild.firstChild.className += ' first-child';
66 box.element.firstChild.lastChild.className += ' last-child';
67 } catch (e) {} // maybe show box right away
68
69
70 if (box.fits() && locationHashRefersBox(box)) {
71 box.show();
72 }
73 } // set flag to prevent initialising twice
74
75
76 options.inited = true; // trigger "done" event.
77
78 Boxzilla.trigger('done'); // maybe open box with MC4WP form in it
79
80 maybeOpenMailChimpForWordPressBox();
81 }
82
83 function locationHashRefersBox(box) {
84 if (!window.location.hash || window.location.hash.length === 0) {
85 return false;
86 } // parse "boxzilla-{id}" from location hash
87
88
89 var match = window.location.hash.match(/[#&](boxzilla-\d+)/);
90
91 if (!match || _typeof(match) !== 'object' || match.length < 2) {
92 return false;
93 }
94
95 var elementId = match[1];
96
97 if (elementId === box.element.id) {
98 return true;
99 } else if (box.element.querySelector('#' + elementId)) {
100 return true;
101 }
102
103 return false;
104 }
105
106 function maybeOpenMailChimpForWordPressBox() {
107 if ((_typeof(window.mc4wp_forms_config) !== 'object' || !window.mc4wp_forms_config.submitted_form) && _typeof(window.mc4wp_submitted_form) !== 'object') {
108 return;
109 }
110
111 var form = window.mc4wp_submitted_form || window.mc4wp_forms_config.submitted_form;
112 var selector = '#' + form.element_id;
113 Boxzilla.boxes.forEach(function (box) {
114 if (box.element.querySelector(selector)) {
115 box.show();
116 }
117 });
118 } // print message when test mode is enabled
119
120
121 var isLoggedIn = document.body.className.indexOf('logged-in') > -1;
122
123 if (isLoggedIn && options.testMode) {
124 console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\'re done testing.');
125 } // init boxzilla
126
127
128 Boxzilla.init(); // on window.load, create DOM elements for boxes
129
130 window.addEventListener('load', createBoxesFromConfig);
131 })();
132
133 },{"boxzilla":4}],2:[function(require,module,exports){
134 "use strict";
135
136 var duration = 320;
137
138 function css(element, styles) {
139 for (var property in styles) {
140 if (!styles.hasOwnProperty(property)) {
141 continue;
142 }
143
144 element.style[property] = styles[property];
145 }
146 }
147
148 function initObjectProperties(properties, value) {
149 var newObject = {};
150
151 for (var i = 0; i < properties.length; i++) {
152 newObject[properties[i]] = value;
153 }
154
155 return newObject;
156 }
157
158 function copyObjectProperties(properties, object) {
159 var newObject = {};
160
161 for (var i = 0; i < properties.length; i++) {
162 newObject[properties[i]] = object[properties[i]];
163 }
164
165 return newObject;
166 }
167 /**
168 * Checks if the given element is currently being animated.
169 *
170 * @param element
171 * @returns {boolean}
172 */
173
174
175 function animated(element) {
176 return !!element.getAttribute('data-animated');
177 }
178 /**
179 * Toggles the element using the given animation.
180 *
181 * @param element
182 * @param animation Either "fade" or "slide"
183 * @param callbackFn
184 */
185
186
187 function toggle(element, animation, callbackFn) {
188 var nowVisible = element.style.display !== 'none' || element.offsetLeft > 0; // create clone for reference
189
190 var clone = element.cloneNode(true);
191
192 var cleanup = function cleanup() {
193 element.removeAttribute('data-animated');
194 element.setAttribute('style', clone.getAttribute('style'));
195 element.style.display = nowVisible ? 'none' : '';
196
197 if (callbackFn) {
198 callbackFn();
199 }
200 }; // store attribute so everyone knows we're animating this element
201
202
203 element.setAttribute('data-animated', 'true'); // toggle element visiblity right away if we're making something visible
204
205 if (!nowVisible) {
206 element.style.display = '';
207 }
208
209 var hiddenStyles;
210 var visibleStyles; // animate properties
211
212 if (animation === 'slide') {
213 hiddenStyles = initObjectProperties(['height', 'borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'], 0);
214 visibleStyles = {};
215
216 if (!nowVisible) {
217 var computedStyles = window.getComputedStyle(element);
218 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.
219
220 if (!isFinite(visibleStyles.height)) {
221 var clientRect = element.getBoundingClientRect();
222 visibleStyles.height = clientRect.height;
223 }
224
225 css(element, hiddenStyles);
226 } // don't show a scrollbar during animation
227
228
229 element.style.overflowY = 'hidden';
230 animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);
231 } else {
232 hiddenStyles = {
233 opacity: 0
234 };
235 visibleStyles = {
236 opacity: 1
237 };
238
239 if (!nowVisible) {
240 css(element, hiddenStyles);
241 }
242
243 animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);
244 }
245 }
246
247 function animate(element, targetStyles, fn) {
248 var last = +new Date();
249 var initialStyles = window.getComputedStyle(element);
250 var currentStyles = {};
251 var propSteps = {};
252
253 for (var property in targetStyles) {
254 if (!targetStyles.hasOwnProperty(property)) {
255 continue;
256 } // make sure we have an object filled with floats
257
258
259 targetStyles[property] = parseFloat(targetStyles[property]); // calculate step size & current value
260
261 var to = targetStyles[property];
262 var current = parseFloat(initialStyles[property]); // is there something to do?
263
264 if (current === to) {
265 delete targetStyles[property];
266 continue;
267 }
268
269 propSteps[property] = (to - current) / duration; // points per second
270
271 currentStyles[property] = current;
272 }
273
274 var tick = function tick() {
275 var now = +new Date();
276 var timeSinceLastTick = now - last;
277 var done = true;
278 var step, to, increment, newValue;
279
280 for (var _property in targetStyles) {
281 if (!targetStyles.hasOwnProperty(_property)) {
282 continue;
283 }
284
285 step = propSteps[_property];
286 to = targetStyles[_property];
287 increment = step * timeSinceLastTick;
288 newValue = currentStyles[_property] + increment;
289
290 if (step > 0 && newValue >= to || step < 0 && newValue <= to) {
291 newValue = to;
292 } else {
293 done = false;
294 } // store new value
295
296
297 currentStyles[_property] = newValue;
298 element.style[_property] = _property !== 'opacity' ? newValue + 'px' : newValue;
299 }
300
301 last = +new Date();
302
303 if (!done) {
304 // keep going until we're done for all props
305 window.requestAnimationFrame(tick);
306 } else {
307 // call callback
308 fn && fn();
309 }
310 };
311
312 tick();
313 }
314
315 module.exports = {
316 toggle: toggle,
317 animate: animate,
318 animated: animated
319 };
320
321 },{}],3:[function(require,module,exports){
322 "use strict";
323
324 var defaults = {
325 animation: 'fade',
326 rehide: false,
327 content: '',
328 cookie: null,
329 icon: '&times',
330 screenWidthCondition: null,
331 position: 'center',
332 testMode: false,
333 trigger: false,
334 closable: true
335 };
336
337 var Animator = require('./animator.js');
338 /**
339 * Merge 2 objects, values of the latter overwriting the former.
340 *
341 * @param obj1
342 * @param obj2
343 * @returns {*}
344 */
345
346
347 function merge(obj1, obj2) {
348 var obj3 = {}; // add obj1 to obj3
349
350 for (var attrname in obj1) {
351 if (obj1.hasOwnProperty(attrname)) {
352 obj3[attrname] = obj1[attrname];
353 }
354 } // add obj2 to obj3
355
356
357 for (var _attrname in obj2) {
358 if (obj2.hasOwnProperty(_attrname)) {
359 obj3[_attrname] = obj2[_attrname];
360 }
361 }
362
363 return obj3;
364 }
365 /**
366 * Get the real height of entire document.
367 * @returns {number}
368 */
369
370
371 function getDocumentHeight() {
372 var body = document.body;
373 var html = document.documentElement;
374 return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
375 } // Box Object
376
377
378 function Box(id, config, fireEvent) {
379 this.id = id;
380 this.fireEvent = fireEvent; // store config values
381
382 this.config = merge(defaults, config); // add overlay element to dom and store ref to overlay
383
384 this.overlay = document.createElement('div');
385 this.overlay.style.display = 'none';
386 this.overlay.id = 'boxzilla-overlay-' + this.id;
387 this.overlay.classList.add('boxzilla-overlay');
388 document.body.appendChild(this.overlay); // state
389
390 this.visible = false;
391 this.dismissed = false;
392 this.triggered = false;
393 this.triggerHeight = this.calculateTriggerHeight();
394 this.cookieSet = this.isCookieSet();
395 this.element = null;
396 this.contentElement = null;
397 this.closeIcon = null; // create dom elements for this box
398
399 this.dom(); // further initialise the box
400
401 this.events();
402 } // initialise the box
403
404
405 Box.prototype.events = function () {
406 var box = this; // attach event to "close" icon inside box
407
408 if (this.closeIcon) {
409 this.closeIcon.addEventListener('click', function (evt) {
410 evt.preventDefault();
411 box.dismiss();
412 });
413 }
414
415 this.element.addEventListener('click', function (evt) {
416 if (evt.target.tagName === 'A') {
417 this.fireEvent('box.interactions.link', [box, evt.target]);
418 }
419 }, false);
420 this.element.addEventListener('submit', function (evt) {
421 box.setCookie();
422 this.fireEvent('box.interactions.form', [box, evt.target]);
423 }, false);
424 this.overlay.addEventListener('click', function (e) {
425 var x = e.offsetX;
426 var y = e.offsetY; // calculate if click was less than 40px outside box to avoid closing it by accident
427
428 var rect = box.element.getBoundingClientRect();
429 var margin = 40; // if click was not anywhere near box, dismiss it.
430
431 if (x < rect.left - margin || x > rect.right + margin || y < rect.top - margin || y > rect.bottom + margin) {
432 box.dismiss();
433 }
434 });
435 }; // generate dom elements for this box
436
437
438 Box.prototype.dom = function () {
439 var wrapper = document.createElement('div');
440 wrapper.className = 'boxzilla-container boxzilla-' + this.config.position + '-container';
441 var box = document.createElement('div');
442 box.id = 'boxzilla-' + this.id;
443 box.className = 'boxzilla boxzilla-' + this.id + ' boxzilla-' + this.config.position;
444 box.style.display = 'none';
445 wrapper.appendChild(box);
446 var content;
447
448 if (typeof this.config.content === 'string') {
449 content = document.createElement('div');
450 content.innerHTML = this.config.content;
451 } else {
452 content = this.config.content; // make sure element is visible
453
454 content.style.display = '';
455 }
456
457 content.className = 'boxzilla-content';
458 box.appendChild(content);
459
460 if (this.config.closable && this.config.icon) {
461 var closeIcon = document.createElement('span');
462 closeIcon.className = 'boxzilla-close-icon';
463 closeIcon.innerHTML = this.config.icon;
464 box.appendChild(closeIcon);
465 this.closeIcon = closeIcon;
466 }
467
468 document.body.appendChild(wrapper);
469 this.contentElement = content;
470 this.element = box;
471 }; // set (calculate) custom box styling depending on box options
472
473
474 Box.prototype.setCustomBoxStyling = function () {
475 // reset element to its initial state
476 var origDisplay = this.element.style.display;
477 this.element.style.display = '';
478 this.element.style.overflowY = '';
479 this.element.style.maxHeight = ''; // get new dimensions
480
481 var windowHeight = window.innerHeight;
482 var boxHeight = this.element.clientHeight; // add scrollbar to box and limit height
483
484 if (boxHeight > windowHeight) {
485 this.element.style.maxHeight = windowHeight + 'px';
486 this.element.style.overflowY = 'scroll';
487 } // set new top margin for boxes which are centered
488
489
490 if (this.config.position === 'center') {
491 var newTopMargin = (windowHeight - boxHeight) / 2;
492 newTopMargin = newTopMargin >= 0 ? newTopMargin : 0;
493 this.element.style.marginTop = newTopMargin + 'px';
494 }
495
496 this.element.style.display = origDisplay;
497 }; // toggle visibility of the box
498
499
500 Box.prototype.toggle = function (show, animate) {
501 show = typeof show === 'undefined' ? !this.visible : show;
502 animate = typeof animate === 'undefined' ? true : animate; // is box already at desired visibility?
503
504 if (show === this.visible) {
505 return false;
506 } // is box being animated?
507
508
509 if (Animator.animated(this.element)) {
510 return false;
511 } // if box should be hidden but is not closable, bail.
512
513
514 if (!show && !this.config.closable) {
515 return false;
516 } // set new visibility status
517
518
519 this.visible = show; // calculate new styling rules
520
521 this.setCustomBoxStyling(); // trigger event
522
523 this.fireEvent('box.' + (show ? 'show' : 'hide'), [this]); // show or hide box using selected animation
524
525 if (this.config.position === 'center') {
526 this.overlay.classList.toggle('boxzilla-' + this.id + '-overlay');
527
528 if (animate) {
529 Animator.toggle(this.overlay, 'fade');
530 } else {
531 this.overlay.style.display = show ? '' : 'none';
532 }
533 }
534
535 if (animate) {
536 Animator.toggle(this.element, this.config.animation, function () {
537 if (this.visible) {
538 return;
539 }
540
541 this.contentElement.innerHTML = this.contentElement.innerHTML + '';
542 }.bind(this));
543 } else {
544 this.element.style.display = show ? '' : 'none';
545 }
546
547 return true;
548 }; // show the box
549
550
551 Box.prototype.show = function (animate) {
552 return this.toggle(true, animate);
553 }; // hide the box
554
555
556 Box.prototype.hide = function (animate) {
557 return this.toggle(false, animate);
558 }; // calculate trigger height
559
560
561 Box.prototype.calculateTriggerHeight = function () {
562 var triggerHeight = 0;
563
564 if (this.config.trigger) {
565 if (this.config.trigger.method === 'element') {
566 var triggerElement = document.body.querySelector(this.config.trigger.value);
567
568 if (triggerElement) {
569 var offset = triggerElement.getBoundingClientRect();
570 triggerHeight = offset.top;
571 }
572 } else if (this.config.trigger.method === 'percentage') {
573 triggerHeight = this.config.trigger.value / 100 * getDocumentHeight();
574 }
575 }
576
577 return triggerHeight;
578 };
579
580 Box.prototype.fits = function () {
581 if (!this.config.screenWidthCondition || !this.config.screenWidthCondition.value) {
582 return true;
583 }
584
585 switch (this.config.screenWidthCondition.condition) {
586 case 'larger':
587 return window.innerWidth > this.config.screenWidthCondition.value;
588
589 case 'smaller':
590 return window.innerWidth < this.config.screenWidthCondition.value;
591 } // meh.. condition should be "smaller" or "larger", just return true.
592
593
594 return true;
595 };
596
597 Box.prototype.onResize = function () {
598 this.triggerHeight = this.calculateTriggerHeight();
599 this.setCustomBoxStyling();
600 }; // is this box enabled?
601
602
603 Box.prototype.mayAutoShow = function () {
604 if (this.dismissed) {
605 return false;
606 } // check if box fits on given minimum screen width
607
608
609 if (!this.fits()) {
610 return false;
611 } // if trigger empty or error in calculating triggerHeight, return false
612
613
614 if (!this.config.trigger) {
615 return false;
616 } // rely on cookie value (show if not set, don't show if set)
617
618
619 return !this.cookieSet;
620 };
621
622 Box.prototype.mayRehide = function () {
623 return this.config.rehide && this.triggered;
624 };
625
626 Box.prototype.isCookieSet = function () {
627 // always show on test mode or when no auto-trigger is configured
628 if (this.config.testMode || !this.config.trigger) {
629 return false;
630 } // if either cookie is null or trigger & dismiss are both falsey, don't bother checking.
631
632
633 if (!this.config.cookie || !this.config.cookie.triggered && !this.config.cookie.dismissed) {
634 return false;
635 }
636
637 return document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + 'boxzilla_box_' + this.id + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1') === 'true';
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 this.fireEvent('box.dismiss', [this]);
682 return true;
683 };
684
685 module.exports = Box;
686
687 },{"./animator.js":2}],4:[function(require,module,exports){
688 "use strict";
689
690 var Box = require('./box.js');
691
692 var throttle = require('./util.js').throttle;
693
694 var styles = require('./styles.js');
695
696 var ExitIntent = require('./triggers/exit-intent.js');
697
698 var Scroll = require('./triggers/scroll.js');
699
700 var Pageviews = require('./triggers/pageviews.js');
701
702 var Time = require('./triggers/time.js');
703
704 var initialised = false;
705 var boxes = [];
706 var listeners = {};
707
708 function onKeyUp(evt) {
709 if (evt.key === 'Escape' || evt.key === 'Esc') {
710 dismiss();
711 }
712 }
713
714 function recalculateHeights() {
715 boxes.forEach(function (box) {
716 return box.onResize();
717 });
718 }
719
720 function onElementClick(evt) {
721 // bubble up to <a> element
722 var el = evt.target;
723
724 for (var i = 0; i <= 3; i++) {
725 if (!el || el.tagName === 'A') {
726 break;
727 }
728
729 el = el.parentElement;
730 }
731
732 if (!el || el.tagName !== 'A' || !el.href) {
733 return;
734 }
735
736 var match = el.href.match(/[#&]boxzilla-(.+)/i);
737
738 if (match && match.length > 1) {
739 toggle(match[1]);
740 }
741 }
742
743 function trigger(event, args) {
744 listeners[event] && listeners[event].forEach(function (f) {
745 return f.apply(null, args);
746 });
747 }
748
749 function on(event, fn) {
750 listeners[event] = listeners[event] || [];
751 listeners[event].push(fn);
752 }
753
754 function off(event, fn) {
755 listeners[event] && listeners[event].filter(function (f) {
756 return f !== fn;
757 });
758 } // initialise & add event listeners
759
760
761 function init() {
762 if (initialised) {
763 return;
764 } // insert styles into DOM
765
766
767 var styleElement = document.createElement('style');
768 styleElement.innerHTML = styles;
769 document.head.appendChild(styleElement); // init triggers
770
771 ExitIntent(boxes);
772 Pageviews(boxes);
773 Scroll(boxes);
774 Time(boxes);
775 document.body.addEventListener('click', onElementClick, true);
776 window.addEventListener('resize', throttle(recalculateHeights));
777 window.addEventListener('load', recalculateHeights);
778 document.addEventListener('keyup', onKeyUp);
779 trigger('ready');
780 initialised = true; // ensure this function doesn't run again
781 }
782
783 function create(id, opts) {
784 // preserve backwards compat for minimumScreenWidth option
785 if (typeof opts.minimumScreenWidth !== 'undefined') {
786 opts.screenWidthCondition = {
787 condition: 'larger',
788 value: opts.minimumScreenWidth
789 };
790 }
791
792 id = String(id);
793 var box = new Box(id, opts, trigger);
794 boxes.push(box);
795 return box;
796 }
797
798 function get(id) {
799 id = String(id);
800
801 for (var i = 0; i < boxes.length; i++) {
802 if (boxes[i].id === id) {
803 return boxes[i];
804 }
805 }
806
807 throw new Error('No box exists with ID ' + id);
808 } // dismiss a single box (or all by omitting id param)
809
810
811 function dismiss(id, animate) {
812 if (id) {
813 get(id).dismiss(animate);
814 } else {
815 boxes.forEach(function (box) {
816 return box.dismiss(animate);
817 });
818 }
819 }
820
821 function hide(id, animate) {
822 if (id) {
823 get(id).hide(animate);
824 } else {
825 boxes.forEach(function (box) {
826 return box.hide(animate);
827 });
828 }
829 }
830
831 function show(id, animate) {
832 if (id) {
833 get(id).show(animate);
834 } else {
835 boxes.forEach(function (box) {
836 return box.show(animate);
837 });
838 }
839 }
840
841 function toggle(id, animate) {
842 if (id) {
843 get(id).toggle(animate);
844 } else {
845 boxes.forEach(function (box) {
846 return box.toggle(animate);
847 });
848 }
849 } // expose boxzilla object
850
851
852 var Boxzilla = {
853 off: off,
854 on: on,
855 get: get,
856 init: init,
857 create: create,
858 trigger: trigger,
859 show: show,
860 hide: hide,
861 dismiss: dismiss,
862 toggle: toggle,
863 boxes: boxes
864 };
865 window.Boxzilla = Boxzilla;
866
867 if (typeof module !== 'undefined' && module.exports) {
868 module.exports = Boxzilla;
869 }
870
871 },{"./box.js":3,"./styles.js":5,"./triggers/exit-intent.js":7,"./triggers/pageviews.js":8,"./triggers/scroll.js":9,"./triggers/time.js":10,"./util.js":11}],5:[function(require,module,exports){
872 "use strict";
873
874 var styles = '#boxzilla-overlay,.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}';
875 module.exports = styles;
876
877 },{}],6:[function(require,module,exports){
878 "use strict";
879
880 var Timer = function Timer() {
881 this.time = 0;
882 this.interval = 0;
883 };
884
885 Timer.prototype.tick = function () {
886 this.time++;
887 };
888
889 Timer.prototype.start = function () {
890 if (!this.interval) {
891 this.interval = window.setInterval(this.tick.bind(this), 1000);
892 }
893 };
894
895 Timer.prototype.stop = function () {
896 if (this.interval) {
897 window.clearInterval(this.interval);
898 this.interval = 0;
899 }
900 };
901
902 module.exports = Timer;
903
904 },{}],7:[function(require,module,exports){
905 "use strict";
906
907 module.exports = function (boxes) {
908 var timeout = null;
909 var touchStart = {};
910
911 function trigger() {
912 document.documentElement.removeEventListener('mouseleave', onMouseLeave);
913 document.documentElement.removeEventListener('mouseenter', onMouseEnter);
914 document.documentElement.removeEventListener('click', clearTimeout);
915 window.removeEventListener('touchstart', onTouchStart);
916 window.removeEventListener('touchend', onTouchEnd); // show boxes with exit intent trigger
917
918 boxes.forEach(function (box) {
919 if (box.mayAutoShow() && box.config.trigger.method === 'exit_intent') {
920 box.trigger();
921 }
922 });
923 }
924
925 function clearTimeout() {
926 if (timeout === null) {
927 return;
928 }
929
930 window.clearTimeout(timeout);
931 timeout = null;
932 }
933
934 function onMouseEnter() {
935 clearTimeout();
936 }
937
938 function getAddressBarY() {
939 if (document.documentMode || /Edge\//.test(navigator.userAgent)) {
940 return 5;
941 }
942
943 return 0;
944 }
945
946 function onMouseLeave(evt) {
947 clearTimeout(); // did mouse leave at top of window?
948 // add small exception space in the top-right corner
949
950 if (evt.clientY <= getAddressBarY() && evt.clientX < 0.8 * window.innerWidth) {
951 timeout = window.setTimeout(trigger, 600);
952 }
953 }
954
955 function onTouchStart() {
956 clearTimeout();
957 touchStart = {
958 timestamp: performance.now(),
959 scrollY: window.scrollY,
960 windowHeight: window.innerHeight
961 };
962 }
963
964 function onTouchEnd(evt) {
965 clearTimeout(); // did address bar appear?
966
967 if (window.innerHeight > touchStart.windowHeight) {
968 return;
969 } // allow a tiny tiny margin for error, to not fire on clicks
970
971
972 if (window.scrollY + 20 > touchStart.scrollY) {
973 return;
974 }
975
976 if (performance.now() - touchStart.timestamp > 300) {
977 return;
978 }
979
980 if (['A', 'INPUT', 'BUTTON'].indexOf(evt.target.tagName) > -1) {
981 return;
982 }
983
984 timeout = window.setTimeout(trigger, 800);
985 }
986
987 window.addEventListener('touchstart', onTouchStart);
988 window.addEventListener('touchend', onTouchEnd);
989 document.documentElement.addEventListener('mouseenter', onMouseEnter);
990 document.documentElement.addEventListener('mouseleave', onMouseLeave);
991 document.documentElement.addEventListener('click', clearTimeout);
992 };
993
994 },{}],8:[function(require,module,exports){
995 "use strict";
996
997 module.exports = function (boxes) {
998 var pageviews;
999
1000 try {
1001 pageviews = sessionStorage.getItem('boxzilla_pageviews') || 0;
1002 sessionStorage.setItem('boxzilla_pageviews', ++pageviews);
1003 } catch (e) {
1004 pageviews = 0;
1005 }
1006
1007 window.setTimeout(function () {
1008 boxes.forEach(function (box) {
1009 if (box.config.trigger.method === 'pageviews' && pageviews > box.config.trigger.value && box.mayAutoShow()) {
1010 box.trigger();
1011 }
1012 });
1013 }, 1000);
1014 };
1015
1016 },{}],9:[function(require,module,exports){
1017 "use strict";
1018
1019 var throttle = require('../util.js').throttle;
1020
1021 module.exports = function (boxes) {
1022 // check triggerHeight criteria for all boxes
1023 function checkHeightCriteria() {
1024 var scrollY = window.hasOwnProperty('pageYOffset') ? window.pageYOffset : window.scrollTop;
1025 scrollY = scrollY + window.innerHeight * 0.9;
1026 boxes.forEach(function (box) {
1027 if (!box.mayAutoShow() || box.triggerHeight <= 0) {
1028 return;
1029 }
1030
1031 if (scrollY > box.triggerHeight) {
1032 box.trigger();
1033 } else if (box.mayRehide() && scrollY < box.triggerHeight - 5) {
1034 // if box may auto-hide and scrollY is less than triggerHeight (with small margin of error), hide box
1035 box.hide();
1036 }
1037 });
1038 }
1039
1040 window.addEventListener('touchstart', throttle(checkHeightCriteria), true);
1041 window.addEventListener('scroll', throttle(checkHeightCriteria), true);
1042 };
1043
1044 },{"../util.js":11}],10:[function(require,module,exports){
1045 "use strict";
1046
1047 var Timer = require('../timer.js');
1048
1049 module.exports = function (boxes) {
1050 var siteTimer = new Timer();
1051 var pageTimer = new Timer();
1052 var timers = {
1053 start: function start() {
1054 try {
1055 var sessionTime = parseInt(sessionStorage.getItem('boxzilla_timer'));
1056
1057 if (sessionTime) {
1058 siteTimer.time = sessionTime;
1059 }
1060 } catch (e) {}
1061
1062 siteTimer.start();
1063 pageTimer.start();
1064 },
1065 stop: function stop() {
1066 sessionStorage.setItem('boxzilla_timer', siteTimer.time);
1067 siteTimer.stop();
1068 pageTimer.stop();
1069 }
1070 }; // start timers
1071
1072 timers.start(); // stop timers when leaving page or switching to other tab
1073
1074 document.addEventListener('visibilitychange', function () {
1075 document.hidden ? timers.stop() : timers.start();
1076 });
1077 window.addEventListener('beforeunload', function () {
1078 timers.stop();
1079 });
1080 window.setInterval(function () {
1081 boxes.forEach(function (box) {
1082 if (box.config.trigger.method === 'time_on_site' && siteTimer.time > box.config.trigger.value && box.mayAutoShow()) {
1083 box.trigger();
1084 } else if (box.config.trigger.method === 'time_on_page' && pageTimer.time > box.config.trigger.value && box.mayAutoShow()) {
1085 box.trigger();
1086 }
1087 });
1088 }, 1000);
1089 };
1090
1091 },{"../timer.js":6}],11:[function(require,module,exports){
1092 "use strict";
1093
1094 function throttle(fn, threshold, scope) {
1095 threshold || (threshold = 800);
1096 var last;
1097 var deferTimer;
1098 return function () {
1099 var context = scope || this;
1100 var now = +new Date();
1101 var args = arguments;
1102
1103 if (last && now < last + threshold) {
1104 // hold on to it
1105 clearTimeout(deferTimer);
1106 deferTimer = setTimeout(function () {
1107 last = now;
1108 fn.apply(context, args);
1109 }, threshold);
1110 } else {
1111 last = now;
1112 fn.apply(context, args);
1113 }
1114 };
1115 }
1116
1117 module.exports = {
1118 throttle: throttle
1119 };
1120
1121 },{}]},{},[1]);
1122 ; })();