Version Description
Download this release
Release Info
Developer | DvanKooten |
Plugin | Boxzilla |
Version | 3.2.10 |
Comparing to | |
See all releases |
Code changes from version 3.2.9 to 3.2.10
- assets/js/script.js +274 -198
- assets/js/script.min.js +1 -1
- assets/js/script.min.js.map +1 -1
- bootstrap.php +1 -1
- boxzilla.php +3 -3
- languages/boxzilla.pot +72 -68
- readme.txt +13 -2
- src/admin/class-admin.php +812 -763
- src/admin/class-autocomplete.php +97 -91
- src/admin/class-installer.php +93 -88
- src/admin/class-migrations.php +21 -17
- src/admin/class-notices.php +36 -32
- src/admin/class-review-notice.php +29 -23
- src/admin/migrations/3.1-cookie-option.php +9 -9
- src/admin/migrations/3.1.11-screen-width-condition.php +11 -11
- src/admin/views/extensions.php +16 -14
- src/admin/views/metaboxes/box-appearance-controls.php +19 -19
- src/admin/views/metaboxes/box-option-controls.php +145 -142
- src/admin/views/metaboxes/email-optin.php +3 -3
- src/admin/views/metaboxes/need-help.php +2 -2
- src/admin/views/settings.php +12 -12
- src/class-bootstrapper.php +24 -22
- src/class-box.php +209 -203
- src/class-boxzilla-service-provider.php +59 -64
- src/class-boxzilla.php +3 -1
- src/class-loader.php +336 -332
- src/class-php-fallback.php +58 -56
- src/class-plugin.php +114 -105
- src/default-actions.php +26 -25
- src/default-filters.php +9 -9
- src/di/class-container-with-property-access.php +24 -19
- src/functions.php +4 -4
- src/licensing/class-api-exception.php +29 -27
- src/licensing/class-api.php +174 -168
- src/licensing/class-license-manager.php +181 -173
- src/licensing/class-license-service-provider.php +34 -34
- src/licensing/class-license.php +108 -101
- src/licensing/class-poller.php +16 -13
- src/licensing/class-update-manager.php +240 -232
- src/licensing/views/license-form.php +32 -23
assets/js/script.js
CHANGED
@@ -1,151 +1,12 @@
|
|
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 |
-
box.element.firstChild.firstChild.className += " first-child";
|
68 |
-
box.element.firstChild.lastChild.className += " last-child"; // maybe show box right away
|
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 || 0 === window.location.hash.length) {
|
85 |
-
return false;
|
86 |
-
}
|
87 |
-
|
88 |
-
var elementId = window.location.hash.substring(1); // only attempt on strings looking like an ID
|
89 |
-
|
90 |
-
var regex = /^[a-zA-Z\-\_0-9]+$/;
|
91 |
-
|
92 |
-
if (!regex.test(elementId)) {
|
93 |
-
return false;
|
94 |
-
}
|
95 |
-
|
96 |
-
if (elementId === box.element.id) {
|
97 |
-
return true;
|
98 |
-
} else if (box.element.querySelector('#' + elementId)) {
|
99 |
-
return true;
|
100 |
-
}
|
101 |
-
|
102 |
-
return false;
|
103 |
-
}
|
104 |
-
|
105 |
-
function maybeOpenMailChimpForWordPressBox() {
|
106 |
-
if (_typeof(window.mc4wp_forms_config) !== "object" || !window.mc4wp_forms_config.submitted_form) {
|
107 |
-
return;
|
108 |
-
}
|
109 |
-
|
110 |
-
var selector = '#' + window.mc4wp_forms_config.submitted_form.element_id;
|
111 |
-
var boxes = Boxzilla.boxes;
|
112 |
-
|
113 |
-
for (var boxId in boxes) {
|
114 |
-
if (!boxes.hasOwnProperty(boxId)) {
|
115 |
-
continue;
|
116 |
-
}
|
117 |
-
|
118 |
-
var box = boxes[boxId];
|
119 |
-
|
120 |
-
if (box.element.querySelector(selector)) {
|
121 |
-
box.show();
|
122 |
-
return;
|
123 |
-
}
|
124 |
-
}
|
125 |
-
} // print message when test mode is enabled
|
126 |
-
|
127 |
-
|
128 |
-
var isLoggedIn = document.body.className.indexOf('logged-in') > -1;
|
129 |
-
|
130 |
-
if (isLoggedIn && options.testMode) {
|
131 |
-
console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\'re done testing.');
|
132 |
-
} // init boxzilla
|
133 |
-
|
134 |
-
|
135 |
-
Boxzilla.init(); // on window.load, create DOM elements for boxes
|
136 |
-
|
137 |
-
window.addEventListener('load', createBoxesFromConfig);
|
138 |
-
})();
|
139 |
-
|
140 |
-
},{"boxzilla":5}],2:[function(require,module,exports){
|
141 |
/*!
|
142 |
-
* EventEmitter
|
143 |
* Unlicense - http://unlicense.org/
|
144 |
* Oliver Caldwell - http://oli.me.uk/
|
145 |
* @preserve
|
146 |
*/
|
147 |
|
148 |
-
;(function () {
|
149 |
'use strict';
|
150 |
|
151 |
/**
|
@@ -158,7 +19,6 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
158 |
|
159 |
// Shortcuts to improve speed and size
|
160 |
var proto = EventEmitter.prototype;
|
161 |
-
var exports = this;
|
162 |
var originalGlobalValue = exports.EventEmitter;
|
163 |
|
164 |
/**
|
@@ -259,6 +119,16 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
259 |
return response || listeners;
|
260 |
};
|
261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
/**
|
263 |
* Adds a listener function to the specified event.
|
264 |
* The listener will not be added if it is a duplicate.
|
@@ -270,6 +140,10 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
270 |
* @return {Object} Current instance of EventEmitter for chaining.
|
271 |
*/
|
272 |
proto.addListener = function addListener(evt, listener) {
|
|
|
|
|
|
|
|
|
273 |
var listeners = this.getListenersAsObject(evt);
|
274 |
var listenerIsWrapped = typeof listener === 'object';
|
275 |
var key;
|
@@ -369,7 +243,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
369 |
|
370 |
/**
|
371 |
* Adds listeners in bulk using the manipulateListeners method.
|
372 |
-
* If you pass an object as the
|
373 |
* You can also pass it a regular expression to add the array of listeners to all events that match it.
|
374 |
* Yeah, this function does quite a bit. That's probably a bad thing.
|
375 |
*
|
@@ -384,7 +258,7 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
384 |
|
385 |
/**
|
386 |
* Removes listeners in bulk using the manipulateListeners method.
|
387 |
-
* If you pass an object as the
|
388 |
* You can also pass it an event name and an array of listeners to be removed.
|
389 |
* You can also pass it a regular expression to remove the listeners from all events that match it.
|
390 |
*
|
@@ -508,9 +382,8 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
508 |
for (key in listenersMap) {
|
509 |
if (listenersMap.hasOwnProperty(key)) {
|
510 |
listeners = listenersMap[key].slice(0);
|
511 |
-
i = listeners.length;
|
512 |
|
513 |
-
|
514 |
// If the listener returns true then it shall be removed from the event
|
515 |
// The function is executed either with a basic call or an apply if there is an args array
|
516 |
listener = listeners[i];
|
@@ -611,9 +484,9 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat
|
|
611 |
else {
|
612 |
exports.EventEmitter = EventEmitter;
|
613 |
}
|
614 |
-
}
|
615 |
|
616 |
-
},{}],
|
617 |
"use strict";
|
618 |
|
619 |
var duration = 320;
|
@@ -787,7 +660,7 @@ module.exports = {
|
|
787 |
'animated': animated
|
788 |
};
|
789 |
|
790 |
-
},{}],
|
791 |
'use strict';
|
792 |
|
793 |
var defaults = {
|
@@ -1130,21 +1003,28 @@ module.exports = function (_Boxzilla) {
|
|
1130 |
return Box;
|
1131 |
};
|
1132 |
|
1133 |
-
},{"./animator.js":
|
1134 |
'use strict';
|
1135 |
|
1136 |
-
var EventEmitter = require('wolfy87-eventemitter')
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1148 |
|
1149 |
function throttle(fn, threshhold, scope) {
|
1150 |
threshhold || (threshhold = 250);
|
@@ -1170,7 +1050,7 @@ function throttle(fn, threshhold, scope) {
|
|
1170 |
|
1171 |
|
1172 |
function onKeyUp(e) {
|
1173 |
-
if (e.keyCode
|
1174 |
Boxzilla.dismiss();
|
1175 |
}
|
1176 |
} // check "pageviews" criteria for each box
|
@@ -1264,9 +1144,9 @@ function onOverlayClick(e) {
|
|
1264 |
});
|
1265 |
}
|
1266 |
|
1267 |
-
function
|
1268 |
// do nothing if already triggered OR another box is visible.
|
1269 |
-
if (
|
1270 |
return;
|
1271 |
}
|
1272 |
|
@@ -1275,34 +1155,12 @@ function triggerExitIntent() {
|
|
1275 |
box.trigger();
|
1276 |
}
|
1277 |
});
|
1278 |
-
exitIntentTriggered = true;
|
1279 |
-
}
|
1280 |
-
|
1281 |
-
function onMouseLeave(e) {
|
1282 |
-
var delay = 400; // did mouse leave at top of window?
|
1283 |
-
|
1284 |
-
if (e.clientY <= 0) {
|
1285 |
-
exitIntentDelayTimer = window.setTimeout(triggerExitIntent, delay);
|
1286 |
-
}
|
1287 |
}
|
1288 |
|
1289 |
function isAnyBoxVisible() {
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
if (box.visible) {
|
1294 |
-
return true;
|
1295 |
-
}
|
1296 |
-
}
|
1297 |
-
|
1298 |
-
return false;
|
1299 |
-
}
|
1300 |
-
|
1301 |
-
function onMouseEnter() {
|
1302 |
-
if (exitIntentDelayTimer) {
|
1303 |
-
window.clearInterval(exitIntentDelayTimer);
|
1304 |
-
exitIntentDelayTimer = null;
|
1305 |
-
}
|
1306 |
}
|
1307 |
|
1308 |
function onElementClick(e) {
|
@@ -1346,6 +1204,10 @@ var timers = {
|
|
1346 |
}; // initialise & add event listeners
|
1347 |
|
1348 |
Boxzilla.init = function () {
|
|
|
|
|
|
|
|
|
1349 |
document.body.addEventListener('click', onElementClick, true);
|
1350 |
|
1351 |
try {
|
@@ -1357,8 +1219,6 @@ Boxzilla.init = function () {
|
|
1357 |
siteTimer = new Timer(0);
|
1358 |
pageTimer = new Timer(0); // insert styles into DOM
|
1359 |
|
1360 |
-
var styles = require('./styles.js');
|
1361 |
-
|
1362 |
var styleElement = document.createElement('style');
|
1363 |
styleElement.setAttribute("type", "text/css");
|
1364 |
styleElement.innerHTML = styles;
|
@@ -1367,8 +1227,9 @@ Boxzilla.init = function () {
|
|
1367 |
overlay = document.createElement('div');
|
1368 |
overlay.style.display = 'none';
|
1369 |
overlay.id = 'boxzilla-overlay';
|
1370 |
-
document.body.appendChild(overlay); //
|
1371 |
|
|
|
1372 |
scrollElement.addEventListener('touchstart', throttle(checkHeightCriteria), true);
|
1373 |
scrollElement.addEventListener('scroll', throttle(checkHeightCriteria), true);
|
1374 |
window.addEventListener('resize', throttle(recalculateHeights));
|
@@ -1376,8 +1237,6 @@ Boxzilla.init = function () {
|
|
1376 |
overlay.addEventListener('click', onOverlayClick);
|
1377 |
window.setInterval(checkTimeCriteria, 1000);
|
1378 |
window.setTimeout(checkPageViewsCriteria, 1000);
|
1379 |
-
document.documentElement.addEventListener('mouseleave', onMouseLeave);
|
1380 |
-
document.documentElement.addEventListener('mouseenter', onMouseEnter);
|
1381 |
document.addEventListener('keyup', onKeyUp);
|
1382 |
timers.start();
|
1383 |
window.addEventListener('focus', timers.start);
|
@@ -1387,6 +1246,7 @@ Boxzilla.init = function () {
|
|
1387 |
});
|
1388 |
window.addEventListener('blur', timers.stop);
|
1389 |
Boxzilla.trigger('ready');
|
|
|
1390 |
};
|
1391 |
/**
|
1392 |
* Create a new Box
|
@@ -1475,13 +1335,13 @@ if (typeof module !== 'undefined' && module.exports) {
|
|
1475 |
module.exports = Boxzilla;
|
1476 |
}
|
1477 |
|
1478 |
-
},{"./box.js":
|
1479 |
"use strict";
|
1480 |
|
1481 |
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}";
|
1482 |
module.exports = styles;
|
1483 |
|
1484 |
-
},{}],
|
1485 |
'use strict';
|
1486 |
|
1487 |
var Timer = function Timer(start) {
|
@@ -1508,5 +1368,221 @@ Timer.prototype.stop = function () {
|
|
1508 |
|
1509 |
module.exports = Timer;
|
1510 |
|
1511 |
-
},{}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1512 |
; })();
|
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 |
/*!
|
3 |
+
* EventEmitter v5.2.5 - git.io/ee
|
4 |
* Unlicense - http://unlicense.org/
|
5 |
* Oliver Caldwell - http://oli.me.uk/
|
6 |
* @preserve
|
7 |
*/
|
8 |
|
9 |
+
;(function (exports) {
|
10 |
'use strict';
|
11 |
|
12 |
/**
|
19 |
|
20 |
// Shortcuts to improve speed and size
|
21 |
var proto = EventEmitter.prototype;
|
|
|
22 |
var originalGlobalValue = exports.EventEmitter;
|
23 |
|
24 |
/**
|
119 |
return response || listeners;
|
120 |
};
|
121 |
|
122 |
+
function isValidListener (listener) {
|
123 |
+
if (typeof listener === 'function' || listener instanceof RegExp) {
|
124 |
+
return true
|
125 |
+
} else if (listener && typeof listener === 'object') {
|
126 |
+
return isValidListener(listener.listener)
|
127 |
+
} else {
|
128 |
+
return false
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
/**
|
133 |
* Adds a listener function to the specified event.
|
134 |
* The listener will not be added if it is a duplicate.
|
140 |
* @return {Object} Current instance of EventEmitter for chaining.
|
141 |
*/
|
142 |
proto.addListener = function addListener(evt, listener) {
|
143 |
+
if (!isValidListener(listener)) {
|
144 |
+
throw new TypeError('listener must be a function');
|
145 |
+
}
|
146 |
+
|
147 |
var listeners = this.getListenersAsObject(evt);
|
148 |
var listenerIsWrapped = typeof listener === 'object';
|
149 |
var key;
|
243 |
|
244 |
/**
|
245 |
* Adds listeners in bulk using the manipulateListeners method.
|
246 |
+
* 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.
|
247 |
* You can also pass it a regular expression to add the array of listeners to all events that match it.
|
248 |
* Yeah, this function does quite a bit. That's probably a bad thing.
|
249 |
*
|
258 |
|
259 |
/**
|
260 |
* Removes listeners in bulk using the manipulateListeners method.
|
261 |
+
* 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.
|
262 |
* You can also pass it an event name and an array of listeners to be removed.
|
263 |
* You can also pass it a regular expression to remove the listeners from all events that match it.
|
264 |
*
|
382 |
for (key in listenersMap) {
|
383 |
if (listenersMap.hasOwnProperty(key)) {
|
384 |
listeners = listenersMap[key].slice(0);
|
|
|
385 |
|
386 |
+
for (i = 0; i < listeners.length; i++) {
|
387 |
// If the listener returns true then it shall be removed from the event
|
388 |
// The function is executed either with a basic call or an apply if there is an args array
|
389 |
listener = listeners[i];
|
484 |
else {
|
485 |
exports.EventEmitter = EventEmitter;
|
486 |
}
|
487 |
+
}(typeof window !== 'undefined' ? window : this || {}));
|
488 |
|
489 |
+
},{}],2:[function(require,module,exports){
|
490 |
"use strict";
|
491 |
|
492 |
var duration = 320;
|
660 |
'animated': animated
|
661 |
};
|
662 |
|
663 |
+
},{}],3:[function(require,module,exports){
|
664 |
'use strict';
|
665 |
|
666 |
var defaults = {
|
1003 |
return Box;
|
1004 |
};
|
1005 |
|
1006 |
+
},{"./animator.js":2}],4:[function(require,module,exports){
|
1007 |
'use strict';
|
1008 |
|
1009 |
+
var EventEmitter = require('wolfy87-eventemitter');
|
1010 |
+
|
1011 |
+
var Timer = require('./timer.js');
|
1012 |
+
|
1013 |
+
var Boxzilla = Object.create(EventEmitter.prototype);
|
1014 |
+
|
1015 |
+
var Box = require('./box.js')(Boxzilla);
|
1016 |
+
|
1017 |
+
var boxes = [];
|
1018 |
+
var overlay;
|
1019 |
+
var scrollElement = window;
|
1020 |
+
var siteTimer;
|
1021 |
+
var pageTimer;
|
1022 |
+
var pageViews;
|
1023 |
+
var initialised = false;
|
1024 |
+
|
1025 |
+
var styles = require('./styles.js');
|
1026 |
+
|
1027 |
+
var ExitIntent = require('./triggers/exit-intent.js');
|
1028 |
|
1029 |
function throttle(fn, threshhold, scope) {
|
1030 |
threshhold || (threshhold = 250);
|
1050 |
|
1051 |
|
1052 |
function onKeyUp(e) {
|
1053 |
+
if (e.keyCode === 27) {
|
1054 |
Boxzilla.dismiss();
|
1055 |
}
|
1056 |
} // check "pageviews" criteria for each box
|
1144 |
});
|
1145 |
}
|
1146 |
|
1147 |
+
function showBoxesWithExitIntentTrigger() {
|
1148 |
// do nothing if already triggered OR another box is visible.
|
1149 |
+
if (isAnyBoxVisible()) {
|
1150 |
return;
|
1151 |
}
|
1152 |
|
1155 |
box.trigger();
|
1156 |
}
|
1157 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1158 |
}
|
1159 |
|
1160 |
function isAnyBoxVisible() {
|
1161 |
+
return boxes.filter(function (b) {
|
1162 |
+
return b.visible;
|
1163 |
+
}).length > 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1164 |
}
|
1165 |
|
1166 |
function onElementClick(e) {
|
1204 |
}; // initialise & add event listeners
|
1205 |
|
1206 |
Boxzilla.init = function () {
|
1207 |
+
if (initialised) {
|
1208 |
+
return;
|
1209 |
+
}
|
1210 |
+
|
1211 |
document.body.addEventListener('click', onElementClick, true);
|
1212 |
|
1213 |
try {
|
1219 |
siteTimer = new Timer(0);
|
1220 |
pageTimer = new Timer(0); // insert styles into DOM
|
1221 |
|
|
|
|
|
1222 |
var styleElement = document.createElement('style');
|
1223 |
styleElement.setAttribute("type", "text/css");
|
1224 |
styleElement.innerHTML = styles;
|
1227 |
overlay = document.createElement('div');
|
1228 |
overlay.style.display = 'none';
|
1229 |
overlay.id = 'boxzilla-overlay';
|
1230 |
+
document.body.appendChild(overlay); // init exit intent trigger
|
1231 |
|
1232 |
+
new ExitIntent(showBoxesWithExitIntentTrigger);
|
1233 |
scrollElement.addEventListener('touchstart', throttle(checkHeightCriteria), true);
|
1234 |
scrollElement.addEventListener('scroll', throttle(checkHeightCriteria), true);
|
1235 |
window.addEventListener('resize', throttle(recalculateHeights));
|
1237 |
overlay.addEventListener('click', onOverlayClick);
|
1238 |
window.setInterval(checkTimeCriteria, 1000);
|
1239 |
window.setTimeout(checkPageViewsCriteria, 1000);
|
|
|
|
|
1240 |
document.addEventListener('keyup', onKeyUp);
|
1241 |
timers.start();
|
1242 |
window.addEventListener('focus', timers.start);
|
1246 |
});
|
1247 |
window.addEventListener('blur', timers.stop);
|
1248 |
Boxzilla.trigger('ready');
|
1249 |
+
initialised = true; // ensure this function doesn't run again
|
1250 |
};
|
1251 |
/**
|
1252 |
* Create a new Box
|
1335 |
module.exports = Boxzilla;
|
1336 |
}
|
1337 |
|
1338 |
+
},{"./box.js":3,"./styles.js":5,"./timer.js":6,"./triggers/exit-intent.js":7,"wolfy87-eventemitter":1}],5:[function(require,module,exports){
|
1339 |
"use strict";
|
1340 |
|
1341 |
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}";
|
1342 |
module.exports = styles;
|
1343 |
|
1344 |
+
},{}],6:[function(require,module,exports){
|
1345 |
'use strict';
|
1346 |
|
1347 |
var Timer = function Timer(start) {
|
1368 |
|
1369 |
module.exports = Timer;
|
1370 |
|
1371 |
+
},{}],7:[function(require,module,exports){
|
1372 |
+
'use strict';
|
1373 |
+
|
1374 |
+
module.exports = function (callback) {
|
1375 |
+
var timeout = null;
|
1376 |
+
var touchStart = {};
|
1377 |
+
|
1378 |
+
function triggerCallback() {
|
1379 |
+
document.documentElement.removeEventListener('mouseleave', onMouseLeave);
|
1380 |
+
document.documentElement.removeEventListener('mouseenter', onMouseEnter);
|
1381 |
+
document.documentElement.removeEventListener('click', clearTimeout);
|
1382 |
+
window.removeEventListener('touchstart', onTouchStart);
|
1383 |
+
window.removeEventListener('touchend', onTouchEnd);
|
1384 |
+
callback();
|
1385 |
+
}
|
1386 |
+
|
1387 |
+
function clearTimeout() {
|
1388 |
+
if (timeout === null) {
|
1389 |
+
return;
|
1390 |
+
}
|
1391 |
+
|
1392 |
+
window.clearTimeout(timeout);
|
1393 |
+
timeout = null;
|
1394 |
+
}
|
1395 |
+
|
1396 |
+
function onMouseEnter(evt) {
|
1397 |
+
clearTimeout();
|
1398 |
+
}
|
1399 |
+
|
1400 |
+
function onMouseLeave(evt) {
|
1401 |
+
clearTimeout(); // did mouse leave at top of window?
|
1402 |
+
// add small exception space in the top-right corner
|
1403 |
+
|
1404 |
+
if (evt.clientY <= 0 && evt.clientX < 0.80 * window.innerWidth) {
|
1405 |
+
timeout = window.setTimeout(triggerCallback, 400);
|
1406 |
+
}
|
1407 |
+
}
|
1408 |
+
|
1409 |
+
function onTouchStart(evt) {
|
1410 |
+
clearTimeout();
|
1411 |
+
touchStart = {
|
1412 |
+
timestamp: performance.now(),
|
1413 |
+
scrollY: window.scrollY,
|
1414 |
+
windowHeight: window.innerHeight
|
1415 |
+
};
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
function onTouchEnd(evt) {
|
1419 |
+
clearTimeout(); // did address bar appear?
|
1420 |
+
|
1421 |
+
if (window.innerHeight > touchStart.windowHeight) {
|
1422 |
+
return;
|
1423 |
+
} // allow a tiny tiny margin for error, to not fire on clicks
|
1424 |
+
|
1425 |
+
|
1426 |
+
if (window.scrollY + 20 >= touchStart.scrollY) {
|
1427 |
+
return;
|
1428 |
+
}
|
1429 |
+
|
1430 |
+
if (performance.now() - touchStart.timestamp > 300) {
|
1431 |
+
return;
|
1432 |
+
}
|
1433 |
+
|
1434 |
+
if (['A', 'INPUT', 'BUTTON'].indexOf(evt.target.tagName) > -1) {
|
1435 |
+
return;
|
1436 |
+
}
|
1437 |
+
|
1438 |
+
timeout = window.setTimeout(triggerCallback, 800);
|
1439 |
+
}
|
1440 |
+
|
1441 |
+
window.addEventListener('touchstart', onTouchStart);
|
1442 |
+
window.addEventListener('touchend', onTouchEnd);
|
1443 |
+
document.documentElement.addEventListener('mouseenter', onMouseEnter);
|
1444 |
+
document.documentElement.addEventListener('mouseleave', onMouseLeave);
|
1445 |
+
document.documentElement.addEventListener('click', clearTimeout);
|
1446 |
+
};
|
1447 |
+
|
1448 |
+
},{}],8:[function(require,module,exports){
|
1449 |
+
"use strict";
|
1450 |
+
|
1451 |
+
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); }
|
1452 |
+
|
1453 |
+
(function () {
|
1454 |
+
'use strict';
|
1455 |
+
|
1456 |
+
var Boxzilla = require('boxzilla');
|
1457 |
+
|
1458 |
+
var options = window.boxzilla_options; // expose Boxzilla object to window
|
1459 |
+
|
1460 |
+
window.Boxzilla = Boxzilla; // helper function for setting CSS styles
|
1461 |
+
|
1462 |
+
function css(element, styles) {
|
1463 |
+
if (styles.background_color) {
|
1464 |
+
element.style.background = styles.background_color;
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
if (styles.color) {
|
1468 |
+
element.style.color = styles.color;
|
1469 |
+
}
|
1470 |
+
|
1471 |
+
if (styles.border_color) {
|
1472 |
+
element.style.borderColor = styles.border_color;
|
1473 |
+
}
|
1474 |
+
|
1475 |
+
if (styles.border_width) {
|
1476 |
+
element.style.borderWidth = parseInt(styles.border_width) + "px";
|
1477 |
+
}
|
1478 |
+
|
1479 |
+
if (styles.border_style) {
|
1480 |
+
element.style.borderStyle = styles.border_style;
|
1481 |
+
}
|
1482 |
+
|
1483 |
+
if (styles.width) {
|
1484 |
+
element.style.maxWidth = parseInt(styles.width) + "px";
|
1485 |
+
}
|
1486 |
+
}
|
1487 |
+
|
1488 |
+
function createBoxesFromConfig() {
|
1489 |
+
// failsafe against including script twice.
|
1490 |
+
if (options.inited) {
|
1491 |
+
return;
|
1492 |
+
} // create boxes from options
|
1493 |
+
|
1494 |
+
|
1495 |
+
for (var key in options.boxes) {
|
1496 |
+
// get opts
|
1497 |
+
var boxOpts = options.boxes[key];
|
1498 |
+
boxOpts.testMode = isLoggedIn && options.testMode; // find box content element, bail if not found
|
1499 |
+
|
1500 |
+
var boxContentElement = document.getElementById('boxzilla-box-' + boxOpts.id + '-content');
|
1501 |
+
|
1502 |
+
if (!boxContentElement) {
|
1503 |
+
continue;
|
1504 |
+
} // use element as content option
|
1505 |
+
|
1506 |
+
|
1507 |
+
boxOpts.content = boxContentElement; // create box
|
1508 |
+
|
1509 |
+
var box = Boxzilla.create(boxOpts.id, boxOpts); // add box slug to box element as classname
|
1510 |
+
|
1511 |
+
box.element.className = box.element.className + ' boxzilla-' + boxOpts.post.slug; // add custom css to box
|
1512 |
+
|
1513 |
+
css(box.element, boxOpts.css);
|
1514 |
+
box.element.firstChild.firstChild.className += " first-child";
|
1515 |
+
box.element.firstChild.lastChild.className += " last-child"; // maybe show box right away
|
1516 |
+
|
1517 |
+
if (box.fits() && locationHashRefersBox(box)) {
|
1518 |
+
box.show();
|
1519 |
+
}
|
1520 |
+
} // set flag to prevent initialising twice
|
1521 |
+
|
1522 |
+
|
1523 |
+
options.inited = true; // trigger "done" event.
|
1524 |
+
|
1525 |
+
Boxzilla.trigger('done'); // maybe open box with MC4WP form in it
|
1526 |
+
|
1527 |
+
maybeOpenMailChimpForWordPressBox();
|
1528 |
+
}
|
1529 |
+
|
1530 |
+
function locationHashRefersBox(box) {
|
1531 |
+
if (!window.location.hash || 0 === window.location.hash.length) {
|
1532 |
+
return false;
|
1533 |
+
}
|
1534 |
+
|
1535 |
+
var elementId = window.location.hash.substring(1); // only attempt on strings looking like an ID
|
1536 |
+
|
1537 |
+
var regex = /^[a-zA-Z\-\_0-9]+$/;
|
1538 |
+
|
1539 |
+
if (!regex.test(elementId)) {
|
1540 |
+
return false;
|
1541 |
+
}
|
1542 |
+
|
1543 |
+
if (elementId === box.element.id) {
|
1544 |
+
return true;
|
1545 |
+
} else if (box.element.querySelector('#' + elementId)) {
|
1546 |
+
return true;
|
1547 |
+
}
|
1548 |
+
|
1549 |
+
return false;
|
1550 |
+
}
|
1551 |
+
|
1552 |
+
function maybeOpenMailChimpForWordPressBox() {
|
1553 |
+
if (_typeof(window.mc4wp_forms_config) !== "object" || !window.mc4wp_forms_config.submitted_form) {
|
1554 |
+
return;
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
var selector = '#' + window.mc4wp_forms_config.submitted_form.element_id;
|
1558 |
+
var boxes = Boxzilla.boxes;
|
1559 |
+
|
1560 |
+
for (var boxId in boxes) {
|
1561 |
+
if (!boxes.hasOwnProperty(boxId)) {
|
1562 |
+
continue;
|
1563 |
+
}
|
1564 |
+
|
1565 |
+
var box = boxes[boxId];
|
1566 |
+
|
1567 |
+
if (box.element.querySelector(selector)) {
|
1568 |
+
box.show();
|
1569 |
+
return;
|
1570 |
+
}
|
1571 |
+
}
|
1572 |
+
} // print message when test mode is enabled
|
1573 |
+
|
1574 |
+
|
1575 |
+
var isLoggedIn = document.body.className.indexOf('logged-in') > -1;
|
1576 |
+
|
1577 |
+
if (isLoggedIn && options.testMode) {
|
1578 |
+
console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\'re done testing.');
|
1579 |
+
} // init boxzilla
|
1580 |
+
|
1581 |
+
|
1582 |
+
Boxzilla.init(); // on window.load, create DOM elements for boxes
|
1583 |
+
|
1584 |
+
window.addEventListener('load', createBoxesFromConfig);
|
1585 |
+
})();
|
1586 |
+
|
1587 |
+
},{"boxzilla":4}]},{},[8]);
|
1588 |
; })();
|
assets/js/script.min.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
!function(){var l=void 0;!function r(s,l,a){function c(e,t){if(!l[e]){if(!s[e]){var i=!1;if(!t&&i)return i(e,!0);if(d)return d(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var o=l[e]={exports:{}};s[e][0].call(o.exports,function(t){return c(s[e][1][t]||t)},o,o.exports,r,s,l,a)}return l[e].exports}for(var d=!1,t=0;t<a.length;t++)c(a[t]);return c}({1:[function(t,e,i){"use strict";function d(t){return(d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){var s=t("boxzilla"),l=window.boxzilla_options;function a(t){if(!window.location.hash||0===window.location.hash.length)return!1;var e=window.location.hash.substring(1);return!!/^[a-zA-Z\-\_0-9]+$/.test(e)&&(e===t.element.id||!!t.element.querySelector("#"+e))}window.Boxzilla=s;var c=-1<document.body.className.indexOf("logged-in");c&&l.testMode&&console.log("Boxzilla: Test mode is enabled. Please disable test mode if you're done testing."),s.init(),window.addEventListener("load",function(){if(!l.inited){for(var t in l.boxes){var e=l.boxes[t];e.testMode=c&&l.testMode;var i=document.getElementById("boxzilla-box-"+e.id+"-content");if(i){e.content=i;var n=s.create(e.id,e);n.element.className=n.element.className+" boxzilla-"+e.post.slug,o=n.element,(r=e.css).background_color&&(o.style.background=r.background_color),r.color&&(o.style.color=r.color),r.border_color&&(o.style.borderColor=r.border_color),r.border_width&&(o.style.borderWidth=parseInt(r.border_width)+"px"),r.border_style&&(o.style.borderStyle=r.border_style),r.width&&(o.style.maxWidth=parseInt(r.width)+"px"),n.element.firstChild.firstChild.className+=" first-child",n.element.firstChild.lastChild.className+=" last-child",n.fits()&&a(n)&&n.show()}}var o,r;l.inited=!0,s.trigger("done"),function(){if("object"===d(window.mc4wp_forms_config)&&window.mc4wp_forms_config.submitted_form){var t="#"+window.mc4wp_forms_config.submitted_form.element_id,e=s.boxes;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];if(n.element.querySelector(t))return n.show()}}}()}})}()},{boxzilla:5}],2:[function(t,s,e){(function(){"use strict";function t(){}var e=t.prototype,i=this,n=i.EventEmitter;function r(t,e){for(var i=t.length;i--;)if(t[i].listener===e)return i;return-1}function o(t){return function(){return this[t].apply(this,arguments)}}e.getListeners=function(t){var e,i,n=this._getEvents();if(t instanceof RegExp)for(i in e={},n)n.hasOwnProperty(i)&&t.test(i)&&(e[i]=n[i]);else e=n[t]||(n[t]=[]);return e},e.flattenListeners=function(t){var e,i=[];for(e=0;e<t.length;e+=1)i.push(t[e].listener);return i},e.getListenersAsObject=function(t){var e,i=this.getListeners(t);return i instanceof Array&&((e={})[t]=i),e||i},e.addListener=function(t,e){var i,n=this.getListenersAsObject(t),o="object"==typeof e;for(i in n)n.hasOwnProperty(i)&&-1===r(n[i],e)&&n[i].push(o?e:{listener:e,once:!1});return this},e.on=o("addListener"),e.addOnceListener=function(t,e){return this.addListener(t,{listener:e,once:!0})},e.once=o("addOnceListener"),e.defineEvent=function(t){return this.getListeners(t),this},e.defineEvents=function(t){for(var e=0;e<t.length;e+=1)this.defineEvent(t[e]);return this},e.removeListener=function(t,e){var i,n,o=this.getListenersAsObject(t);for(n in o)o.hasOwnProperty(n)&&-1!==(i=r(o[n],e))&&o[n].splice(i,1);return this},e.off=o("removeListener"),e.addListeners=function(t,e){return this.manipulateListeners(!1,t,e)},e.removeListeners=function(t,e){return this.manipulateListeners(!0,t,e)},e.manipulateListeners=function(t,e,i){var n,o,r=t?this.removeListener:this.addListener,s=t?this.removeListeners:this.addListeners;if("object"!=typeof e||e instanceof RegExp)for(n=i.length;n--;)r.call(this,e,i[n]);else for(n in e)e.hasOwnProperty(n)&&(o=e[n])&&("function"==typeof o?r.call(this,n,o):s.call(this,n,o));return this},e.removeEvent=function(t){var e,i=typeof t,n=this._getEvents();if("string"===i)delete n[t];else if(t instanceof RegExp)for(e in n)n.hasOwnProperty(e)&&t.test(e)&&delete n[e];else delete this._events;return this},e.removeAllListeners=o("removeEvent"),e.emitEvent=function(t,e){var i,n,o,r,s=this.getListenersAsObject(t);for(r in s)if(s.hasOwnProperty(r))for(o=(i=s[r].slice(0)).length;o--;)!0===(n=i[o]).once&&this.removeListener(t,n.listener),n.listener.apply(this,e||[])===this._getOnceReturnValue()&&this.removeListener(t,n.listener);return this},e.trigger=o("emitEvent"),e.emit=function(t){var e=Array.prototype.slice.call(arguments,1);return this.emitEvent(t,e)},e.setOnceReturnValue=function(t){return this._onceReturnValue=t,this},e._getOnceReturnValue=function(){return!this.hasOwnProperty("_onceReturnValue")||this._onceReturnValue},e._getEvents=function(){return this._events||(this._events={})},t.noConflict=function(){return i.EventEmitter=n,t},"function"==typeof l&&l.amd?l(function(){return t}):"object"==typeof s&&s.exports?s.exports=t:i.EventEmitter=t}).call(this)},{}],3:[function(t,e,i){"use strict";var o=320;function c(t,e){for(var i in e)t.style[i]=e[i]}function d(c,d,h){var f=+new Date,t=window.getComputedStyle(c),u={},g={};for(var e in d){d[e]=parseFloat(d[e]);var i=d[e],n=parseFloat(t[e]);n!=i?(g[e]=(i-n)/o,u[e]=n):delete d[e]}!function t(){var e,i,n,o,r=+new Date-f,s=!0;for(var l in d){e=g[l],i=d[l],n=e*r,o=u[l]+n,0<e&&i<=o||e<0&&o<=i?o=i:s=!1,u[l]=o;var a="opacity"!==l?"px":"";c.style[l]=o+a}f=+new Date,s?h&&h():window.requestAnimationFrame&&requestAnimationFrame(t)||setTimeout(t,32)}()}e.exports={toggle:function(t,e,i){var n,o,r="none"!=t.style.display||0<t.offsetLeft,s=t.cloneNode(!0),l=function(){t.removeAttribute("data-animated"),t.setAttribute("style",s.getAttribute("style")),t.style.display=r?"none":"",i&&i()};if(t.setAttribute("data-animated","true"),r||(t.style.display=""),"slide"===e){if(n=function(t,e){for(var i={},n=0;n<t.length;n++)i[t[n]]=e;return i}(["height","borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],0),o={},!r){if(o=function(t,e){for(var i={},n=0;n<t.length;n++)i[t[n]]=e[t[n]];return i}(["height","borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],window.getComputedStyle(t)),!isFinite(o.height)){var a=t.getBoundingClientRect();o.height=a.height}c(t,n)}t.style.overflowY="hidden",d(t,r?n:o,l)}else n={opacity:0},o={opacity:1},r||c(t,n),d(t,r?n:o,l)},animate:d,animated:function(t){return!!t.getAttribute("data-animated")}}},{}],4:[function(t,e,i){"use strict";var n,o={animation:"fade",rehide:!1,content:"",cookie:null,icon:"×",screenWidthCondition:null,position:"center",testMode:!1,trigger:!1,closable:!0},r=t("./animator.js");var s=function(t,e){this.id=t,this.config=function(t,e){var i={};for(var n in t)i[n]=t[n];for(var n in e)i[n]=e[n];return i}(o,e),this.overlay=document.getElementById("boxzilla-overlay"),this.visible=!1,this.dismissed=!1,this.triggered=!1,this.triggerHeight=this.calculateTriggerHeight(),this.cookieSet=this.isCookieSet(),this.element=null,this.contentElement=null,this.closeIcon=null,this.dom(),this.events()};s.prototype.events=function(){var e=this;this.closeIcon&&this.closeIcon.addEventListener("click",this.dismiss.bind(this)),this.element.addEventListener("click",function(t){"A"===t.target.tagName&&n.trigger("box.interactions.link",[e,t.target])},!1),this.element.addEventListener("submit",function(t){e.setCookie(),n.trigger("box.interactions.form",[e,t.target])},!1)},s.prototype.dom=function(){var t=document.createElement("div");t.className="boxzilla-container boxzilla-"+this.config.position+"-container";var e,i=document.createElement("div");if(i.setAttribute("id","boxzilla-"+this.id),i.className="boxzilla boxzilla-"+this.id+" boxzilla-"+this.config.position,i.style.display="none",t.appendChild(i),"string"==typeof this.config.content?(e=document.createElement("div")).innerHTML=this.config.content:(e=this.config.content).style.display="",e.className="boxzilla-content",i.appendChild(e),this.config.closable&&this.config.icon){var n=document.createElement("span");n.className="boxzilla-close-icon",n.innerHTML=this.config.icon,i.appendChild(n),this.closeIcon=n}document.body.appendChild(t),this.contentElement=e,this.element=i},s.prototype.setCustomBoxStyling=function(){var t=this.element.style.display;this.element.style.display="",this.element.style.overflowY="auto",this.element.style.maxHeight="none";var e=window.innerHeight,i=this.element.clientHeight;if(e<i&&(this.element.style.maxHeight=e+"px",this.element.style.overflowY="scroll"),"center"===this.config.position){var n=(e-i)/2;n=0<=n?n:0,this.element.style.marginTop=n+"px"}this.element.style.display=t},s.prototype.toggle=function(t){return void 0===t&&(t=!this.visible),t!==this.visible&&(!r.animated(this.element)&&(!(!t&&!this.config.closable)&&(this.visible=t,this.setCustomBoxStyling(),n.trigger("box."+(t?"show":"hide"),[this]),"center"===this.config.position&&(this.overlay.classList.toggle("boxzilla-"+this.id+"-overlay"),r.toggle(this.overlay,"fade")),r.toggle(this.element,this.config.animation,function(){this.visible||(this.contentElement.innerHTML=this.contentElement.innerHTML)}.bind(this)),!0)))},s.prototype.show=function(){return this.toggle(!0)},s.prototype.hide=function(){return this.toggle(!1)},s.prototype.calculateTriggerHeight=function(){var t,e,i=0;if(this.config.trigger)if("element"===this.config.trigger.method){var n=document.body.querySelector(this.config.trigger.value);if(n)i=n.getBoundingClientRect().top}else"percentage"===this.config.trigger.method&&(i=this.config.trigger.value/100*(t=document.body,e=document.documentElement,Math.max(t.scrollHeight,t.offsetHeight,e.clientHeight,e.scrollHeight,e.offsetHeight)));return i},s.prototype.fits=function(){if(!this.config.screenWidthCondition||!this.config.screenWidthCondition.value)return!0;switch(this.config.screenWidthCondition.condition){case"larger":return window.innerWidth>this.config.screenWidthCondition.value;case"smaller":return window.innerWidth<this.config.screenWidthCondition.value}return!0},s.prototype.onResize=function(){this.triggerHeight=this.calculateTriggerHeight(),this.setCustomBoxStyling()},s.prototype.mayAutoShow=function(){return!this.dismissed&&(!!this.fits()&&(!!this.config.trigger&&!this.cookieSet))},s.prototype.mayRehide=function(){return this.config.rehide&&this.triggered},s.prototype.isCookieSet=function(){return!(this.config.testMode||!this.config.trigger)&&(!(!this.config.cookie||!this.config.cookie.triggered&&!this.config.cookie.dismissed)&&"true"===document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*boxzilla_box_"+this.id+"\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1"))},s.prototype.setCookie=function(t){var e=new Date;e.setHours(e.getHours()+t),document.cookie="boxzilla_box_"+this.id+"=true; expires="+e.toUTCString()+"; path=/"},s.prototype.trigger=function(){this.show()&&(this.triggered=!0,this.config.cookie&&this.config.cookie.triggered&&this.setCookie(this.config.cookie.triggered))},s.prototype.dismiss=function(t){return t&&t.preventDefault(),!!this.visible&&(this.hide(),this.config.cookie&&this.config.cookie.dismissed&&this.setCookie(this.config.cookie.dismissed),this.dismissed=!0,n.trigger("box.dismiss",[this]),!0)},e.exports=function(t){return n=t,s}},{"./animator.js":3}],5:[function(i,t,e){"use strict";var n,o,r,s,l,a,c=i("wolfy87-eventemitter"),d=Object.create(c.prototype),h=i("./box.js")(d),f=i("./timer.js"),u=[],g=window;function m(n,o,r){var s,l;return o||(o=250),function(){var t=r||this,e=+new Date,i=arguments;s&&e<s+o?(clearTimeout(l),l=setTimeout(function(){s=e,n.apply(t,i)},o)):(s=e,n.apply(t,i))}}function p(t){27==t.keyCode&&d.dismiss()}function v(){L()||u.forEach(function(t){t.mayAutoShow()&&"pageviews"===t.config.trigger.method&&a>=t.config.trigger.value&&t.trigger()})}function b(){L()||u.forEach(function(t){t.mayAutoShow()&&("time_on_site"===t.config.trigger.method&&s.time>=t.config.trigger.value&&t.trigger(),"time_on_page"===t.config.trigger.method&&l.time>=t.config.trigger.value&&t.trigger())})}function y(){var e=g.hasOwnProperty("pageYOffset")?g.pageYOffset:g.scrollTop;e+=.9*window.innerHeight,u.forEach(function(t){if(t.mayAutoShow()&&!(t.triggerHeight<=0)){if(e>t.triggerHeight){if(L())return;t.trigger()}t.mayRehide()&&e<t.triggerHeight-5&&t.hide()}})}function w(){u.forEach(function(t){t.onResize()})}function x(t){var i=t.offsetX,n=t.offsetY;u.forEach(function(t){var e=t.element.getBoundingClientRect();(i<e.left-40||i>e.right+40||n<e.top-40||n>e.bottom+40)&&t.dismiss()})}function E(){r||L()||(u.forEach(function(t){t.mayAutoShow()&&"exit_intent"===t.config.trigger.method&&t.trigger()}),r=!0)}function z(t){t.clientY<=0&&(o=window.setTimeout(E,400))}function L(){for(var t=0;t<u.length;t++){if(u[t].visible)return!0}return!1}function _(){o&&(window.clearInterval(o),o=null)}function C(t){for(var e=t.target||t.srcElement,i=0;i<=3&&(e&&"A"!==e.tagName);i++)e=e.parentElement;if(e&&"A"===e.tagName&&e.getAttribute("href")&&0===e.getAttribute("href").toLowerCase().indexOf("#boxzilla-")){var n=e.getAttribute("href").toLowerCase().substring("#boxzilla-".length);d.toggle(n)}}var k=function(){try{var t=sessionStorage.getItem("boxzilla_timer");t&&(s.time=t)}catch(t){}s.start(),l.start()},S=function(){sessionStorage.setItem("boxzilla_timer",s.time),s.stop(),l.stop()};d.init=function(){document.body.addEventListener("click",C,!0);try{a=sessionStorage.getItem("boxzilla_pageviews")||0}catch(t){a=0}s=new f(0),l=new f(0);var t=i("./styles.js"),e=document.createElement("style");e.setAttribute("type","text/css"),e.innerHTML=t,document.head.appendChild(e),(n=document.createElement("div")).style.display="none",n.id="boxzilla-overlay",document.body.appendChild(n),g.addEventListener("touchstart",m(y),!0),g.addEventListener("scroll",m(y),!0),window.addEventListener("resize",m(w)),window.addEventListener("load",w),n.addEventListener("click",x),window.setInterval(b,1e3),window.setTimeout(v,1e3),document.documentElement.addEventListener("mouseleave",z),document.documentElement.addEventListener("mouseenter",_),document.addEventListener("keyup",p),k(),window.addEventListener("focus",k),window.addEventListener("beforeunload",function(){S(),sessionStorage.setItem("boxzilla_pageviews",++a)}),window.addEventListener("blur",S),d.trigger("ready")},d.create=function(t,e){void 0!==e.minimumScreenWidth&&(e.screenWidthCondition={condition:"larger",value:e.minimumScreenWidth});var i=new h(t,e);return u.push(i),i},d.get=function(t){for(var e=0;e<u.length;e++){var i=u[e];if(i.id==t)return i}throw new Error("No box exists with ID "+t)},d.dismiss=function(t){void 0===t?u.forEach(function(t){t.dismiss()}):d.get(t).dismiss()},d.hide=function(t){void 0===t?u.forEach(function(t){t.hide()}):d.get(t).hide()},d.show=function(t){void 0===t?u.forEach(function(t){t.show()}):d.get(t).show()},d.toggle=function(t){void 0===t?u.forEach(function(t){t.toggle()}):d.get(t).toggle()},d.boxes=u,window.Boxzilla=d,void 0!==t&&t.exports&&(t.exports=d)},{"./box.js":4,"./styles.js":6,"./timer.js":7,"wolfy87-eventemitter":2}],6:[function(t,e,i){"use strict";e.exports="#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}"},{}],7:[function(t,e,i){"use strict";var n=function(t){this.time=t,this.interval=0};n.prototype.tick=function(){this.time++},n.prototype.start=function(){this.interval||(this.interval=window.setInterval(this.tick.bind(this),1e3))},n.prototype.stop=function(){this.interval&&(window.clearInterval(this.interval),this.interval=0)},e.exports=n},{}]},{},[1])}();
|
2 |
//# sourceMappingURL=script.min.js.map
|
1 |
+
!function(){var l=void 0;!function r(s,l,c){function a(e,t){if(!l[e]){if(!s[e]){var i=!1;if(!t&&i)return i(e,!0);if(d)return d(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var o=l[e]={exports:{}};s[e][0].call(o.exports,function(t){return a(s[e][1][t]||t)},o,o.exports,r,s,l,c)}return l[e].exports}for(var d=!1,t=0;t<c.length;t++)a(c[t]);return a}({1:[function(t,s,e){!function(t){"use strict";function e(){}var i=e.prototype,n=t.EventEmitter;function r(t,e){for(var i=t.length;i--;)if(t[i].listener===e)return i;return-1}function o(t){return function(){return this[t].apply(this,arguments)}}i.getListeners=function(t){var e,i,n=this._getEvents();if(t instanceof RegExp)for(i in e={},n)n.hasOwnProperty(i)&&t.test(i)&&(e[i]=n[i]);else e=n[t]||(n[t]=[]);return e},i.flattenListeners=function(t){var e,i=[];for(e=0;e<t.length;e+=1)i.push(t[e].listener);return i},i.getListenersAsObject=function(t){var e,i=this.getListeners(t);return i instanceof Array&&((e={})[t]=i),e||i},i.addListener=function(t,e){if(!function t(e){return"function"==typeof e||e instanceof RegExp||!(!e||"object"!=typeof e)&&t(e.listener)}(e))throw new TypeError("listener must be a function");var i,n=this.getListenersAsObject(t),o="object"==typeof e;for(i in n)n.hasOwnProperty(i)&&-1===r(n[i],e)&&n[i].push(o?e:{listener:e,once:!1});return this},i.on=o("addListener"),i.addOnceListener=function(t,e){return this.addListener(t,{listener:e,once:!0})},i.once=o("addOnceListener"),i.defineEvent=function(t){return this.getListeners(t),this},i.defineEvents=function(t){for(var e=0;e<t.length;e+=1)this.defineEvent(t[e]);return this},i.removeListener=function(t,e){var i,n,o=this.getListenersAsObject(t);for(n in o)o.hasOwnProperty(n)&&-1!==(i=r(o[n],e))&&o[n].splice(i,1);return this},i.off=o("removeListener"),i.addListeners=function(t,e){return this.manipulateListeners(!1,t,e)},i.removeListeners=function(t,e){return this.manipulateListeners(!0,t,e)},i.manipulateListeners=function(t,e,i){var n,o,r=t?this.removeListener:this.addListener,s=t?this.removeListeners:this.addListeners;if("object"!=typeof e||e instanceof RegExp)for(n=i.length;n--;)r.call(this,e,i[n]);else for(n in e)e.hasOwnProperty(n)&&(o=e[n])&&("function"==typeof o?r.call(this,n,o):s.call(this,n,o));return this},i.removeEvent=function(t){var e,i=typeof t,n=this._getEvents();if("string"===i)delete n[t];else if(t instanceof RegExp)for(e in n)n.hasOwnProperty(e)&&t.test(e)&&delete n[e];else delete this._events;return this},i.removeAllListeners=o("removeEvent"),i.emitEvent=function(t,e){var i,n,o,r,s=this.getListenersAsObject(t);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].slice(0),o=0;o<i.length;o++)!0===(n=i[o]).once&&this.removeListener(t,n.listener),n.listener.apply(this,e||[])===this._getOnceReturnValue()&&this.removeListener(t,n.listener);return this},i.trigger=o("emitEvent"),i.emit=function(t){var e=Array.prototype.slice.call(arguments,1);return this.emitEvent(t,e)},i.setOnceReturnValue=function(t){return this._onceReturnValue=t,this},i._getOnceReturnValue=function(){return!this.hasOwnProperty("_onceReturnValue")||this._onceReturnValue},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return t.EventEmitter=n,e},"function"==typeof l&&l.amd?l(function(){return e}):"object"==typeof s&&s.exports?s.exports=e:t.EventEmitter=e}("undefined"!=typeof window?window:this||{})},{}],2:[function(t,e,i){"use strict";var o=320;function a(t,e){for(var i in e)t.style[i]=e[i]}function d(a,d,u){var h=+new Date,t=window.getComputedStyle(a),f={},g={};for(var e in d){d[e]=parseFloat(d[e]);var i=d[e],n=parseFloat(t[e]);n!=i?(g[e]=(i-n)/o,f[e]=n):delete d[e]}!function t(){var e,i,n,o,r=+new Date-h,s=!0;for(var l in d){e=g[l],i=d[l],n=e*r,o=f[l]+n,0<e&&i<=o||e<0&&o<=i?o=i:s=!1,f[l]=o;var c="opacity"!==l?"px":"";a.style[l]=o+c}h=+new Date,s?u&&u():window.requestAnimationFrame&&requestAnimationFrame(t)||setTimeout(t,32)}()}e.exports={toggle:function(t,e,i){var n,o,r="none"!=t.style.display||0<t.offsetLeft,s=t.cloneNode(!0),l=function(){t.removeAttribute("data-animated"),t.setAttribute("style",s.getAttribute("style")),t.style.display=r?"none":"",i&&i()};if(t.setAttribute("data-animated","true"),r||(t.style.display=""),"slide"===e){if(n=function(t,e){for(var i={},n=0;n<t.length;n++)i[t[n]]=e;return i}(["height","borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],0),o={},!r){if(o=function(t,e){for(var i={},n=0;n<t.length;n++)i[t[n]]=e[t[n]];return i}(["height","borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],window.getComputedStyle(t)),!isFinite(o.height)){var c=t.getBoundingClientRect();o.height=c.height}a(t,n)}t.style.overflowY="hidden",d(t,r?n:o,l)}else n={opacity:0},o={opacity:1},r||a(t,n),d(t,r?n:o,l)},animate:d,animated:function(t){return!!t.getAttribute("data-animated")}}},{}],3:[function(t,e,i){"use strict";var n,o={animation:"fade",rehide:!1,content:"",cookie:null,icon:"×",screenWidthCondition:null,position:"center",testMode:!1,trigger:!1,closable:!0},r=t("./animator.js");var s=function(t,e){this.id=t,this.config=function(t,e){var i={};for(var n in t)i[n]=t[n];for(var n in e)i[n]=e[n];return i}(o,e),this.overlay=document.getElementById("boxzilla-overlay"),this.visible=!1,this.dismissed=!1,this.triggered=!1,this.triggerHeight=this.calculateTriggerHeight(),this.cookieSet=this.isCookieSet(),this.element=null,this.contentElement=null,this.closeIcon=null,this.dom(),this.events()};s.prototype.events=function(){var e=this;this.closeIcon&&this.closeIcon.addEventListener("click",this.dismiss.bind(this)),this.element.addEventListener("click",function(t){"A"===t.target.tagName&&n.trigger("box.interactions.link",[e,t.target])},!1),this.element.addEventListener("submit",function(t){e.setCookie(),n.trigger("box.interactions.form",[e,t.target])},!1)},s.prototype.dom=function(){var t=document.createElement("div");t.className="boxzilla-container boxzilla-"+this.config.position+"-container";var e,i=document.createElement("div");if(i.setAttribute("id","boxzilla-"+this.id),i.className="boxzilla boxzilla-"+this.id+" boxzilla-"+this.config.position,i.style.display="none",t.appendChild(i),"string"==typeof this.config.content?(e=document.createElement("div")).innerHTML=this.config.content:(e=this.config.content).style.display="",e.className="boxzilla-content",i.appendChild(e),this.config.closable&&this.config.icon){var n=document.createElement("span");n.className="boxzilla-close-icon",n.innerHTML=this.config.icon,i.appendChild(n),this.closeIcon=n}document.body.appendChild(t),this.contentElement=e,this.element=i},s.prototype.setCustomBoxStyling=function(){var t=this.element.style.display;this.element.style.display="",this.element.style.overflowY="auto",this.element.style.maxHeight="none";var e=window.innerHeight,i=this.element.clientHeight;if(e<i&&(this.element.style.maxHeight=e+"px",this.element.style.overflowY="scroll"),"center"===this.config.position){var n=(e-i)/2;n=0<=n?n:0,this.element.style.marginTop=n+"px"}this.element.style.display=t},s.prototype.toggle=function(t){return void 0===t&&(t=!this.visible),t!==this.visible&&(!r.animated(this.element)&&(!(!t&&!this.config.closable)&&(this.visible=t,this.setCustomBoxStyling(),n.trigger("box."+(t?"show":"hide"),[this]),"center"===this.config.position&&(this.overlay.classList.toggle("boxzilla-"+this.id+"-overlay"),r.toggle(this.overlay,"fade")),r.toggle(this.element,this.config.animation,function(){this.visible||(this.contentElement.innerHTML=this.contentElement.innerHTML)}.bind(this)),!0)))},s.prototype.show=function(){return this.toggle(!0)},s.prototype.hide=function(){return this.toggle(!1)},s.prototype.calculateTriggerHeight=function(){var t,e,i=0;if(this.config.trigger)if("element"===this.config.trigger.method){var n=document.body.querySelector(this.config.trigger.value);if(n)i=n.getBoundingClientRect().top}else"percentage"===this.config.trigger.method&&(i=this.config.trigger.value/100*(t=document.body,e=document.documentElement,Math.max(t.scrollHeight,t.offsetHeight,e.clientHeight,e.scrollHeight,e.offsetHeight)));return i},s.prototype.fits=function(){if(!this.config.screenWidthCondition||!this.config.screenWidthCondition.value)return!0;switch(this.config.screenWidthCondition.condition){case"larger":return window.innerWidth>this.config.screenWidthCondition.value;case"smaller":return window.innerWidth<this.config.screenWidthCondition.value}return!0},s.prototype.onResize=function(){this.triggerHeight=this.calculateTriggerHeight(),this.setCustomBoxStyling()},s.prototype.mayAutoShow=function(){return!this.dismissed&&(!!this.fits()&&(!!this.config.trigger&&!this.cookieSet))},s.prototype.mayRehide=function(){return this.config.rehide&&this.triggered},s.prototype.isCookieSet=function(){return!(this.config.testMode||!this.config.trigger)&&(!(!this.config.cookie||!this.config.cookie.triggered&&!this.config.cookie.dismissed)&&"true"===document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*boxzilla_box_"+this.id+"\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1"))},s.prototype.setCookie=function(t){var e=new Date;e.setHours(e.getHours()+t),document.cookie="boxzilla_box_"+this.id+"=true; expires="+e.toUTCString()+"; path=/"},s.prototype.trigger=function(){this.show()&&(this.triggered=!0,this.config.cookie&&this.config.cookie.triggered&&this.setCookie(this.config.cookie.triggered))},s.prototype.dismiss=function(t){return t&&t.preventDefault(),!!this.visible&&(this.hide(),this.config.cookie&&this.config.cookie.dismissed&&this.setCookie(this.config.cookie.dismissed),this.dismissed=!0,n.trigger("box.dismiss",[this]),!0)},e.exports=function(t){return n=t,s}},{"./animator.js":2}],4:[function(t,e,i){"use strict";var n,o,r,s,l=t("wolfy87-eventemitter"),c=t("./timer.js"),a=Object.create(l.prototype),d=t("./box.js")(a),u=[],h=window,f=!1,g=t("./styles.js"),m=t("./triggers/exit-intent.js");function p(n,o,r){var s,l;return o||(o=250),function(){var t=r||this,e=+new Date,i=arguments;s&&e<s+o?(clearTimeout(l),l=setTimeout(function(){s=e,n.apply(t,i)},o)):(s=e,n.apply(t,i))}}function v(t){27===t.keyCode&&a.dismiss()}function b(){z()||u.forEach(function(t){t.mayAutoShow()&&"pageviews"===t.config.trigger.method&&s>=t.config.trigger.value&&t.trigger()})}function w(){z()||u.forEach(function(t){t.mayAutoShow()&&("time_on_site"===t.config.trigger.method&&o.time>=t.config.trigger.value&&t.trigger(),"time_on_page"===t.config.trigger.method&&r.time>=t.config.trigger.value&&t.trigger())})}function y(){var e=h.hasOwnProperty("pageYOffset")?h.pageYOffset:h.scrollTop;e+=.9*window.innerHeight,u.forEach(function(t){if(t.mayAutoShow()&&!(t.triggerHeight<=0)){if(e>t.triggerHeight){if(z())return;t.trigger()}t.mayRehide()&&e<t.triggerHeight-5&&t.hide()}})}function x(){u.forEach(function(t){t.onResize()})}function E(t){var i=t.offsetX,n=t.offsetY;u.forEach(function(t){var e=t.element.getBoundingClientRect();(i<e.left-40||i>e.right+40||n<e.top-40||n>e.bottom+40)&&t.dismiss()})}function L(){z()||u.forEach(function(t){t.mayAutoShow()&&"exit_intent"===t.config.trigger.method&&t.trigger()})}function z(){return 0<u.filter(function(t){return t.visible}).length}function _(t){for(var e=t.target||t.srcElement,i=0;i<=3&&(e&&"A"!==e.tagName);i++)e=e.parentElement;if(e&&"A"===e.tagName&&e.getAttribute("href")&&0===e.getAttribute("href").toLowerCase().indexOf("#boxzilla-")){var n=e.getAttribute("href").toLowerCase().substring("#boxzilla-".length);a.toggle(n)}}var k=function(){try{var t=sessionStorage.getItem("boxzilla_timer");t&&(o.time=t)}catch(t){}o.start(),r.start()},C=function(){sessionStorage.setItem("boxzilla_timer",o.time),o.stop(),r.stop()};a.init=function(){if(!f){document.body.addEventListener("click",_,!0);try{s=sessionStorage.getItem("boxzilla_pageviews")||0}catch(t){s=0}o=new c(0),r=new c(0);var t=document.createElement("style");t.setAttribute("type","text/css"),t.innerHTML=g,document.head.appendChild(t),(n=document.createElement("div")).style.display="none",n.id="boxzilla-overlay",document.body.appendChild(n),new m(L),h.addEventListener("touchstart",p(y),!0),h.addEventListener("scroll",p(y),!0),window.addEventListener("resize",p(x)),window.addEventListener("load",x),n.addEventListener("click",E),window.setInterval(w,1e3),window.setTimeout(b,1e3),document.addEventListener("keyup",v),k(),window.addEventListener("focus",k),window.addEventListener("beforeunload",function(){C(),sessionStorage.setItem("boxzilla_pageviews",++s)}),window.addEventListener("blur",C),a.trigger("ready"),f=!0}},a.create=function(t,e){void 0!==e.minimumScreenWidth&&(e.screenWidthCondition={condition:"larger",value:e.minimumScreenWidth});var i=new d(t,e);return u.push(i),i},a.get=function(t){for(var e=0;e<u.length;e++){var i=u[e];if(i.id==t)return i}throw new Error("No box exists with ID "+t)},a.dismiss=function(t){void 0===t?u.forEach(function(t){t.dismiss()}):a.get(t).dismiss()},a.hide=function(t){void 0===t?u.forEach(function(t){t.hide()}):a.get(t).hide()},a.show=function(t){void 0===t?u.forEach(function(t){t.show()}):a.get(t).show()},a.toggle=function(t){void 0===t?u.forEach(function(t){t.toggle()}):a.get(t).toggle()},a.boxes=u,window.Boxzilla=a,void 0!==e&&e.exports&&(e.exports=a)},{"./box.js":3,"./styles.js":5,"./timer.js":6,"./triggers/exit-intent.js":7,"wolfy87-eventemitter":1}],5:[function(t,e,i){"use strict";e.exports="#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}"},{}],6:[function(t,e,i){"use strict";var n=function(t){this.time=t,this.interval=0};n.prototype.tick=function(){this.time++},n.prototype.start=function(){this.interval||(this.interval=window.setInterval(this.tick.bind(this),1e3))},n.prototype.stop=function(){this.interval&&(window.clearInterval(this.interval),this.interval=0)},e.exports=n},{}],7:[function(t,e,i){"use strict";e.exports=function(t){var e=null,i={};function n(){document.documentElement.removeEventListener("mouseleave",s),document.documentElement.removeEventListener("mouseenter",r),document.documentElement.removeEventListener("click",o),window.removeEventListener("touchstart",l),window.removeEventListener("touchend",c),t()}function o(){null!==e&&(window.clearTimeout(e),e=null)}function r(t){o()}function s(t){o(),t.clientY<=0&&t.clientX<.8*window.innerWidth&&(e=window.setTimeout(n,400))}function l(t){o(),i={timestamp:performance.now(),scrollY:window.scrollY,windowHeight:window.innerHeight}}function c(t){o(),window.innerHeight>i.windowHeight||window.scrollY+20>=i.scrollY||300<performance.now()-i.timestamp||-1<["A","INPUT","BUTTON"].indexOf(t.target.tagName)||(e=window.setTimeout(n,800))}window.addEventListener("touchstart",l),window.addEventListener("touchend",c),document.documentElement.addEventListener("mouseenter",r),document.documentElement.addEventListener("mouseleave",s),document.documentElement.addEventListener("click",o)}},{}],8:[function(t,e,i){"use strict";function d(t){return(d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){var s=t("boxzilla"),l=window.boxzilla_options;function c(t){if(!window.location.hash||0===window.location.hash.length)return!1;var e=window.location.hash.substring(1);return!!/^[a-zA-Z\-\_0-9]+$/.test(e)&&(e===t.element.id||!!t.element.querySelector("#"+e))}window.Boxzilla=s;var a=-1<document.body.className.indexOf("logged-in");a&&l.testMode&&console.log("Boxzilla: Test mode is enabled. Please disable test mode if you're done testing."),s.init(),window.addEventListener("load",function(){if(!l.inited){for(var t in l.boxes){var e=l.boxes[t];e.testMode=a&&l.testMode;var i=document.getElementById("boxzilla-box-"+e.id+"-content");if(i){e.content=i;var n=s.create(e.id,e);n.element.className=n.element.className+" boxzilla-"+e.post.slug,o=n.element,(r=e.css).background_color&&(o.style.background=r.background_color),r.color&&(o.style.color=r.color),r.border_color&&(o.style.borderColor=r.border_color),r.border_width&&(o.style.borderWidth=parseInt(r.border_width)+"px"),r.border_style&&(o.style.borderStyle=r.border_style),r.width&&(o.style.maxWidth=parseInt(r.width)+"px"),n.element.firstChild.firstChild.className+=" first-child",n.element.firstChild.lastChild.className+=" last-child",n.fits()&&c(n)&&n.show()}}var o,r;l.inited=!0,s.trigger("done"),function(){if("object"===d(window.mc4wp_forms_config)&&window.mc4wp_forms_config.submitted_form){var t="#"+window.mc4wp_forms_config.submitted_form.element_id,e=s.boxes;for(var i in e)if(e.hasOwnProperty(i)){var n=e[i];if(n.element.querySelector(t))return n.show()}}}()}})}()},{boxzilla:4}]},{},[8])}();
|
2 |
//# sourceMappingURL=script.min.js.map
|
assets/js/script.min.js.map
CHANGED
@@ -1 +1 @@
|
|
1 |
-
{"version":3,"sources":["script.js"],"names":["define","undefined","r","e","n","t","o","i","f","c","u","a","Error","code","p","exports","call","length","1","require","module","_typeof","obj","Symbol","iterator","constructor","prototype","Boxzilla","options","window","boxzilla_options","locationHashRefersBox","box","location","hash","elementId","substring","test","element","id","querySelector","isLoggedIn","document","body","className","indexOf","testMode","console","log","init","addEventListener","inited","key","boxes","boxOpts","boxContentElement","getElementById","content","create","post","slug","styles","css","background_color","style","background","color","border_color","borderColor","border_width","borderWidth","parseInt","border_style","borderStyle","width","maxWidth","firstChild","lastChild","fits","show","trigger","mc4wp_forms_config","submitted_form","selector","element_id","boxId","hasOwnProperty","maybeOpenMailChimpForWordPressBox","boxzilla","2","EventEmitter","proto","this","originalGlobalValue","indexOfListener","listeners","listener","alias","name","apply","arguments","getListeners","evt","response","events","_getEvents","RegExp","flattenListeners","flatListeners","push","getListenersAsObject","Array","addListener","listenerIsWrapped","once","on","addOnceListener","defineEvent","defineEvents","evts","removeListener","index","splice","off","addListeners","manipulateListeners","removeListeners","remove","value","single","multiple","removeEvent","type","_events","removeAllListeners","emitEvent","args","listenersMap","slice","_getOnceReturnValue","emit","setOnceReturnValue","_onceReturnValue","noConflict","amd","3","duration","property","animate","targetStyles","fn","last","Date","initialStyles","getComputedStyle","currentStyles","propSteps","parseFloat","to","current","tick","step","increment","newValue","timeSinceLastTick","done","suffix","requestAnimationFrame","setTimeout","toggle","animation","callbackFn","hiddenStyles","visibleStyles","nowVisible","display","offsetLeft","clone","cloneNode","cleanup","removeAttribute","setAttribute","getAttribute","properties","newObject","initObjectProperties","object","copyObjectProperties","isFinite","height","clientRect","getBoundingClientRect","overflowY","opacity","animated","4","defaults","rehide","cookie","icon","screenWidthCondition","position","closable","Animator","Box","config","obj1","obj2","obj3","attrname","merge","overlay","visible","dismissed","triggered","triggerHeight","calculateTriggerHeight","cookieSet","isCookieSet","contentElement","closeIcon","dom","dismiss","bind","target","tagName","setCookie","wrapper","createElement","appendChild","innerHTML","setCustomBoxStyling","origDisplay","maxHeight","windowHeight","innerHeight","boxHeight","clientHeight","newTopMargin","marginTop","classList","hide","html","method","triggerElement","top","documentElement","Math","max","scrollHeight","offsetHeight","condition","innerWidth","onResize","mayAutoShow","mayRehide","replace","hours","expiryDate","setHours","getHours","toUTCString","preventDefault","_Boxzilla","./animator.js","5","exitIntentDelayTimer","exitIntentTriggered","siteTimer","pageTimer","pageViews","Object","Timer","scrollElement","throttle","threshhold","scope","deferTimer","context","now","clearTimeout","onKeyUp","keyCode","checkPageViewsCriteria","isAnyBoxVisible","forEach","checkTimeCriteria","time","checkHeightCriteria","scrollY","pageYOffset","scrollTop","recalculateHeights","onOverlayClick","x","offsetX","y","offsetY","rect","left","right","bottom","triggerExitIntent","onMouseLeave","clientY","onMouseEnter","clearInterval","onElementClick","el","srcElement","parentElement","toLowerCase","timers","sessionTime","sessionStorage","getItem","start","setItem","stop","styleElement","head","setInterval","opts","minimumScreenWidth","get","./box.js","./styles.js","./timer.js","wolfy87-eventemitter","6","7","interval"],"mappings":"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","file":"script.min.js","sourcesContent":["(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){\n\"use strict\";\n\nfunction _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); }\n\n(function () {\n 'use strict';\n\n var Boxzilla = require('boxzilla');\n\n var options = window.boxzilla_options; // expose Boxzilla object to window\n\n window.Boxzilla = Boxzilla; // helper function for setting CSS styles\n\n function css(element, styles) {\n if (styles.background_color) {\n element.style.background = styles.background_color;\n }\n\n if (styles.color) {\n element.style.color = styles.color;\n }\n\n if (styles.border_color) {\n element.style.borderColor = styles.border_color;\n }\n\n if (styles.border_width) {\n element.style.borderWidth = parseInt(styles.border_width) + \"px\";\n }\n\n if (styles.border_style) {\n element.style.borderStyle = styles.border_style;\n }\n\n if (styles.width) {\n element.style.maxWidth = parseInt(styles.width) + \"px\";\n }\n }\n\n function createBoxesFromConfig() {\n // failsafe against including script twice.\n if (options.inited) {\n return;\n } // create boxes from options\n\n\n for (var key in options.boxes) {\n // get opts\n var boxOpts = options.boxes[key];\n boxOpts.testMode = isLoggedIn && options.testMode; // find box content element, bail if not found\n\n var boxContentElement = document.getElementById('boxzilla-box-' + boxOpts.id + '-content');\n\n if (!boxContentElement) {\n continue;\n } // use element as content option\n\n\n boxOpts.content = boxContentElement; // create box\n\n var box = Boxzilla.create(boxOpts.id, boxOpts); // add box slug to box element as classname\n\n box.element.className = box.element.className + ' boxzilla-' + boxOpts.post.slug; // add custom css to box\n\n css(box.element, boxOpts.css);\n box.element.firstChild.firstChild.className += \" first-child\";\n box.element.firstChild.lastChild.className += \" last-child\"; // maybe show box right away\n\n if (box.fits() && locationHashRefersBox(box)) {\n box.show();\n }\n } // set flag to prevent initialising twice\n\n\n options.inited = true; // trigger \"done\" event.\n\n Boxzilla.trigger('done'); // maybe open box with MC4WP form in it\n\n maybeOpenMailChimpForWordPressBox();\n }\n\n function locationHashRefersBox(box) {\n if (!window.location.hash || 0 === window.location.hash.length) {\n return false;\n }\n\n var elementId = window.location.hash.substring(1); // only attempt on strings looking like an ID \n\n var regex = /^[a-zA-Z\\-\\_0-9]+$/;\n\n if (!regex.test(elementId)) {\n return false;\n }\n\n if (elementId === box.element.id) {\n return true;\n } else if (box.element.querySelector('#' + elementId)) {\n return true;\n }\n\n return false;\n }\n\n function maybeOpenMailChimpForWordPressBox() {\n if (_typeof(window.mc4wp_forms_config) !== \"object\" || !window.mc4wp_forms_config.submitted_form) {\n return;\n }\n\n var selector = '#' + window.mc4wp_forms_config.submitted_form.element_id;\n var boxes = Boxzilla.boxes;\n\n for (var boxId in boxes) {\n if (!boxes.hasOwnProperty(boxId)) {\n continue;\n }\n\n var box = boxes[boxId];\n\n if (box.element.querySelector(selector)) {\n box.show();\n return;\n }\n }\n } // print message when test mode is enabled\n\n\n var isLoggedIn = document.body.className.indexOf('logged-in') > -1;\n\n if (isLoggedIn && options.testMode) {\n console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\\'re done testing.');\n } // init boxzilla\n\n\n Boxzilla.init(); // on window.load, create DOM elements for boxes\n\n window.addEventListener('load', createBoxesFromConfig);\n})();\n\n},{\"boxzilla\":5}],2:[function(require,module,exports){\n/*!\n * EventEmitter v4.2.11 - git.io/ee\n * Unlicense - http://unlicense.org/\n * Oliver Caldwell - http://oli.me.uk/\n * @preserve\n */\n\n;(function () {\n 'use strict';\n\n /**\n * Class for managing events.\n * Can be extended to provide event functionality in other classes.\n *\n * @class EventEmitter Manages event registering and emitting.\n */\n function EventEmitter() {}\n\n // Shortcuts to improve speed and size\n var proto = EventEmitter.prototype;\n var exports = this;\n var originalGlobalValue = exports.EventEmitter;\n\n /**\n * Finds the index of the listener for the event in its storage array.\n *\n * @param {Function[]} listeners Array of listeners to search through.\n * @param {Function} listener Method to look for.\n * @return {Number} Index of the specified listener, -1 if not found\n * @api private\n */\n function indexOfListener(listeners, listener) {\n var i = listeners.length;\n while (i--) {\n if (listeners[i].listener === listener) {\n return i;\n }\n }\n\n return -1;\n }\n\n /**\n * Alias a method while keeping the context correct, to allow for overwriting of target method.\n *\n * @param {String} name The name of the target method.\n * @return {Function} The aliased method\n * @api private\n */\n function alias(name) {\n return function aliasClosure() {\n return this[name].apply(this, arguments);\n };\n }\n\n /**\n * Returns the listener array for the specified event.\n * Will initialise the event object and listener arrays if required.\n * 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.\n * Each property in the object response is an array of listener functions.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Function[]|Object} All listener functions for the event.\n */\n proto.getListeners = function getListeners(evt) {\n var events = this._getEvents();\n var response;\n var key;\n\n // Return a concatenated array of all matching events if\n // the selector is a regular expression.\n if (evt instanceof RegExp) {\n response = {};\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n response[key] = events[key];\n }\n }\n }\n else {\n response = events[evt] || (events[evt] = []);\n }\n\n return response;\n };\n\n /**\n * Takes a list of listener objects and flattens it into a list of listener functions.\n *\n * @param {Object[]} listeners Raw listener objects.\n * @return {Function[]} Just the listener functions.\n */\n proto.flattenListeners = function flattenListeners(listeners) {\n var flatListeners = [];\n var i;\n\n for (i = 0; i < listeners.length; i += 1) {\n flatListeners.push(listeners[i].listener);\n }\n\n return flatListeners;\n };\n\n /**\n * 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.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Object} All listener functions for an event in an object.\n */\n proto.getListenersAsObject = function getListenersAsObject(evt) {\n var listeners = this.getListeners(evt);\n var response;\n\n if (listeners instanceof Array) {\n response = {};\n response[evt] = listeners;\n }\n\n return response || listeners;\n };\n\n /**\n * Adds a listener function to the specified event.\n * The listener will not be added if it is a duplicate.\n * If the listener returns true then it will be removed after it is called.\n * If you pass a regular expression as the event name then the listener will be added to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListener = function addListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var listenerIsWrapped = typeof listener === 'object';\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {\n listeners[key].push(listenerIsWrapped ? listener : {\n listener: listener,\n once: false\n });\n }\n }\n\n return this;\n };\n\n /**\n * Alias of addListener\n */\n proto.on = alias('addListener');\n\n /**\n * Semi-alias of addListener. It will add a listener that will be\n * automatically removed after its first execution.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addOnceListener = function addOnceListener(evt, listener) {\n return this.addListener(evt, {\n listener: listener,\n once: true\n });\n };\n\n /**\n * Alias of addOnceListener.\n */\n proto.once = alias('addOnceListener');\n\n /**\n * 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.\n * You need to tell it what event names should be matched by a regex.\n *\n * @param {String} evt Name of the event to create.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvent = function defineEvent(evt) {\n this.getListeners(evt);\n return this;\n };\n\n /**\n * Uses defineEvent to define multiple events.\n *\n * @param {String[]} evts An array of event names to define.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvents = function defineEvents(evts) {\n for (var i = 0; i < evts.length; i += 1) {\n this.defineEvent(evts[i]);\n }\n return this;\n };\n\n /**\n * Removes a listener function from the specified event.\n * When passed a regular expression as the event name, it will remove the listener from all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to remove the listener from.\n * @param {Function} listener Method to remove from the event.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListener = function removeListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var index;\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key)) {\n index = indexOfListener(listeners[key], listener);\n\n if (index !== -1) {\n listeners[key].splice(index, 1);\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of removeListener\n */\n proto.off = alias('removeListener');\n\n /**\n * Adds listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second 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.\n * You can also pass it a regular expression to add the array of listeners to all events that match it.\n * Yeah, this function does quite a bit. That's probably a bad thing.\n *\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to add.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListeners = function addListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(false, evt, listeners);\n };\n\n /**\n * Removes listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be removed.\n * You can also pass it a regular expression to remove the listeners from all events that match it.\n *\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListeners = function removeListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(true, evt, listeners);\n };\n\n /**\n * 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.\n * The first argument will determine if the listeners are removed (true) or added (false).\n * 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.\n * You can also pass it an event name and an array of listeners to be added/removed.\n * You can also pass it a regular expression to manipulate the listeners of all events that match it.\n *\n * @param {Boolean} remove True if you want to remove listeners, false if you want to add.\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to add/remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {\n var i;\n var value;\n var single = remove ? this.removeListener : this.addListener;\n var multiple = remove ? this.removeListeners : this.addListeners;\n\n // If evt is an object then pass each of its properties to this method\n if (typeof evt === 'object' && !(evt instanceof RegExp)) {\n for (i in evt) {\n if (evt.hasOwnProperty(i) && (value = evt[i])) {\n // Pass the single listener straight through to the singular method\n if (typeof value === 'function') {\n single.call(this, i, value);\n }\n else {\n // Otherwise pass back to the multiple function\n multiple.call(this, i, value);\n }\n }\n }\n }\n else {\n // So evt must be a string\n // And listeners must be an array of listeners\n // Loop over it and pass each one to the multiple method\n i = listeners.length;\n while (i--) {\n single.call(this, evt, listeners[i]);\n }\n }\n\n return this;\n };\n\n /**\n * Removes all listeners from a specified event.\n * If you do not specify an event then all listeners will be removed.\n * That means every event will be emptied.\n * You can also pass a regex to remove all events that match it.\n *\n * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeEvent = function removeEvent(evt) {\n var type = typeof evt;\n var events = this._getEvents();\n var key;\n\n // Remove different things depending on the state of evt\n if (type === 'string') {\n // Remove all listeners for the specified event\n delete events[evt];\n }\n else if (evt instanceof RegExp) {\n // Remove all events matching the regex.\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n delete events[key];\n }\n }\n }\n else {\n // Remove all listeners in all events\n delete this._events;\n }\n\n return this;\n };\n\n /**\n * Alias of removeEvent.\n *\n * Added to mirror the node API.\n */\n proto.removeAllListeners = alias('removeEvent');\n\n /**\n * Emits an event of your choice.\n * When emitted, every listener attached to that event will be executed.\n * If you pass the optional argument array then those arguments will be passed to every listener upon execution.\n * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.\n * So they will not arrive within the array on the other side, they will be separate.\n * You can also pass a regular expression to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {Array} [args] Optional array of arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emitEvent = function emitEvent(evt, args) {\n var listenersMap = this.getListenersAsObject(evt);\n var listeners;\n var listener;\n var i;\n var key;\n var response;\n\n for (key in listenersMap) {\n if (listenersMap.hasOwnProperty(key)) {\n listeners = listenersMap[key].slice(0);\n i = listeners.length;\n\n while (i--) {\n // If the listener returns true then it shall be removed from the event\n // The function is executed either with a basic call or an apply if there is an args array\n listener = listeners[i];\n\n if (listener.once === true) {\n this.removeListener(evt, listener.listener);\n }\n\n response = listener.listener.apply(this, args || []);\n\n if (response === this._getOnceReturnValue()) {\n this.removeListener(evt, listener.listener);\n }\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of emitEvent\n */\n proto.trigger = alias('emitEvent');\n\n /**\n * 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.\n * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {...*} Optional additional arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emit = function emit(evt) {\n var args = Array.prototype.slice.call(arguments, 1);\n return this.emitEvent(evt, args);\n };\n\n /**\n * Sets the current value to check against when executing listeners. If a\n * listeners return value matches the one set here then it will be removed\n * after execution. This value defaults to true.\n *\n * @param {*} value The new value to check for when executing listeners.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.setOnceReturnValue = function setOnceReturnValue(value) {\n this._onceReturnValue = value;\n return this;\n };\n\n /**\n * Fetches the current value to check against when executing listeners. If\n * the listeners return value matches this one then it should be removed\n * automatically. It will return true by default.\n *\n * @return {*|Boolean} The current value to check for or the default, true.\n * @api private\n */\n proto._getOnceReturnValue = function _getOnceReturnValue() {\n if (this.hasOwnProperty('_onceReturnValue')) {\n return this._onceReturnValue;\n }\n else {\n return true;\n }\n };\n\n /**\n * Fetches the events object and creates one if required.\n *\n * @return {Object} The events storage object.\n * @api private\n */\n proto._getEvents = function _getEvents() {\n return this._events || (this._events = {});\n };\n\n /**\n * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.\n *\n * @return {Function} Non conflicting EventEmitter class.\n */\n EventEmitter.noConflict = function noConflict() {\n exports.EventEmitter = originalGlobalValue;\n return EventEmitter;\n };\n\n // Expose the class either via AMD, CommonJS or the global object\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return EventEmitter;\n });\n }\n else if (typeof module === 'object' && module.exports){\n module.exports = EventEmitter;\n }\n else {\n exports.EventEmitter = EventEmitter;\n }\n}.call(this));\n\n},{}],3:[function(require,module,exports){\n\"use strict\";\n\nvar duration = 320;\n\nfunction css(element, styles) {\n for (var property in styles) {\n element.style[property] = styles[property];\n }\n}\n\nfunction initObjectProperties(properties, value) {\n var newObject = {};\n\n for (var i = 0; i < properties.length; i++) {\n newObject[properties[i]] = value;\n }\n\n return newObject;\n}\n\nfunction copyObjectProperties(properties, object) {\n var newObject = {};\n\n for (var i = 0; i < properties.length; i++) {\n newObject[properties[i]] = object[properties[i]];\n }\n\n return newObject;\n}\n/**\n * Checks if the given element is currently being animated.\n *\n * @param element\n * @returns {boolean}\n */\n\n\nfunction animated(element) {\n return !!element.getAttribute('data-animated');\n}\n/**\n * Toggles the element using the given animation.\n *\n * @param element\n * @param animation Either \"fade\" or \"slide\"\n */\n\n\nfunction toggle(element, animation, callbackFn) {\n var nowVisible = element.style.display != 'none' || element.offsetLeft > 0; // create clone for reference\n\n var clone = element.cloneNode(true);\n\n var cleanup = function cleanup() {\n element.removeAttribute('data-animated');\n element.setAttribute('style', clone.getAttribute('style'));\n element.style.display = nowVisible ? 'none' : '';\n\n if (callbackFn) {\n callbackFn();\n }\n }; // store attribute so everyone knows we're animating this element\n\n\n element.setAttribute('data-animated', \"true\"); // toggle element visiblity right away if we're making something visible\n\n if (!nowVisible) {\n element.style.display = '';\n }\n\n var hiddenStyles, visibleStyles; // animate properties\n\n if (animation === 'slide') {\n hiddenStyles = initObjectProperties([\"height\", \"borderTopWidth\", \"borderBottomWidth\", \"paddingTop\", \"paddingBottom\"], 0);\n visibleStyles = {};\n\n if (!nowVisible) {\n var computedStyles = window.getComputedStyle(element);\n 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.\n\n if (!isFinite(visibleStyles.height)) {\n var clientRect = element.getBoundingClientRect();\n visibleStyles.height = clientRect.height;\n }\n\n css(element, hiddenStyles);\n } // don't show a scrollbar during animation\n\n\n element.style.overflowY = 'hidden';\n animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);\n } else {\n hiddenStyles = {\n opacity: 0\n };\n visibleStyles = {\n opacity: 1\n };\n\n if (!nowVisible) {\n css(element, hiddenStyles);\n }\n\n animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);\n }\n}\n\nfunction animate(element, targetStyles, fn) {\n var last = +new Date();\n var initialStyles = window.getComputedStyle(element);\n var currentStyles = {};\n var propSteps = {};\n\n for (var property in targetStyles) {\n // make sure we have an object filled with floats\n targetStyles[property] = parseFloat(targetStyles[property]); // calculate step size & current value\n\n var to = targetStyles[property];\n var current = parseFloat(initialStyles[property]); // is there something to do?\n\n if (current == to) {\n delete targetStyles[property];\n continue;\n }\n\n propSteps[property] = (to - current) / duration; // points per second\n\n currentStyles[property] = current;\n }\n\n var tick = function tick() {\n var now = +new Date();\n var timeSinceLastTick = now - last;\n var done = true;\n var step, to, increment, newValue;\n\n for (var property in targetStyles) {\n step = propSteps[property];\n to = targetStyles[property];\n increment = step * timeSinceLastTick;\n newValue = currentStyles[property] + increment;\n\n if (step > 0 && newValue >= to || step < 0 && newValue <= to) {\n newValue = to;\n } else {\n done = false;\n } // store new value\n\n\n currentStyles[property] = newValue;\n var suffix = property !== \"opacity\" ? \"px\" : \"\";\n element.style[property] = newValue + suffix;\n }\n\n last = +new Date(); // keep going until we're done for all props\n\n if (!done) {\n window.requestAnimationFrame && requestAnimationFrame(tick) || setTimeout(tick, 32);\n } else {\n // call callback\n fn && fn();\n }\n };\n\n tick();\n}\n\nmodule.exports = {\n 'toggle': toggle,\n 'animate': animate,\n 'animated': animated\n};\n\n},{}],4:[function(require,module,exports){\n'use strict';\n\nvar defaults = {\n 'animation': 'fade',\n 'rehide': false,\n 'content': '',\n 'cookie': null,\n 'icon': '×',\n 'screenWidthCondition': null,\n 'position': 'center',\n 'testMode': false,\n 'trigger': false,\n 'closable': true\n},\n Boxzilla,\n Animator = require('./animator.js');\n/**\n* Merge 2 objects, values of the latter overwriting the former.\n*\n* @param obj1\n* @param obj2\n* @returns {*}\n*/\n\n\nfunction merge(obj1, obj2) {\n var obj3 = {};\n\n for (var attrname in obj1) {\n obj3[attrname] = obj1[attrname];\n }\n\n for (var attrname in obj2) {\n obj3[attrname] = obj2[attrname];\n }\n\n return obj3;\n}\n/**\n* Get the real height of entire document.\n* @returns {number}\n*/\n\n\nfunction getDocumentHeight() {\n var body = document.body,\n html = document.documentElement;\n var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);\n return height;\n} // Box Object\n\n\nvar Box = function Box(id, config) {\n this.id = id; // store config values\n\n this.config = merge(defaults, config); // store ref to overlay\n\n this.overlay = document.getElementById('boxzilla-overlay'); // state\n\n this.visible = false;\n this.dismissed = false;\n this.triggered = false;\n this.triggerHeight = this.calculateTriggerHeight();\n this.cookieSet = this.isCookieSet();\n this.element = null;\n this.contentElement = null;\n this.closeIcon = null; // create dom elements for this box\n\n this.dom(); // further initialise the box\n\n this.events();\n}; // initialise the box\n\n\nBox.prototype.events = function () {\n var box = this; // attach event to \"close\" icon inside box\n\n if (this.closeIcon) {\n this.closeIcon.addEventListener('click', this.dismiss.bind(this));\n }\n\n this.element.addEventListener('click', function (e) {\n if (e.target.tagName === 'A') {\n Boxzilla.trigger('box.interactions.link', [box, e.target]);\n }\n }, false);\n this.element.addEventListener('submit', function (e) {\n box.setCookie();\n Boxzilla.trigger('box.interactions.form', [box, e.target]);\n }, false);\n}; // generate dom elements for this box\n\n\nBox.prototype.dom = function () {\n var wrapper = document.createElement('div');\n wrapper.className = 'boxzilla-container boxzilla-' + this.config.position + '-container';\n var box = document.createElement('div');\n box.setAttribute('id', 'boxzilla-' + this.id);\n box.className = 'boxzilla boxzilla-' + this.id + ' boxzilla-' + this.config.position;\n box.style.display = 'none';\n wrapper.appendChild(box);\n var content;\n\n if (typeof this.config.content === \"string\") {\n content = document.createElement('div');\n content.innerHTML = this.config.content;\n } else {\n content = this.config.content; // make sure element is visible\n\n content.style.display = '';\n }\n\n content.className = 'boxzilla-content';\n box.appendChild(content);\n\n if (this.config.closable && this.config.icon) {\n var closeIcon = document.createElement('span');\n closeIcon.className = \"boxzilla-close-icon\";\n closeIcon.innerHTML = this.config.icon;\n box.appendChild(closeIcon);\n this.closeIcon = closeIcon;\n }\n\n document.body.appendChild(wrapper);\n this.contentElement = content;\n this.element = box;\n}; // set (calculate) custom box styling depending on box options\n\n\nBox.prototype.setCustomBoxStyling = function () {\n // reset element to its initial state\n var origDisplay = this.element.style.display;\n this.element.style.display = '';\n this.element.style.overflowY = 'auto';\n this.element.style.maxHeight = 'none'; // get new dimensions\n\n var windowHeight = window.innerHeight;\n var boxHeight = this.element.clientHeight; // add scrollbar to box and limit height\n\n if (boxHeight > windowHeight) {\n this.element.style.maxHeight = windowHeight + \"px\";\n this.element.style.overflowY = 'scroll';\n } // set new top margin for boxes which are centered\n\n\n if (this.config.position === 'center') {\n var newTopMargin = (windowHeight - boxHeight) / 2;\n newTopMargin = newTopMargin >= 0 ? newTopMargin : 0;\n this.element.style.marginTop = newTopMargin + \"px\";\n }\n\n this.element.style.display = origDisplay;\n}; // toggle visibility of the box\n\n\nBox.prototype.toggle = function (show) {\n // revert visibility if no explicit argument is given\n if (typeof show === \"undefined\") {\n show = !this.visible;\n } // is box already at desired visibility?\n\n\n if (show === this.visible) {\n return false;\n } // is box being animated?\n\n\n if (Animator.animated(this.element)) {\n return false;\n } // if box should be hidden but is not closable, bail.\n\n\n if (!show && !this.config.closable) {\n return false;\n } // set new visibility status\n\n\n this.visible = show; // calculate new styling rules\n\n this.setCustomBoxStyling(); // trigger event\n\n Boxzilla.trigger('box.' + (show ? 'show' : 'hide'), [this]); // show or hide box using selected animation\n\n if (this.config.position === 'center') {\n this.overlay.classList.toggle('boxzilla-' + this.id + '-overlay');\n Animator.toggle(this.overlay, \"fade\");\n }\n\n Animator.toggle(this.element, this.config.animation, function () {\n if (this.visible) {\n return;\n }\n\n this.contentElement.innerHTML = this.contentElement.innerHTML;\n }.bind(this));\n return true;\n}; // show the box\n\n\nBox.prototype.show = function () {\n return this.toggle(true);\n}; // hide the box\n\n\nBox.prototype.hide = function () {\n return this.toggle(false);\n}; // calculate trigger height\n\n\nBox.prototype.calculateTriggerHeight = function () {\n var triggerHeight = 0;\n\n if (this.config.trigger) {\n if (this.config.trigger.method === 'element') {\n var triggerElement = document.body.querySelector(this.config.trigger.value);\n\n if (triggerElement) {\n var offset = triggerElement.getBoundingClientRect();\n triggerHeight = offset.top;\n }\n } else if (this.config.trigger.method === 'percentage') {\n triggerHeight = this.config.trigger.value / 100 * getDocumentHeight();\n }\n }\n\n return triggerHeight;\n};\n\nBox.prototype.fits = function () {\n if (!this.config.screenWidthCondition || !this.config.screenWidthCondition.value) {\n return true;\n }\n\n switch (this.config.screenWidthCondition.condition) {\n case \"larger\":\n return window.innerWidth > this.config.screenWidthCondition.value;\n\n case \"smaller\":\n return window.innerWidth < this.config.screenWidthCondition.value;\n } // meh.. condition should be \"smaller\" or \"larger\", just return true.\n\n\n return true;\n};\n\nBox.prototype.onResize = function () {\n this.triggerHeight = this.calculateTriggerHeight();\n this.setCustomBoxStyling();\n}; // is this box enabled?\n\n\nBox.prototype.mayAutoShow = function () {\n if (this.dismissed) {\n return false;\n } // check if box fits on given minimum screen width\n\n\n if (!this.fits()) {\n return false;\n } // if trigger empty or error in calculating triggerHeight, return false\n\n\n if (!this.config.trigger) {\n return false;\n } // rely on cookie value (show if not set, don't show if set)\n\n\n return !this.cookieSet;\n};\n\nBox.prototype.mayRehide = function () {\n return this.config.rehide && this.triggered;\n};\n\nBox.prototype.isCookieSet = function () {\n // always show on test mode or when no auto-trigger is configured\n if (this.config.testMode || !this.config.trigger) {\n return false;\n } // if either cookie is null or trigger & dismiss are both falsey, don't bother checking.\n\n\n if (!this.config.cookie || !this.config.cookie.triggered && !this.config.cookie.dismissed) {\n return false;\n }\n\n var cookieSet = document.cookie.replace(new RegExp(\"(?:(?:^|.*;)\\\\s*\" + 'boxzilla_box_' + this.id + \"\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$\"), \"$1\") === \"true\";\n return cookieSet;\n}; // set cookie that disables automatically showing the box\n\n\nBox.prototype.setCookie = function (hours) {\n var expiryDate = new Date();\n expiryDate.setHours(expiryDate.getHours() + hours);\n document.cookie = 'boxzilla_box_' + this.id + '=true; expires=' + expiryDate.toUTCString() + '; path=/';\n};\n\nBox.prototype.trigger = function () {\n var shown = this.show();\n\n if (!shown) {\n return;\n }\n\n this.triggered = true;\n\n if (this.config.cookie && this.config.cookie.triggered) {\n this.setCookie(this.config.cookie.triggered);\n }\n};\n/**\n* Dismisses the box and optionally sets a cookie.\n*\n* @param e The event that triggered this dismissal.\n* @returns {boolean}\n*/\n\n\nBox.prototype.dismiss = function (e) {\n // prevent default action\n e && e.preventDefault(); // only dismiss box if it's currently open.\n\n if (!this.visible) {\n return false;\n } // hide box element\n\n\n this.hide(); // set cookie\n\n if (this.config.cookie && this.config.cookie.dismissed) {\n this.setCookie(this.config.cookie.dismissed);\n }\n\n this.dismissed = true;\n Boxzilla.trigger('box.dismiss', [this]);\n return true;\n};\n\nmodule.exports = function (_Boxzilla) {\n Boxzilla = _Boxzilla;\n return Box;\n};\n\n},{\"./animator.js\":3}],5:[function(require,module,exports){\n'use strict';\n\nvar EventEmitter = require('wolfy87-eventemitter'),\n Boxzilla = Object.create(EventEmitter.prototype),\n Box = require('./box.js')(Boxzilla),\n Timer = require('./timer.js'),\n boxes = [],\n overlay,\n scrollElement = window,\n exitIntentDelayTimer,\n exitIntentTriggered,\n siteTimer,\n pageTimer,\n pageViews;\n\nfunction throttle(fn, threshhold, scope) {\n threshhold || (threshhold = 250);\n var last, deferTimer;\n return function () {\n var context = scope || this;\n var now = +new Date(),\n args = arguments;\n\n if (last && now < last + threshhold) {\n // hold on to it\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function () {\n last = now;\n fn.apply(context, args);\n }, threshhold);\n } else {\n last = now;\n fn.apply(context, args);\n }\n };\n} // \"keyup\" listener\n\n\nfunction onKeyUp(e) {\n if (e.keyCode == 27) {\n Boxzilla.dismiss();\n }\n} // check \"pageviews\" criteria for each box\n\n\nfunction checkPageViewsCriteria() {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (!box.mayAutoShow()) {\n return;\n }\n\n if (box.config.trigger.method === 'pageviews' && pageViews >= box.config.trigger.value) {\n box.trigger();\n }\n });\n} // check time trigger criteria for each box\n\n\nfunction checkTimeCriteria() {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (!box.mayAutoShow()) {\n return;\n } // check \"time on site\" trigger\n\n\n if (box.config.trigger.method === 'time_on_site' && siteTimer.time >= box.config.trigger.value) {\n box.trigger();\n } // check \"time on page\" trigger\n\n\n if (box.config.trigger.method === 'time_on_page' && pageTimer.time >= box.config.trigger.value) {\n box.trigger();\n }\n });\n} // check triggerHeight criteria for all boxes\n\n\nfunction checkHeightCriteria() {\n var scrollY = scrollElement.hasOwnProperty('pageYOffset') ? scrollElement.pageYOffset : scrollElement.scrollTop;\n scrollY = scrollY + window.innerHeight * 0.9;\n boxes.forEach(function (box) {\n if (!box.mayAutoShow() || box.triggerHeight <= 0) {\n return;\n }\n\n if (scrollY > box.triggerHeight) {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n } // trigger box\n\n\n box.trigger();\n } // if box may auto-hide and scrollY is less than triggerHeight (with small margin of error), hide box\n\n\n if (box.mayRehide() && scrollY < box.triggerHeight - 5) {\n box.hide();\n }\n });\n} // recalculate heights and variables based on height\n\n\nfunction recalculateHeights() {\n boxes.forEach(function (box) {\n box.onResize();\n });\n}\n\nfunction onOverlayClick(e) {\n var x = e.offsetX;\n var y = e.offsetY; // calculate if click was less than 40px outside box to avoid closing it by accident\n\n boxes.forEach(function (box) {\n var rect = box.element.getBoundingClientRect();\n var margin = 40; // if click was not anywhere near box, dismiss it.\n\n if (x < rect.left - margin || x > rect.right + margin || y < rect.top - margin || y > rect.bottom + margin) {\n box.dismiss();\n }\n });\n}\n\nfunction triggerExitIntent() {\n // do nothing if already triggered OR another box is visible.\n if (exitIntentTriggered || isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (box.mayAutoShow() && box.config.trigger.method === 'exit_intent') {\n box.trigger();\n }\n });\n exitIntentTriggered = true;\n}\n\nfunction onMouseLeave(e) {\n var delay = 400; // did mouse leave at top of window?\n\n if (e.clientY <= 0) {\n exitIntentDelayTimer = window.setTimeout(triggerExitIntent, delay);\n }\n}\n\nfunction isAnyBoxVisible() {\n for (var i = 0; i < boxes.length; i++) {\n var box = boxes[i];\n\n if (box.visible) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction onMouseEnter() {\n if (exitIntentDelayTimer) {\n window.clearInterval(exitIntentDelayTimer);\n exitIntentDelayTimer = null;\n }\n}\n\nfunction onElementClick(e) {\n // find <a> element in up to 3 parent elements\n var el = e.target || e.srcElement;\n var depth = 3;\n\n for (var i = 0; i <= depth; i++) {\n if (!el || el.tagName === 'A') {\n break;\n }\n\n el = el.parentElement;\n }\n\n if (!el || el.tagName !== 'A' || !el.getAttribute('href')) {\n return;\n }\n\n if (el.getAttribute('href').toLowerCase().indexOf('#boxzilla-') === 0) {\n var boxId = el.getAttribute('href').toLowerCase().substring(\"#boxzilla-\".length);\n Boxzilla.toggle(boxId);\n }\n}\n\nvar timers = {\n start: function start() {\n try {\n var sessionTime = sessionStorage.getItem('boxzilla_timer');\n if (sessionTime) siteTimer.time = sessionTime;\n } catch (e) {}\n\n siteTimer.start();\n pageTimer.start();\n },\n stop: function stop() {\n sessionStorage.setItem('boxzilla_timer', siteTimer.time);\n siteTimer.stop();\n pageTimer.stop();\n }\n}; // initialise & add event listeners\n\nBoxzilla.init = function () {\n document.body.addEventListener('click', onElementClick, true);\n\n try {\n pageViews = sessionStorage.getItem('boxzilla_pageviews') || 0;\n } catch (e) {\n pageViews = 0;\n }\n\n siteTimer = new Timer(0);\n pageTimer = new Timer(0); // insert styles into DOM\n\n var styles = require('./styles.js');\n\n var styleElement = document.createElement('style');\n styleElement.setAttribute(\"type\", \"text/css\");\n styleElement.innerHTML = styles;\n document.head.appendChild(styleElement); // add overlay element to dom\n\n overlay = document.createElement('div');\n overlay.style.display = 'none';\n overlay.id = 'boxzilla-overlay';\n document.body.appendChild(overlay); // event binds\n\n scrollElement.addEventListener('touchstart', throttle(checkHeightCriteria), true);\n scrollElement.addEventListener('scroll', throttle(checkHeightCriteria), true);\n window.addEventListener('resize', throttle(recalculateHeights));\n window.addEventListener('load', recalculateHeights);\n overlay.addEventListener('click', onOverlayClick);\n window.setInterval(checkTimeCriteria, 1000);\n window.setTimeout(checkPageViewsCriteria, 1000);\n document.documentElement.addEventListener('mouseleave', onMouseLeave);\n document.documentElement.addEventListener('mouseenter', onMouseEnter);\n document.addEventListener('keyup', onKeyUp);\n timers.start();\n window.addEventListener('focus', timers.start);\n window.addEventListener('beforeunload', function () {\n timers.stop();\n sessionStorage.setItem('boxzilla_pageviews', ++pageViews);\n });\n window.addEventListener('blur', timers.stop);\n Boxzilla.trigger('ready');\n};\n/**\n * Create a new Box\n *\n * @param string id\n * @param object opts\n *\n * @returns Box\n */\n\n\nBoxzilla.create = function (id, opts) {\n // preserve backwards compat for minimumScreenWidth option\n if (typeof opts.minimumScreenWidth !== \"undefined\") {\n opts.screenWidthCondition = {\n condition: \"larger\",\n value: opts.minimumScreenWidth\n };\n }\n\n var box = new Box(id, opts);\n boxes.push(box);\n return box;\n};\n\nBoxzilla.get = function (id) {\n for (var i = 0; i < boxes.length; i++) {\n var box = boxes[i];\n\n if (box.id == id) {\n return box;\n }\n }\n\n throw new Error(\"No box exists with ID \" + id);\n}; // dismiss a single box (or all by omitting id param)\n\n\nBoxzilla.dismiss = function (id) {\n // if no id given, dismiss all current open boxes\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.dismiss();\n });\n } else {\n Boxzilla.get(id).dismiss();\n }\n};\n\nBoxzilla.hide = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.hide();\n });\n } else {\n Boxzilla.get(id).hide();\n }\n};\n\nBoxzilla.show = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.show();\n });\n } else {\n Boxzilla.get(id).show();\n }\n};\n\nBoxzilla.toggle = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.toggle();\n });\n } else {\n Boxzilla.get(id).toggle();\n }\n}; // expose each individual box.\n\n\nBoxzilla.boxes = boxes; // expose boxzilla object\n\nwindow.Boxzilla = Boxzilla;\n\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = Boxzilla;\n}\n\n},{\"./box.js\":4,\"./styles.js\":6,\"./timer.js\":7,\"wolfy87-eventemitter\":2}],6:[function(require,module,exports){\n\"use strict\";\n\nvar 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}\";\nmodule.exports = styles;\n\n},{}],7:[function(require,module,exports){\n'use strict';\n\nvar Timer = function Timer(start) {\n this.time = start;\n this.interval = 0;\n};\n\nTimer.prototype.tick = function () {\n this.time++;\n};\n\nTimer.prototype.start = function () {\n if (!this.interval) {\n this.interval = window.setInterval(this.tick.bind(this), 1000);\n }\n};\n\nTimer.prototype.stop = function () {\n if (this.interval) {\n window.clearInterval(this.interval);\n this.interval = 0;\n }\n};\n\nmodule.exports = Timer;\n\n},{}]},{},[1]);\n; })();"]}
|
1 |
+
{"version":3,"sources":["script.js"],"names":["define","undefined","r","e","n","t","o","i","f","c","u","a","Error","code","p","exports","call","length","1","require","module","EventEmitter","proto","prototype","originalGlobalValue","indexOfListener","listeners","listener","alias","name","this","apply","arguments","getListeners","evt","response","key","events","_getEvents","RegExp","hasOwnProperty","test","flattenListeners","flatListeners","push","getListenersAsObject","Array","addListener","isValidListener","TypeError","listenerIsWrapped","once","on","addOnceListener","defineEvent","defineEvents","evts","removeListener","index","splice","off","addListeners","manipulateListeners","removeListeners","remove","value","single","multiple","removeEvent","type","_events","removeAllListeners","emitEvent","args","listenersMap","slice","_getOnceReturnValue","trigger","emit","setOnceReturnValue","_onceReturnValue","noConflict","amd","window","2","duration","css","element","styles","property","style","animate","targetStyles","fn","last","Date","initialStyles","getComputedStyle","currentStyles","propSteps","parseFloat","to","current","tick","step","increment","newValue","timeSinceLastTick","done","suffix","requestAnimationFrame","setTimeout","toggle","animation","callbackFn","hiddenStyles","visibleStyles","nowVisible","display","offsetLeft","clone","cloneNode","cleanup","removeAttribute","setAttribute","getAttribute","properties","newObject","initObjectProperties","object","copyObjectProperties","isFinite","height","clientRect","getBoundingClientRect","overflowY","opacity","animated","3","Boxzilla","defaults","rehide","content","cookie","icon","screenWidthCondition","position","testMode","closable","Animator","Box","id","config","obj1","obj2","obj3","attrname","merge","overlay","document","getElementById","visible","dismissed","triggered","triggerHeight","calculateTriggerHeight","cookieSet","isCookieSet","contentElement","closeIcon","dom","box","addEventListener","dismiss","bind","target","tagName","setCookie","wrapper","createElement","className","appendChild","innerHTML","body","setCustomBoxStyling","origDisplay","maxHeight","windowHeight","innerHeight","boxHeight","clientHeight","newTopMargin","marginTop","show","classList","hide","html","method","triggerElement","querySelector","top","documentElement","Math","max","scrollHeight","offsetHeight","fits","condition","innerWidth","onResize","mayAutoShow","mayRehide","replace","hours","expiryDate","setHours","getHours","toUTCString","preventDefault","_Boxzilla","./animator.js","4","siteTimer","pageTimer","pageViews","Timer","Object","create","boxes","scrollElement","initialised","ExitIntent","throttle","threshhold","scope","deferTimer","context","now","clearTimeout","onKeyUp","keyCode","checkPageViewsCriteria","isAnyBoxVisible","forEach","checkTimeCriteria","time","checkHeightCriteria","scrollY","pageYOffset","scrollTop","recalculateHeights","onOverlayClick","x","offsetX","y","offsetY","rect","left","right","bottom","showBoxesWithExitIntentTrigger","filter","b","onElementClick","el","srcElement","parentElement","toLowerCase","indexOf","boxId","substring","timers","sessionTime","sessionStorage","getItem","start","setItem","stop","init","styleElement","head","setInterval","opts","minimumScreenWidth","get","./box.js","./styles.js","./timer.js","./triggers/exit-intent.js","wolfy87-eventemitter","5","6","interval","clearInterval","7","callback","timeout","touchStart","triggerCallback","removeEventListener","onMouseLeave","onMouseEnter","onTouchStart","onTouchEnd","clientY","clientX","timestamp","performance","8","_typeof","obj","Symbol","iterator","constructor","options","boxzilla_options","locationHashRefersBox","location","hash","elementId","isLoggedIn","console","log","inited","boxOpts","boxContentElement","post","slug","background_color","background","color","border_color","borderColor","border_width","borderWidth","parseInt","border_style","borderStyle","width","maxWidth","firstChild","lastChild","mc4wp_forms_config","submitted_form","selector","element_id","maybeOpenMailChimpForWordPressBox","boxzilla"],"mappings":"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","file":"script.min.js","sourcesContent":["(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){\n/*!\n * EventEmitter v5.2.5 - git.io/ee\n * Unlicense - http://unlicense.org/\n * Oliver Caldwell - http://oli.me.uk/\n * @preserve\n */\n\n;(function (exports) {\n 'use strict';\n\n /**\n * Class for managing events.\n * Can be extended to provide event functionality in other classes.\n *\n * @class EventEmitter Manages event registering and emitting.\n */\n function EventEmitter() {}\n\n // Shortcuts to improve speed and size\n var proto = EventEmitter.prototype;\n var originalGlobalValue = exports.EventEmitter;\n\n /**\n * Finds the index of the listener for the event in its storage array.\n *\n * @param {Function[]} listeners Array of listeners to search through.\n * @param {Function} listener Method to look for.\n * @return {Number} Index of the specified listener, -1 if not found\n * @api private\n */\n function indexOfListener(listeners, listener) {\n var i = listeners.length;\n while (i--) {\n if (listeners[i].listener === listener) {\n return i;\n }\n }\n\n return -1;\n }\n\n /**\n * Alias a method while keeping the context correct, to allow for overwriting of target method.\n *\n * @param {String} name The name of the target method.\n * @return {Function} The aliased method\n * @api private\n */\n function alias(name) {\n return function aliasClosure() {\n return this[name].apply(this, arguments);\n };\n }\n\n /**\n * Returns the listener array for the specified event.\n * Will initialise the event object and listener arrays if required.\n * 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.\n * Each property in the object response is an array of listener functions.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Function[]|Object} All listener functions for the event.\n */\n proto.getListeners = function getListeners(evt) {\n var events = this._getEvents();\n var response;\n var key;\n\n // Return a concatenated array of all matching events if\n // the selector is a regular expression.\n if (evt instanceof RegExp) {\n response = {};\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n response[key] = events[key];\n }\n }\n }\n else {\n response = events[evt] || (events[evt] = []);\n }\n\n return response;\n };\n\n /**\n * Takes a list of listener objects and flattens it into a list of listener functions.\n *\n * @param {Object[]} listeners Raw listener objects.\n * @return {Function[]} Just the listener functions.\n */\n proto.flattenListeners = function flattenListeners(listeners) {\n var flatListeners = [];\n var i;\n\n for (i = 0; i < listeners.length; i += 1) {\n flatListeners.push(listeners[i].listener);\n }\n\n return flatListeners;\n };\n\n /**\n * 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.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Object} All listener functions for an event in an object.\n */\n proto.getListenersAsObject = function getListenersAsObject(evt) {\n var listeners = this.getListeners(evt);\n var response;\n\n if (listeners instanceof Array) {\n response = {};\n response[evt] = listeners;\n }\n\n return response || listeners;\n };\n\n function isValidListener (listener) {\n if (typeof listener === 'function' || listener instanceof RegExp) {\n return true\n } else if (listener && typeof listener === 'object') {\n return isValidListener(listener.listener)\n } else {\n return false\n }\n }\n\n /**\n * Adds a listener function to the specified event.\n * The listener will not be added if it is a duplicate.\n * If the listener returns true then it will be removed after it is called.\n * If you pass a regular expression as the event name then the listener will be added to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListener = function addListener(evt, listener) {\n if (!isValidListener(listener)) {\n throw new TypeError('listener must be a function');\n }\n\n var listeners = this.getListenersAsObject(evt);\n var listenerIsWrapped = typeof listener === 'object';\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {\n listeners[key].push(listenerIsWrapped ? listener : {\n listener: listener,\n once: false\n });\n }\n }\n\n return this;\n };\n\n /**\n * Alias of addListener\n */\n proto.on = alias('addListener');\n\n /**\n * Semi-alias of addListener. It will add a listener that will be\n * automatically removed after its first execution.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addOnceListener = function addOnceListener(evt, listener) {\n return this.addListener(evt, {\n listener: listener,\n once: true\n });\n };\n\n /**\n * Alias of addOnceListener.\n */\n proto.once = alias('addOnceListener');\n\n /**\n * 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.\n * You need to tell it what event names should be matched by a regex.\n *\n * @param {String} evt Name of the event to create.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvent = function defineEvent(evt) {\n this.getListeners(evt);\n return this;\n };\n\n /**\n * Uses defineEvent to define multiple events.\n *\n * @param {String[]} evts An array of event names to define.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvents = function defineEvents(evts) {\n for (var i = 0; i < evts.length; i += 1) {\n this.defineEvent(evts[i]);\n }\n return this;\n };\n\n /**\n * Removes a listener function from the specified event.\n * When passed a regular expression as the event name, it will remove the listener from all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to remove the listener from.\n * @param {Function} listener Method to remove from the event.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListener = function removeListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var index;\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key)) {\n index = indexOfListener(listeners[key], listener);\n\n if (index !== -1) {\n listeners[key].splice(index, 1);\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of removeListener\n */\n proto.off = alias('removeListener');\n\n /**\n * Adds listeners in bulk using the manipulateListeners method.\n * 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.\n * You can also pass it a regular expression to add the array of listeners to all events that match it.\n * Yeah, this function does quite a bit. That's probably a bad thing.\n *\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to add.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListeners = function addListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(false, evt, listeners);\n };\n\n /**\n * Removes listeners in bulk using the manipulateListeners method.\n * 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.\n * You can also pass it an event name and an array of listeners to be removed.\n * You can also pass it a regular expression to remove the listeners from all events that match it.\n *\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListeners = function removeListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(true, evt, listeners);\n };\n\n /**\n * 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.\n * The first argument will determine if the listeners are removed (true) or added (false).\n * 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.\n * You can also pass it an event name and an array of listeners to be added/removed.\n * You can also pass it a regular expression to manipulate the listeners of all events that match it.\n *\n * @param {Boolean} remove True if you want to remove listeners, false if you want to add.\n * @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.\n * @param {Function[]} [listeners] An optional array of listener functions to add/remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {\n var i;\n var value;\n var single = remove ? this.removeListener : this.addListener;\n var multiple = remove ? this.removeListeners : this.addListeners;\n\n // If evt is an object then pass each of its properties to this method\n if (typeof evt === 'object' && !(evt instanceof RegExp)) {\n for (i in evt) {\n if (evt.hasOwnProperty(i) && (value = evt[i])) {\n // Pass the single listener straight through to the singular method\n if (typeof value === 'function') {\n single.call(this, i, value);\n }\n else {\n // Otherwise pass back to the multiple function\n multiple.call(this, i, value);\n }\n }\n }\n }\n else {\n // So evt must be a string\n // And listeners must be an array of listeners\n // Loop over it and pass each one to the multiple method\n i = listeners.length;\n while (i--) {\n single.call(this, evt, listeners[i]);\n }\n }\n\n return this;\n };\n\n /**\n * Removes all listeners from a specified event.\n * If you do not specify an event then all listeners will be removed.\n * That means every event will be emptied.\n * You can also pass a regex to remove all events that match it.\n *\n * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeEvent = function removeEvent(evt) {\n var type = typeof evt;\n var events = this._getEvents();\n var key;\n\n // Remove different things depending on the state of evt\n if (type === 'string') {\n // Remove all listeners for the specified event\n delete events[evt];\n }\n else if (evt instanceof RegExp) {\n // Remove all events matching the regex.\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n delete events[key];\n }\n }\n }\n else {\n // Remove all listeners in all events\n delete this._events;\n }\n\n return this;\n };\n\n /**\n * Alias of removeEvent.\n *\n * Added to mirror the node API.\n */\n proto.removeAllListeners = alias('removeEvent');\n\n /**\n * Emits an event of your choice.\n * When emitted, every listener attached to that event will be executed.\n * If you pass the optional argument array then those arguments will be passed to every listener upon execution.\n * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.\n * So they will not arrive within the array on the other side, they will be separate.\n * You can also pass a regular expression to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {Array} [args] Optional array of arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emitEvent = function emitEvent(evt, args) {\n var listenersMap = this.getListenersAsObject(evt);\n var listeners;\n var listener;\n var i;\n var key;\n var response;\n\n for (key in listenersMap) {\n if (listenersMap.hasOwnProperty(key)) {\n listeners = listenersMap[key].slice(0);\n\n for (i = 0; i < listeners.length; i++) {\n // If the listener returns true then it shall be removed from the event\n // The function is executed either with a basic call or an apply if there is an args array\n listener = listeners[i];\n\n if (listener.once === true) {\n this.removeListener(evt, listener.listener);\n }\n\n response = listener.listener.apply(this, args || []);\n\n if (response === this._getOnceReturnValue()) {\n this.removeListener(evt, listener.listener);\n }\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of emitEvent\n */\n proto.trigger = alias('emitEvent');\n\n /**\n * 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.\n * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {...*} Optional additional arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emit = function emit(evt) {\n var args = Array.prototype.slice.call(arguments, 1);\n return this.emitEvent(evt, args);\n };\n\n /**\n * Sets the current value to check against when executing listeners. If a\n * listeners return value matches the one set here then it will be removed\n * after execution. This value defaults to true.\n *\n * @param {*} value The new value to check for when executing listeners.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.setOnceReturnValue = function setOnceReturnValue(value) {\n this._onceReturnValue = value;\n return this;\n };\n\n /**\n * Fetches the current value to check against when executing listeners. If\n * the listeners return value matches this one then it should be removed\n * automatically. It will return true by default.\n *\n * @return {*|Boolean} The current value to check for or the default, true.\n * @api private\n */\n proto._getOnceReturnValue = function _getOnceReturnValue() {\n if (this.hasOwnProperty('_onceReturnValue')) {\n return this._onceReturnValue;\n }\n else {\n return true;\n }\n };\n\n /**\n * Fetches the events object and creates one if required.\n *\n * @return {Object} The events storage object.\n * @api private\n */\n proto._getEvents = function _getEvents() {\n return this._events || (this._events = {});\n };\n\n /**\n * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.\n *\n * @return {Function} Non conflicting EventEmitter class.\n */\n EventEmitter.noConflict = function noConflict() {\n exports.EventEmitter = originalGlobalValue;\n return EventEmitter;\n };\n\n // Expose the class either via AMD, CommonJS or the global object\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return EventEmitter;\n });\n }\n else if (typeof module === 'object' && module.exports){\n module.exports = EventEmitter;\n }\n else {\n exports.EventEmitter = EventEmitter;\n }\n}(typeof window !== 'undefined' ? window : this || {}));\n\n},{}],2:[function(require,module,exports){\n\"use strict\";\n\nvar duration = 320;\n\nfunction css(element, styles) {\n for (var property in styles) {\n element.style[property] = styles[property];\n }\n}\n\nfunction initObjectProperties(properties, value) {\n var newObject = {};\n\n for (var i = 0; i < properties.length; i++) {\n newObject[properties[i]] = value;\n }\n\n return newObject;\n}\n\nfunction copyObjectProperties(properties, object) {\n var newObject = {};\n\n for (var i = 0; i < properties.length; i++) {\n newObject[properties[i]] = object[properties[i]];\n }\n\n return newObject;\n}\n/**\n * Checks if the given element is currently being animated.\n *\n * @param element\n * @returns {boolean}\n */\n\n\nfunction animated(element) {\n return !!element.getAttribute('data-animated');\n}\n/**\n * Toggles the element using the given animation.\n *\n * @param element\n * @param animation Either \"fade\" or \"slide\"\n */\n\n\nfunction toggle(element, animation, callbackFn) {\n var nowVisible = element.style.display != 'none' || element.offsetLeft > 0; // create clone for reference\n\n var clone = element.cloneNode(true);\n\n var cleanup = function cleanup() {\n element.removeAttribute('data-animated');\n element.setAttribute('style', clone.getAttribute('style'));\n element.style.display = nowVisible ? 'none' : '';\n\n if (callbackFn) {\n callbackFn();\n }\n }; // store attribute so everyone knows we're animating this element\n\n\n element.setAttribute('data-animated', \"true\"); // toggle element visiblity right away if we're making something visible\n\n if (!nowVisible) {\n element.style.display = '';\n }\n\n var hiddenStyles, visibleStyles; // animate properties\n\n if (animation === 'slide') {\n hiddenStyles = initObjectProperties([\"height\", \"borderTopWidth\", \"borderBottomWidth\", \"paddingTop\", \"paddingBottom\"], 0);\n visibleStyles = {};\n\n if (!nowVisible) {\n var computedStyles = window.getComputedStyle(element);\n 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.\n\n if (!isFinite(visibleStyles.height)) {\n var clientRect = element.getBoundingClientRect();\n visibleStyles.height = clientRect.height;\n }\n\n css(element, hiddenStyles);\n } // don't show a scrollbar during animation\n\n\n element.style.overflowY = 'hidden';\n animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);\n } else {\n hiddenStyles = {\n opacity: 0\n };\n visibleStyles = {\n opacity: 1\n };\n\n if (!nowVisible) {\n css(element, hiddenStyles);\n }\n\n animate(element, nowVisible ? hiddenStyles : visibleStyles, cleanup);\n }\n}\n\nfunction animate(element, targetStyles, fn) {\n var last = +new Date();\n var initialStyles = window.getComputedStyle(element);\n var currentStyles = {};\n var propSteps = {};\n\n for (var property in targetStyles) {\n // make sure we have an object filled with floats\n targetStyles[property] = parseFloat(targetStyles[property]); // calculate step size & current value\n\n var to = targetStyles[property];\n var current = parseFloat(initialStyles[property]); // is there something to do?\n\n if (current == to) {\n delete targetStyles[property];\n continue;\n }\n\n propSteps[property] = (to - current) / duration; // points per second\n\n currentStyles[property] = current;\n }\n\n var tick = function tick() {\n var now = +new Date();\n var timeSinceLastTick = now - last;\n var done = true;\n var step, to, increment, newValue;\n\n for (var property in targetStyles) {\n step = propSteps[property];\n to = targetStyles[property];\n increment = step * timeSinceLastTick;\n newValue = currentStyles[property] + increment;\n\n if (step > 0 && newValue >= to || step < 0 && newValue <= to) {\n newValue = to;\n } else {\n done = false;\n } // store new value\n\n\n currentStyles[property] = newValue;\n var suffix = property !== \"opacity\" ? \"px\" : \"\";\n element.style[property] = newValue + suffix;\n }\n\n last = +new Date(); // keep going until we're done for all props\n\n if (!done) {\n window.requestAnimationFrame && requestAnimationFrame(tick) || setTimeout(tick, 32);\n } else {\n // call callback\n fn && fn();\n }\n };\n\n tick();\n}\n\nmodule.exports = {\n 'toggle': toggle,\n 'animate': animate,\n 'animated': animated\n};\n\n},{}],3:[function(require,module,exports){\n'use strict';\n\nvar defaults = {\n 'animation': 'fade',\n 'rehide': false,\n 'content': '',\n 'cookie': null,\n 'icon': '×',\n 'screenWidthCondition': null,\n 'position': 'center',\n 'testMode': false,\n 'trigger': false,\n 'closable': true\n},\n Boxzilla,\n Animator = require('./animator.js');\n/**\n* Merge 2 objects, values of the latter overwriting the former.\n*\n* @param obj1\n* @param obj2\n* @returns {*}\n*/\n\n\nfunction merge(obj1, obj2) {\n var obj3 = {};\n\n for (var attrname in obj1) {\n obj3[attrname] = obj1[attrname];\n }\n\n for (var attrname in obj2) {\n obj3[attrname] = obj2[attrname];\n }\n\n return obj3;\n}\n/**\n* Get the real height of entire document.\n* @returns {number}\n*/\n\n\nfunction getDocumentHeight() {\n var body = document.body,\n html = document.documentElement;\n var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);\n return height;\n} // Box Object\n\n\nvar Box = function Box(id, config) {\n this.id = id; // store config values\n\n this.config = merge(defaults, config); // store ref to overlay\n\n this.overlay = document.getElementById('boxzilla-overlay'); // state\n\n this.visible = false;\n this.dismissed = false;\n this.triggered = false;\n this.triggerHeight = this.calculateTriggerHeight();\n this.cookieSet = this.isCookieSet();\n this.element = null;\n this.contentElement = null;\n this.closeIcon = null; // create dom elements for this box\n\n this.dom(); // further initialise the box\n\n this.events();\n}; // initialise the box\n\n\nBox.prototype.events = function () {\n var box = this; // attach event to \"close\" icon inside box\n\n if (this.closeIcon) {\n this.closeIcon.addEventListener('click', this.dismiss.bind(this));\n }\n\n this.element.addEventListener('click', function (e) {\n if (e.target.tagName === 'A') {\n Boxzilla.trigger('box.interactions.link', [box, e.target]);\n }\n }, false);\n this.element.addEventListener('submit', function (e) {\n box.setCookie();\n Boxzilla.trigger('box.interactions.form', [box, e.target]);\n }, false);\n}; // generate dom elements for this box\n\n\nBox.prototype.dom = function () {\n var wrapper = document.createElement('div');\n wrapper.className = 'boxzilla-container boxzilla-' + this.config.position + '-container';\n var box = document.createElement('div');\n box.setAttribute('id', 'boxzilla-' + this.id);\n box.className = 'boxzilla boxzilla-' + this.id + ' boxzilla-' + this.config.position;\n box.style.display = 'none';\n wrapper.appendChild(box);\n var content;\n\n if (typeof this.config.content === \"string\") {\n content = document.createElement('div');\n content.innerHTML = this.config.content;\n } else {\n content = this.config.content; // make sure element is visible\n\n content.style.display = '';\n }\n\n content.className = 'boxzilla-content';\n box.appendChild(content);\n\n if (this.config.closable && this.config.icon) {\n var closeIcon = document.createElement('span');\n closeIcon.className = \"boxzilla-close-icon\";\n closeIcon.innerHTML = this.config.icon;\n box.appendChild(closeIcon);\n this.closeIcon = closeIcon;\n }\n\n document.body.appendChild(wrapper);\n this.contentElement = content;\n this.element = box;\n}; // set (calculate) custom box styling depending on box options\n\n\nBox.prototype.setCustomBoxStyling = function () {\n // reset element to its initial state\n var origDisplay = this.element.style.display;\n this.element.style.display = '';\n this.element.style.overflowY = 'auto';\n this.element.style.maxHeight = 'none'; // get new dimensions\n\n var windowHeight = window.innerHeight;\n var boxHeight = this.element.clientHeight; // add scrollbar to box and limit height\n\n if (boxHeight > windowHeight) {\n this.element.style.maxHeight = windowHeight + \"px\";\n this.element.style.overflowY = 'scroll';\n } // set new top margin for boxes which are centered\n\n\n if (this.config.position === 'center') {\n var newTopMargin = (windowHeight - boxHeight) / 2;\n newTopMargin = newTopMargin >= 0 ? newTopMargin : 0;\n this.element.style.marginTop = newTopMargin + \"px\";\n }\n\n this.element.style.display = origDisplay;\n}; // toggle visibility of the box\n\n\nBox.prototype.toggle = function (show) {\n // revert visibility if no explicit argument is given\n if (typeof show === \"undefined\") {\n show = !this.visible;\n } // is box already at desired visibility?\n\n\n if (show === this.visible) {\n return false;\n } // is box being animated?\n\n\n if (Animator.animated(this.element)) {\n return false;\n } // if box should be hidden but is not closable, bail.\n\n\n if (!show && !this.config.closable) {\n return false;\n } // set new visibility status\n\n\n this.visible = show; // calculate new styling rules\n\n this.setCustomBoxStyling(); // trigger event\n\n Boxzilla.trigger('box.' + (show ? 'show' : 'hide'), [this]); // show or hide box using selected animation\n\n if (this.config.position === 'center') {\n this.overlay.classList.toggle('boxzilla-' + this.id + '-overlay');\n Animator.toggle(this.overlay, \"fade\");\n }\n\n Animator.toggle(this.element, this.config.animation, function () {\n if (this.visible) {\n return;\n }\n\n this.contentElement.innerHTML = this.contentElement.innerHTML;\n }.bind(this));\n return true;\n}; // show the box\n\n\nBox.prototype.show = function () {\n return this.toggle(true);\n}; // hide the box\n\n\nBox.prototype.hide = function () {\n return this.toggle(false);\n}; // calculate trigger height\n\n\nBox.prototype.calculateTriggerHeight = function () {\n var triggerHeight = 0;\n\n if (this.config.trigger) {\n if (this.config.trigger.method === 'element') {\n var triggerElement = document.body.querySelector(this.config.trigger.value);\n\n if (triggerElement) {\n var offset = triggerElement.getBoundingClientRect();\n triggerHeight = offset.top;\n }\n } else if (this.config.trigger.method === 'percentage') {\n triggerHeight = this.config.trigger.value / 100 * getDocumentHeight();\n }\n }\n\n return triggerHeight;\n};\n\nBox.prototype.fits = function () {\n if (!this.config.screenWidthCondition || !this.config.screenWidthCondition.value) {\n return true;\n }\n\n switch (this.config.screenWidthCondition.condition) {\n case \"larger\":\n return window.innerWidth > this.config.screenWidthCondition.value;\n\n case \"smaller\":\n return window.innerWidth < this.config.screenWidthCondition.value;\n } // meh.. condition should be \"smaller\" or \"larger\", just return true.\n\n\n return true;\n};\n\nBox.prototype.onResize = function () {\n this.triggerHeight = this.calculateTriggerHeight();\n this.setCustomBoxStyling();\n}; // is this box enabled?\n\n\nBox.prototype.mayAutoShow = function () {\n if (this.dismissed) {\n return false;\n } // check if box fits on given minimum screen width\n\n\n if (!this.fits()) {\n return false;\n } // if trigger empty or error in calculating triggerHeight, return false\n\n\n if (!this.config.trigger) {\n return false;\n } // rely on cookie value (show if not set, don't show if set)\n\n\n return !this.cookieSet;\n};\n\nBox.prototype.mayRehide = function () {\n return this.config.rehide && this.triggered;\n};\n\nBox.prototype.isCookieSet = function () {\n // always show on test mode or when no auto-trigger is configured\n if (this.config.testMode || !this.config.trigger) {\n return false;\n } // if either cookie is null or trigger & dismiss are both falsey, don't bother checking.\n\n\n if (!this.config.cookie || !this.config.cookie.triggered && !this.config.cookie.dismissed) {\n return false;\n }\n\n var cookieSet = document.cookie.replace(new RegExp(\"(?:(?:^|.*;)\\\\s*\" + 'boxzilla_box_' + this.id + \"\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$\"), \"$1\") === \"true\";\n return cookieSet;\n}; // set cookie that disables automatically showing the box\n\n\nBox.prototype.setCookie = function (hours) {\n var expiryDate = new Date();\n expiryDate.setHours(expiryDate.getHours() + hours);\n document.cookie = 'boxzilla_box_' + this.id + '=true; expires=' + expiryDate.toUTCString() + '; path=/';\n};\n\nBox.prototype.trigger = function () {\n var shown = this.show();\n\n if (!shown) {\n return;\n }\n\n this.triggered = true;\n\n if (this.config.cookie && this.config.cookie.triggered) {\n this.setCookie(this.config.cookie.triggered);\n }\n};\n/**\n* Dismisses the box and optionally sets a cookie.\n*\n* @param e The event that triggered this dismissal.\n* @returns {boolean}\n*/\n\n\nBox.prototype.dismiss = function (e) {\n // prevent default action\n e && e.preventDefault(); // only dismiss box if it's currently open.\n\n if (!this.visible) {\n return false;\n } // hide box element\n\n\n this.hide(); // set cookie\n\n if (this.config.cookie && this.config.cookie.dismissed) {\n this.setCookie(this.config.cookie.dismissed);\n }\n\n this.dismissed = true;\n Boxzilla.trigger('box.dismiss', [this]);\n return true;\n};\n\nmodule.exports = function (_Boxzilla) {\n Boxzilla = _Boxzilla;\n return Box;\n};\n\n},{\"./animator.js\":2}],4:[function(require,module,exports){\n'use strict';\n\nvar EventEmitter = require('wolfy87-eventemitter');\n\nvar Timer = require('./timer.js');\n\nvar Boxzilla = Object.create(EventEmitter.prototype);\n\nvar Box = require('./box.js')(Boxzilla);\n\nvar boxes = [];\nvar overlay;\nvar scrollElement = window;\nvar siteTimer;\nvar pageTimer;\nvar pageViews;\nvar initialised = false;\n\nvar styles = require('./styles.js');\n\nvar ExitIntent = require('./triggers/exit-intent.js');\n\nfunction throttle(fn, threshhold, scope) {\n threshhold || (threshhold = 250);\n var last, deferTimer;\n return function () {\n var context = scope || this;\n var now = +new Date(),\n args = arguments;\n\n if (last && now < last + threshhold) {\n // hold on to it\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function () {\n last = now;\n fn.apply(context, args);\n }, threshhold);\n } else {\n last = now;\n fn.apply(context, args);\n }\n };\n} // \"keyup\" listener\n\n\nfunction onKeyUp(e) {\n if (e.keyCode === 27) {\n Boxzilla.dismiss();\n }\n} // check \"pageviews\" criteria for each box\n\n\nfunction checkPageViewsCriteria() {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (!box.mayAutoShow()) {\n return;\n }\n\n if (box.config.trigger.method === 'pageviews' && pageViews >= box.config.trigger.value) {\n box.trigger();\n }\n });\n} // check time trigger criteria for each box\n\n\nfunction checkTimeCriteria() {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (!box.mayAutoShow()) {\n return;\n } // check \"time on site\" trigger\n\n\n if (box.config.trigger.method === 'time_on_site' && siteTimer.time >= box.config.trigger.value) {\n box.trigger();\n } // check \"time on page\" trigger\n\n\n if (box.config.trigger.method === 'time_on_page' && pageTimer.time >= box.config.trigger.value) {\n box.trigger();\n }\n });\n} // check triggerHeight criteria for all boxes\n\n\nfunction checkHeightCriteria() {\n var scrollY = scrollElement.hasOwnProperty('pageYOffset') ? scrollElement.pageYOffset : scrollElement.scrollTop;\n scrollY = scrollY + window.innerHeight * 0.9;\n boxes.forEach(function (box) {\n if (!box.mayAutoShow() || box.triggerHeight <= 0) {\n return;\n }\n\n if (scrollY > box.triggerHeight) {\n // don't bother if another box is currently open\n if (isAnyBoxVisible()) {\n return;\n } // trigger box\n\n\n box.trigger();\n } // if box may auto-hide and scrollY is less than triggerHeight (with small margin of error), hide box\n\n\n if (box.mayRehide() && scrollY < box.triggerHeight - 5) {\n box.hide();\n }\n });\n} // recalculate heights and variables based on height\n\n\nfunction recalculateHeights() {\n boxes.forEach(function (box) {\n box.onResize();\n });\n}\n\nfunction onOverlayClick(e) {\n var x = e.offsetX;\n var y = e.offsetY; // calculate if click was less than 40px outside box to avoid closing it by accident\n\n boxes.forEach(function (box) {\n var rect = box.element.getBoundingClientRect();\n var margin = 40; // if click was not anywhere near box, dismiss it.\n\n if (x < rect.left - margin || x > rect.right + margin || y < rect.top - margin || y > rect.bottom + margin) {\n box.dismiss();\n }\n });\n}\n\nfunction showBoxesWithExitIntentTrigger() {\n // do nothing if already triggered OR another box is visible.\n if (isAnyBoxVisible()) {\n return;\n }\n\n boxes.forEach(function (box) {\n if (box.mayAutoShow() && box.config.trigger.method === 'exit_intent') {\n box.trigger();\n }\n });\n}\n\nfunction isAnyBoxVisible() {\n return boxes.filter(function (b) {\n return b.visible;\n }).length > 0;\n}\n\nfunction onElementClick(e) {\n // find <a> element in up to 3 parent elements\n var el = e.target || e.srcElement;\n var depth = 3;\n\n for (var i = 0; i <= depth; i++) {\n if (!el || el.tagName === 'A') {\n break;\n }\n\n el = el.parentElement;\n }\n\n if (!el || el.tagName !== 'A' || !el.getAttribute('href')) {\n return;\n }\n\n if (el.getAttribute('href').toLowerCase().indexOf('#boxzilla-') === 0) {\n var boxId = el.getAttribute('href').toLowerCase().substring(\"#boxzilla-\".length);\n Boxzilla.toggle(boxId);\n }\n}\n\nvar timers = {\n start: function start() {\n try {\n var sessionTime = sessionStorage.getItem('boxzilla_timer');\n if (sessionTime) siteTimer.time = sessionTime;\n } catch (e) {}\n\n siteTimer.start();\n pageTimer.start();\n },\n stop: function stop() {\n sessionStorage.setItem('boxzilla_timer', siteTimer.time);\n siteTimer.stop();\n pageTimer.stop();\n }\n}; // initialise & add event listeners\n\nBoxzilla.init = function () {\n if (initialised) {\n return;\n }\n\n document.body.addEventListener('click', onElementClick, true);\n\n try {\n pageViews = sessionStorage.getItem('boxzilla_pageviews') || 0;\n } catch (e) {\n pageViews = 0;\n }\n\n siteTimer = new Timer(0);\n pageTimer = new Timer(0); // insert styles into DOM\n\n var styleElement = document.createElement('style');\n styleElement.setAttribute(\"type\", \"text/css\");\n styleElement.innerHTML = styles;\n document.head.appendChild(styleElement); // add overlay element to dom\n\n overlay = document.createElement('div');\n overlay.style.display = 'none';\n overlay.id = 'boxzilla-overlay';\n document.body.appendChild(overlay); // init exit intent trigger\n\n new ExitIntent(showBoxesWithExitIntentTrigger);\n scrollElement.addEventListener('touchstart', throttle(checkHeightCriteria), true);\n scrollElement.addEventListener('scroll', throttle(checkHeightCriteria), true);\n window.addEventListener('resize', throttle(recalculateHeights));\n window.addEventListener('load', recalculateHeights);\n overlay.addEventListener('click', onOverlayClick);\n window.setInterval(checkTimeCriteria, 1000);\n window.setTimeout(checkPageViewsCriteria, 1000);\n document.addEventListener('keyup', onKeyUp);\n timers.start();\n window.addEventListener('focus', timers.start);\n window.addEventListener('beforeunload', function () {\n timers.stop();\n sessionStorage.setItem('boxzilla_pageviews', ++pageViews);\n });\n window.addEventListener('blur', timers.stop);\n Boxzilla.trigger('ready');\n initialised = true; // ensure this function doesn't run again\n};\n/**\n * Create a new Box\n *\n * @param string id\n * @param object opts\n *\n * @returns Box\n */\n\n\nBoxzilla.create = function (id, opts) {\n // preserve backwards compat for minimumScreenWidth option\n if (typeof opts.minimumScreenWidth !== \"undefined\") {\n opts.screenWidthCondition = {\n condition: \"larger\",\n value: opts.minimumScreenWidth\n };\n }\n\n var box = new Box(id, opts);\n boxes.push(box);\n return box;\n};\n\nBoxzilla.get = function (id) {\n for (var i = 0; i < boxes.length; i++) {\n var box = boxes[i];\n\n if (box.id == id) {\n return box;\n }\n }\n\n throw new Error(\"No box exists with ID \" + id);\n}; // dismiss a single box (or all by omitting id param)\n\n\nBoxzilla.dismiss = function (id) {\n // if no id given, dismiss all current open boxes\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.dismiss();\n });\n } else {\n Boxzilla.get(id).dismiss();\n }\n};\n\nBoxzilla.hide = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.hide();\n });\n } else {\n Boxzilla.get(id).hide();\n }\n};\n\nBoxzilla.show = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.show();\n });\n } else {\n Boxzilla.get(id).show();\n }\n};\n\nBoxzilla.toggle = function (id) {\n if (typeof id === \"undefined\") {\n boxes.forEach(function (box) {\n box.toggle();\n });\n } else {\n Boxzilla.get(id).toggle();\n }\n}; // expose each individual box.\n\n\nBoxzilla.boxes = boxes; // expose boxzilla object\n\nwindow.Boxzilla = Boxzilla;\n\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = Boxzilla;\n}\n\n},{\"./box.js\":3,\"./styles.js\":5,\"./timer.js\":6,\"./triggers/exit-intent.js\":7,\"wolfy87-eventemitter\":1}],5:[function(require,module,exports){\n\"use strict\";\n\nvar 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}\";\nmodule.exports = styles;\n\n},{}],6:[function(require,module,exports){\n'use strict';\n\nvar Timer = function Timer(start) {\n this.time = start;\n this.interval = 0;\n};\n\nTimer.prototype.tick = function () {\n this.time++;\n};\n\nTimer.prototype.start = function () {\n if (!this.interval) {\n this.interval = window.setInterval(this.tick.bind(this), 1000);\n }\n};\n\nTimer.prototype.stop = function () {\n if (this.interval) {\n window.clearInterval(this.interval);\n this.interval = 0;\n }\n};\n\nmodule.exports = Timer;\n\n},{}],7:[function(require,module,exports){\n'use strict';\n\nmodule.exports = function (callback) {\n var timeout = null;\n var touchStart = {};\n\n function triggerCallback() {\n document.documentElement.removeEventListener('mouseleave', onMouseLeave);\n document.documentElement.removeEventListener('mouseenter', onMouseEnter);\n document.documentElement.removeEventListener('click', clearTimeout);\n window.removeEventListener('touchstart', onTouchStart);\n window.removeEventListener('touchend', onTouchEnd);\n callback();\n }\n\n function clearTimeout() {\n if (timeout === null) {\n return;\n }\n\n window.clearTimeout(timeout);\n timeout = null;\n }\n\n function onMouseEnter(evt) {\n clearTimeout();\n }\n\n function onMouseLeave(evt) {\n clearTimeout(); // did mouse leave at top of window?\n // add small exception space in the top-right corner\n\n if (evt.clientY <= 0 && evt.clientX < 0.80 * window.innerWidth) {\n timeout = window.setTimeout(triggerCallback, 400);\n }\n }\n\n function onTouchStart(evt) {\n clearTimeout();\n touchStart = {\n timestamp: performance.now(),\n scrollY: window.scrollY,\n windowHeight: window.innerHeight\n };\n }\n\n function onTouchEnd(evt) {\n clearTimeout(); // did address bar appear?\n\n if (window.innerHeight > touchStart.windowHeight) {\n return;\n } // allow a tiny tiny margin for error, to not fire on clicks\n\n\n if (window.scrollY + 20 >= touchStart.scrollY) {\n return;\n }\n\n if (performance.now() - touchStart.timestamp > 300) {\n return;\n }\n\n if (['A', 'INPUT', 'BUTTON'].indexOf(evt.target.tagName) > -1) {\n return;\n }\n\n timeout = window.setTimeout(triggerCallback, 800);\n }\n\n window.addEventListener('touchstart', onTouchStart);\n window.addEventListener('touchend', onTouchEnd);\n document.documentElement.addEventListener('mouseenter', onMouseEnter);\n document.documentElement.addEventListener('mouseleave', onMouseLeave);\n document.documentElement.addEventListener('click', clearTimeout);\n};\n\n},{}],8:[function(require,module,exports){\n\"use strict\";\n\nfunction _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); }\n\n(function () {\n 'use strict';\n\n var Boxzilla = require('boxzilla');\n\n var options = window.boxzilla_options; // expose Boxzilla object to window\n\n window.Boxzilla = Boxzilla; // helper function for setting CSS styles\n\n function css(element, styles) {\n if (styles.background_color) {\n element.style.background = styles.background_color;\n }\n\n if (styles.color) {\n element.style.color = styles.color;\n }\n\n if (styles.border_color) {\n element.style.borderColor = styles.border_color;\n }\n\n if (styles.border_width) {\n element.style.borderWidth = parseInt(styles.border_width) + \"px\";\n }\n\n if (styles.border_style) {\n element.style.borderStyle = styles.border_style;\n }\n\n if (styles.width) {\n element.style.maxWidth = parseInt(styles.width) + \"px\";\n }\n }\n\n function createBoxesFromConfig() {\n // failsafe against including script twice.\n if (options.inited) {\n return;\n } // create boxes from options\n\n\n for (var key in options.boxes) {\n // get opts\n var boxOpts = options.boxes[key];\n boxOpts.testMode = isLoggedIn && options.testMode; // find box content element, bail if not found\n\n var boxContentElement = document.getElementById('boxzilla-box-' + boxOpts.id + '-content');\n\n if (!boxContentElement) {\n continue;\n } // use element as content option\n\n\n boxOpts.content = boxContentElement; // create box\n\n var box = Boxzilla.create(boxOpts.id, boxOpts); // add box slug to box element as classname\n\n box.element.className = box.element.className + ' boxzilla-' + boxOpts.post.slug; // add custom css to box\n\n css(box.element, boxOpts.css);\n box.element.firstChild.firstChild.className += \" first-child\";\n box.element.firstChild.lastChild.className += \" last-child\"; // maybe show box right away\n\n if (box.fits() && locationHashRefersBox(box)) {\n box.show();\n }\n } // set flag to prevent initialising twice\n\n\n options.inited = true; // trigger \"done\" event.\n\n Boxzilla.trigger('done'); // maybe open box with MC4WP form in it\n\n maybeOpenMailChimpForWordPressBox();\n }\n\n function locationHashRefersBox(box) {\n if (!window.location.hash || 0 === window.location.hash.length) {\n return false;\n }\n\n var elementId = window.location.hash.substring(1); // only attempt on strings looking like an ID \n\n var regex = /^[a-zA-Z\\-\\_0-9]+$/;\n\n if (!regex.test(elementId)) {\n return false;\n }\n\n if (elementId === box.element.id) {\n return true;\n } else if (box.element.querySelector('#' + elementId)) {\n return true;\n }\n\n return false;\n }\n\n function maybeOpenMailChimpForWordPressBox() {\n if (_typeof(window.mc4wp_forms_config) !== \"object\" || !window.mc4wp_forms_config.submitted_form) {\n return;\n }\n\n var selector = '#' + window.mc4wp_forms_config.submitted_form.element_id;\n var boxes = Boxzilla.boxes;\n\n for (var boxId in boxes) {\n if (!boxes.hasOwnProperty(boxId)) {\n continue;\n }\n\n var box = boxes[boxId];\n\n if (box.element.querySelector(selector)) {\n box.show();\n return;\n }\n }\n } // print message when test mode is enabled\n\n\n var isLoggedIn = document.body.className.indexOf('logged-in') > -1;\n\n if (isLoggedIn && options.testMode) {\n console.log('Boxzilla: Test mode is enabled. Please disable test mode if you\\'re done testing.');\n } // init boxzilla\n\n\n Boxzilla.init(); // on window.load, create DOM elements for boxes\n\n window.addEventListener('load', createBoxesFromConfig);\n})();\n\n},{\"boxzilla\":4}]},{},[8]);\n; })();"]}
|
bootstrap.php
CHANGED
@@ -45,7 +45,7 @@ add_action( 'plugins_loaded', function() use( $boxzilla ) {
|
|
45 |
// license manager
|
46 |
if( is_admin() || ( defined( 'DOING_CRON' ) && DOING_CRON ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
47 |
$boxzilla['license_manager']->hook();
|
48 |
-
|
49 |
if( count( $boxzilla->plugins ) > 0 ) {
|
50 |
$boxzilla['update_manager']->hook();
|
51 |
}
|
45 |
// license manager
|
46 |
if( is_admin() || ( defined( 'DOING_CRON' ) && DOING_CRON ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
47 |
$boxzilla['license_manager']->hook();
|
48 |
+
|
49 |
if( count( $boxzilla->plugins ) > 0 ) {
|
50 |
$boxzilla['update_manager']->hook();
|
51 |
}
|
boxzilla.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Boxzilla
|
4 |
-
Version: 3.2.
|
5 |
Plugin URI: https://boxzillaplugin.com/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=plugins-page
|
6 |
Description: Call-To-Action Boxes that display after visitors scroll down far enough. Unobtrusive, but highly conversing!
|
7 |
Author: ibericode
|
@@ -11,7 +11,7 @@ Domain Path: /languages/
|
|
11 |
License: GPL v3
|
12 |
|
13 |
Boxzilla Plugin
|
14 |
-
Copyright (C) 2013-
|
15 |
|
16 |
This program is free software: you can redistribute it and/or modify
|
17 |
it under the terms of the GNU General Public License as published by
|
@@ -41,7 +41,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
41 |
function _load_boxzilla() {
|
42 |
|
43 |
define( 'BOXZILLA_FILE', __FILE__ );
|
44 |
-
define( 'BOXZILLA_VERSION', '3.2.
|
45 |
|
46 |
require __DIR__ . '/bootstrap.php';
|
47 |
}
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Boxzilla
|
4 |
+
Version: 3.2.10
|
5 |
Plugin URI: https://boxzillaplugin.com/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=plugins-page
|
6 |
Description: Call-To-Action Boxes that display after visitors scroll down far enough. Unobtrusive, but highly conversing!
|
7 |
Author: ibericode
|
11 |
License: GPL v3
|
12 |
|
13 |
Boxzilla Plugin
|
14 |
+
Copyright (C) 2013-2019, Danny van Kooten, hi@dannyvankooten.com
|
15 |
|
16 |
This program is free software: you can redistribute it and/or modify
|
17 |
it under the terms of the GNU General Public License as published by
|
41 |
function _load_boxzilla() {
|
42 |
|
43 |
define( 'BOXZILLA_FILE', __FILE__ );
|
44 |
+
define( 'BOXZILLA_VERSION', '3.2.10' );
|
45 |
|
46 |
require __DIR__ . '/bootstrap.php';
|
47 |
}
|
languages/boxzilla.pot
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
# Copyright (C)
|
2 |
# This file is distributed under the same license as the boxzilla package.
|
3 |
msgid ""
|
4 |
msgstr ""
|
@@ -57,83 +57,87 @@ msgstr ""
|
|
57 |
msgid "No Boxes found in Trash"
|
58 |
msgstr ""
|
59 |
|
60 |
-
#: src/admin/class-admin.php:
|
|
|
|
|
|
|
|
|
61 |
msgid "Awesome, you are using Boxzilla! You can now safely <a href=\"%s\">deactivate the Scroll Triggered Boxes plugin</a>."
|
62 |
msgstr ""
|
63 |
|
64 |
-
#: src/admin/class-admin.php:
|
65 |
msgid "Box ID"
|
66 |
msgstr ""
|
67 |
|
68 |
-
#: src/admin/class-admin.php:
|
69 |
msgid "Box Title"
|
70 |
msgstr ""
|
71 |
|
72 |
-
#: src/admin/class-admin.php:
|
73 |
msgid "Settings"
|
74 |
msgstr ""
|
75 |
|
76 |
-
#: src/admin/class-admin.php:
|
77 |
msgid "Extensions"
|
78 |
msgstr ""
|
79 |
|
80 |
-
#: src/admin/class-admin.php:
|
81 |
msgid "and"
|
82 |
msgstr ""
|
83 |
|
84 |
-
#: src/admin/class-admin.php:
|
85 |
msgid "or"
|
86 |
msgstr ""
|
87 |
|
88 |
-
#: src/admin/class-admin.php:
|
89 |
msgid "Enter a comma-separated list of values."
|
90 |
msgstr ""
|
91 |
|
92 |
-
#: src/admin/class-admin.php:
|
93 |
msgid "Enter a comma-separated list of post slugs or post ID's.."
|
94 |
msgstr ""
|
95 |
|
96 |
-
#: src/admin/class-admin.php:
|
97 |
msgid "Enter a comma-separated list of page slugs or page ID's.."
|
98 |
msgstr ""
|
99 |
|
100 |
-
#: src/admin/class-admin.php:
|
101 |
msgid "Enter a comma-separated list of post types.."
|
102 |
msgstr ""
|
103 |
|
104 |
-
#: src/admin/class-admin.php:
|
105 |
msgid "Enter a comma-separated list of relative URL's, eg /contact/"
|
106 |
msgstr ""
|
107 |
|
108 |
-
#: src/admin/class-admin.php:
|
109 |
msgid "Box Appearance"
|
110 |
msgstr ""
|
111 |
|
112 |
-
#: src/admin/class-admin.php:
|
113 |
msgid "Box Options"
|
114 |
msgstr ""
|
115 |
|
116 |
-
#: src/admin/class-admin.php:
|
117 |
msgid "Looking for help?"
|
118 |
msgstr ""
|
119 |
|
120 |
-
#: src/admin/class-admin.php:
|
121 |
msgid "Subscribe to our newsletter"
|
122 |
msgstr ""
|
123 |
|
124 |
-
#: src/admin/class-review-notice.php:
|
125 |
msgid "You've been using Boxzilla for some time now; we hope you love it!"
|
126 |
msgstr ""
|
127 |
|
128 |
-
#: src/admin/class-review-notice.php:
|
129 |
msgid "If you do, please <a href=\"%s\">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us."
|
130 |
msgstr ""
|
131 |
|
132 |
-
#: src/admin/class-review-notice.php:
|
133 |
msgid "Dismiss this notice."
|
134 |
msgstr ""
|
135 |
|
136 |
-
#: src/licensing/class-api.php:
|
137 |
msgid "The Boxzilla server returned an invalid response."
|
138 |
msgstr ""
|
139 |
|
@@ -157,11 +161,11 @@ msgstr ""
|
|
157 |
msgid "If not, please click here: %s."
|
158 |
msgstr ""
|
159 |
|
160 |
-
#: src/admin/views/settings.php:20, src/admin/views/metaboxes/box-option-controls.php:
|
161 |
msgid "Enable test mode?"
|
162 |
msgstr ""
|
163 |
|
164 |
-
#: src/admin/views/settings.php:24, src/admin/views/metaboxes/box-option-controls.php:
|
165 |
msgid "If test mode is enabled, all boxes will show up regardless of whether a cookie has been set."
|
166 |
msgstr ""
|
167 |
|
@@ -169,39 +173,39 @@ msgstr ""
|
|
169 |
msgid "License & Plugin Updates"
|
170 |
msgstr ""
|
171 |
|
172 |
-
#: src/licensing/views/license-form.php:
|
173 |
msgid "Warning! You are <u>not</u> receiving plugin updates for the following plugin(s):"
|
174 |
msgstr ""
|
175 |
|
176 |
-
#: src/licensing/views/license-form.php:
|
177 |
msgid "License Key"
|
178 |
msgstr ""
|
179 |
|
180 |
-
#: src/licensing/views/license-form.php:
|
181 |
msgid "Enter your license key.."
|
182 |
msgstr ""
|
183 |
|
184 |
-
#: src/licensing/views/license-form.php:
|
185 |
msgid "The license key received when purchasing your premium Boxzilla plan. <a href=\"%s\">You can find it here</a>."
|
186 |
msgstr ""
|
187 |
|
188 |
-
#: src/licensing/views/license-form.php:
|
189 |
msgid "License Status"
|
190 |
msgstr ""
|
191 |
|
192 |
-
#: src/licensing/views/license-form.php:
|
193 |
msgid "ACTIVE"
|
194 |
msgstr ""
|
195 |
|
196 |
-
#: src/licensing/views/license-form.php:
|
197 |
msgid "you are receiving plugin updates"
|
198 |
msgstr ""
|
199 |
|
200 |
-
#: src/licensing/views/license-form.php:
|
201 |
msgid "INACTIVE"
|
202 |
msgstr ""
|
203 |
|
204 |
-
#: src/licensing/views/license-form.php:
|
205 |
msgid "you are <strong>not</strong> receiving plugin updates"
|
206 |
msgstr ""
|
207 |
|
@@ -297,147 +301,147 @@ msgstr ""
|
|
297 |
msgid "of the following conditions."
|
298 |
msgstr ""
|
299 |
|
300 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
301 |
msgid "Remove rule"
|
302 |
msgstr ""
|
303 |
|
304 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
305 |
msgid "is"
|
306 |
msgstr ""
|
307 |
|
308 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
309 |
msgid "is not"
|
310 |
msgstr ""
|
311 |
|
312 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
313 |
msgid "contains"
|
314 |
msgstr ""
|
315 |
|
316 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
317 |
msgid "does not contain"
|
318 |
msgstr ""
|
319 |
|
320 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
321 |
msgid "Leave empty for any or enter (comma-separated) names or ID's"
|
322 |
msgstr ""
|
323 |
|
324 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
325 |
msgid "Add another rule"
|
326 |
msgstr ""
|
327 |
|
328 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
329 |
msgid "Box Position"
|
330 |
msgstr ""
|
331 |
|
332 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
333 |
msgid "Top Left"
|
334 |
msgstr ""
|
335 |
|
336 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
337 |
msgid "Top Right"
|
338 |
msgstr ""
|
339 |
|
340 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
341 |
msgid "Center"
|
342 |
msgstr ""
|
343 |
|
344 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
345 |
msgid "Bottom Left"
|
346 |
msgstr ""
|
347 |
|
348 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
349 |
msgid "Bottom Right"
|
350 |
msgstr ""
|
351 |
|
352 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
353 |
msgid "Animation"
|
354 |
msgstr ""
|
355 |
|
356 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
357 |
msgid "Fade In"
|
358 |
msgstr ""
|
359 |
|
360 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
361 |
msgid "Slide In"
|
362 |
msgstr ""
|
363 |
|
364 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
365 |
msgid "Which animation type should be used to show the box when triggered?"
|
366 |
msgstr ""
|
367 |
|
368 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
369 |
msgid "Auto-show box?"
|
370 |
msgstr ""
|
371 |
|
372 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
373 |
msgid "Never"
|
374 |
msgstr ""
|
375 |
|
376 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
377 |
msgid "Yes, after %s seconds on the page."
|
378 |
msgstr ""
|
379 |
|
380 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
381 |
msgid "Yes, when at %s of page height"
|
382 |
msgstr ""
|
383 |
|
384 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
385 |
msgid "Yes, when at element %s"
|
386 |
msgstr ""
|
387 |
|
388 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
389 |
msgid "Example: #comments"
|
390 |
msgstr ""
|
391 |
|
392 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
393 |
msgid "Cookie expiration"
|
394 |
msgstr ""
|
395 |
|
396 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
397 |
msgid "hours"
|
398 |
msgstr ""
|
399 |
|
400 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
401 |
msgid "After this box is triggered or dismissed, how many hours should it stay hidden?"
|
402 |
msgstr ""
|
403 |
|
404 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
405 |
msgid "Screen width"
|
406 |
msgstr ""
|
407 |
|
408 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
409 |
msgid "larger"
|
410 |
msgstr ""
|
411 |
|
412 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
413 |
msgid "smaller"
|
414 |
msgstr ""
|
415 |
|
416 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
417 |
msgid "Only show on screens %s than %s."
|
418 |
msgstr ""
|
419 |
|
420 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
421 |
msgid "Leave empty if you want to show the box on all screen sizes."
|
422 |
msgstr ""
|
423 |
|
424 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
425 |
msgid "Auto-hide?"
|
426 |
msgstr ""
|
427 |
|
428 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
429 |
msgid "Hide box again when visitors scroll back up?"
|
430 |
msgstr ""
|
431 |
|
432 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
433 |
msgid "Show close icon?"
|
434 |
msgstr ""
|
435 |
|
436 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
437 |
msgid "If you decide to hide the close icon, make sure to offer an alternative way to close the box."
|
438 |
msgstr ""
|
439 |
|
440 |
-
#: src/admin/views/metaboxes/box-option-controls.php:
|
441 |
msgid "Example: "
|
442 |
msgstr ""
|
443 |
|
1 |
+
# Copyright (C) 2019 boxzilla
|
2 |
# This file is distributed under the same license as the boxzilla package.
|
3 |
msgid ""
|
4 |
msgstr ""
|
57 |
msgid "No Boxes found in Trash"
|
58 |
msgstr ""
|
59 |
|
60 |
+
#: src/admin/class-admin.php:97
|
61 |
+
msgid "Duplicate box"
|
62 |
+
msgstr ""
|
63 |
+
|
64 |
+
#: src/admin/class-admin.php:136
|
65 |
msgid "Awesome, you are using Boxzilla! You can now safely <a href=\"%s\">deactivate the Scroll Triggered Boxes plugin</a>."
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: src/admin/class-admin.php:208
|
69 |
msgid "Box ID"
|
70 |
msgstr ""
|
71 |
|
72 |
+
#: src/admin/class-admin.php:211
|
73 |
msgid "Box Title"
|
74 |
msgstr ""
|
75 |
|
76 |
+
#: src/admin/class-admin.php:246, src/admin/class-admin.php:247, src/admin/views/settings.php:7
|
77 |
msgid "Settings"
|
78 |
msgstr ""
|
79 |
|
80 |
+
#: src/admin/class-admin.php:252, src/admin/class-admin.php:253
|
81 |
msgid "Extensions"
|
82 |
msgstr ""
|
83 |
|
84 |
+
#: src/admin/class-admin.php:349, src/admin/views/metaboxes/box-option-controls.php:62
|
85 |
msgid "and"
|
86 |
msgstr ""
|
87 |
|
88 |
+
#: src/admin/class-admin.php:350, src/admin/views/metaboxes/box-option-controls.php:61
|
89 |
msgid "or"
|
90 |
msgstr ""
|
91 |
|
92 |
+
#: src/admin/class-admin.php:351
|
93 |
msgid "Enter a comma-separated list of values."
|
94 |
msgstr ""
|
95 |
|
96 |
+
#: src/admin/class-admin.php:352
|
97 |
msgid "Enter a comma-separated list of post slugs or post ID's.."
|
98 |
msgstr ""
|
99 |
|
100 |
+
#: src/admin/class-admin.php:353
|
101 |
msgid "Enter a comma-separated list of page slugs or page ID's.."
|
102 |
msgstr ""
|
103 |
|
104 |
+
#: src/admin/class-admin.php:354
|
105 |
msgid "Enter a comma-separated list of post types.."
|
106 |
msgstr ""
|
107 |
|
108 |
+
#: src/admin/class-admin.php:355
|
109 |
msgid "Enter a comma-separated list of relative URL's, eg /contact/"
|
110 |
msgstr ""
|
111 |
|
112 |
+
#: src/admin/class-admin.php:386
|
113 |
msgid "Box Appearance"
|
114 |
msgstr ""
|
115 |
|
116 |
+
#: src/admin/class-admin.php:395
|
117 |
msgid "Box Options"
|
118 |
msgstr ""
|
119 |
|
120 |
+
#: src/admin/class-admin.php:404
|
121 |
msgid "Looking for help?"
|
122 |
msgstr ""
|
123 |
|
124 |
+
#: src/admin/class-admin.php:412
|
125 |
msgid "Subscribe to our newsletter"
|
126 |
msgstr ""
|
127 |
|
128 |
+
#: src/admin/class-review-notice.php:79
|
129 |
msgid "You've been using Boxzilla for some time now; we hope you love it!"
|
130 |
msgstr ""
|
131 |
|
132 |
+
#: src/admin/class-review-notice.php:80
|
133 |
msgid "If you do, please <a href=\"%s\">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us."
|
134 |
msgstr ""
|
135 |
|
136 |
+
#: src/admin/class-review-notice.php:82
|
137 |
msgid "Dismiss this notice."
|
138 |
msgstr ""
|
139 |
|
140 |
+
#: src/licensing/class-api.php:172
|
141 |
msgid "The Boxzilla server returned an invalid response."
|
142 |
msgstr ""
|
143 |
|
161 |
msgid "If not, please click here: %s."
|
162 |
msgstr ""
|
163 |
|
164 |
+
#: src/admin/views/settings.php:20, src/admin/views/metaboxes/box-option-controls.php:216
|
165 |
msgid "Enable test mode?"
|
166 |
msgstr ""
|
167 |
|
168 |
+
#: src/admin/views/settings.php:24, src/admin/views/metaboxes/box-option-controls.php:220
|
169 |
msgid "If test mode is enabled, all boxes will show up regardless of whether a cookie has been set."
|
170 |
msgstr ""
|
171 |
|
173 |
msgid "License & Plugin Updates"
|
174 |
msgstr ""
|
175 |
|
176 |
+
#: src/licensing/views/license-form.php:14
|
177 |
msgid "Warning! You are <u>not</u> receiving plugin updates for the following plugin(s):"
|
178 |
msgstr ""
|
179 |
|
180 |
+
#: src/licensing/views/license-form.php:40
|
181 |
msgid "License Key"
|
182 |
msgstr ""
|
183 |
|
184 |
+
#: src/licensing/views/license-form.php:42
|
185 |
msgid "Enter your license key.."
|
186 |
msgstr ""
|
187 |
|
188 |
+
#: src/licensing/views/license-form.php:47
|
189 |
msgid "The license key received when purchasing your premium Boxzilla plan. <a href=\"%s\">You can find it here</a>."
|
190 |
msgstr ""
|
191 |
|
192 |
+
#: src/licensing/views/license-form.php:52
|
193 |
msgid "License Status"
|
194 |
msgstr ""
|
195 |
|
196 |
+
#: src/licensing/views/license-form.php:57
|
197 |
msgid "ACTIVE"
|
198 |
msgstr ""
|
199 |
|
200 |
+
#: src/licensing/views/license-form.php:57
|
201 |
msgid "you are receiving plugin updates"
|
202 |
msgstr ""
|
203 |
|
204 |
+
#: src/licensing/views/license-form.php:61
|
205 |
msgid "INACTIVE"
|
206 |
msgstr ""
|
207 |
|
208 |
+
#: src/licensing/views/license-form.php:61
|
209 |
msgid "you are <strong>not</strong> receiving plugin updates"
|
210 |
msgstr ""
|
211 |
|
301 |
msgid "of the following conditions."
|
302 |
msgstr ""
|
303 |
|
304 |
+
#: src/admin/views/metaboxes/box-option-controls.php:72, src/admin/views/metaboxes/box-option-controls.php:240
|
305 |
msgid "Remove rule"
|
306 |
msgstr ""
|
307 |
|
308 |
+
#: src/admin/views/metaboxes/box-option-controls.php:82, src/admin/views/metaboxes/box-option-controls.php:249
|
309 |
msgid "is"
|
310 |
msgstr ""
|
311 |
|
312 |
+
#: src/admin/views/metaboxes/box-option-controls.php:83, src/admin/views/metaboxes/box-option-controls.php:250
|
313 |
msgid "is not"
|
314 |
msgstr ""
|
315 |
|
316 |
+
#: src/admin/views/metaboxes/box-option-controls.php:84, src/admin/views/metaboxes/box-option-controls.php:251
|
317 |
msgid "contains"
|
318 |
msgstr ""
|
319 |
|
320 |
+
#: src/admin/views/metaboxes/box-option-controls.php:85, src/admin/views/metaboxes/box-option-controls.php:252
|
321 |
msgid "does not contain"
|
322 |
msgstr ""
|
323 |
|
324 |
+
#: src/admin/views/metaboxes/box-option-controls.php:88, src/admin/views/metaboxes/box-option-controls.php:255
|
325 |
msgid "Leave empty for any or enter (comma-separated) names or ID's"
|
326 |
msgstr ""
|
327 |
|
328 |
+
#: src/admin/views/metaboxes/box-option-controls.php:98
|
329 |
msgid "Add another rule"
|
330 |
msgstr ""
|
331 |
|
332 |
+
#: src/admin/views/metaboxes/box-option-controls.php:101
|
333 |
msgid "Box Position"
|
334 |
msgstr ""
|
335 |
|
336 |
+
#: src/admin/views/metaboxes/box-option-controls.php:107
|
337 |
msgid "Top Left"
|
338 |
msgstr ""
|
339 |
|
340 |
+
#: src/admin/views/metaboxes/box-option-controls.php:114
|
341 |
msgid "Top Right"
|
342 |
msgstr ""
|
343 |
|
344 |
+
#: src/admin/views/metaboxes/box-option-controls.php:123
|
345 |
msgid "Center"
|
346 |
msgstr ""
|
347 |
|
348 |
+
#: src/admin/views/metaboxes/box-option-controls.php:132
|
349 |
msgid "Bottom Left"
|
350 |
msgstr ""
|
351 |
|
352 |
+
#: src/admin/views/metaboxes/box-option-controls.php:139
|
353 |
msgid "Bottom Right"
|
354 |
msgstr ""
|
355 |
|
356 |
+
#: src/admin/views/metaboxes/box-option-controls.php:148
|
357 |
msgid "Animation"
|
358 |
msgstr ""
|
359 |
|
360 |
+
#: src/admin/views/metaboxes/box-option-controls.php:150
|
361 |
msgid "Fade In"
|
362 |
msgstr ""
|
363 |
|
364 |
+
#: src/admin/views/metaboxes/box-option-controls.php:151
|
365 |
msgid "Slide In"
|
366 |
msgstr ""
|
367 |
|
368 |
+
#: src/admin/views/metaboxes/box-option-controls.php:152
|
369 |
msgid "Which animation type should be used to show the box when triggered?"
|
370 |
msgstr ""
|
371 |
|
372 |
+
#: src/admin/views/metaboxes/box-option-controls.php:156
|
373 |
msgid "Auto-show box?"
|
374 |
msgstr ""
|
375 |
|
376 |
+
#: src/admin/views/metaboxes/box-option-controls.php:158
|
377 |
msgid "Never"
|
378 |
msgstr ""
|
379 |
|
380 |
+
#: src/admin/views/metaboxes/box-option-controls.php:159
|
381 |
msgid "Yes, after %s seconds on the page."
|
382 |
msgstr ""
|
383 |
|
384 |
+
#: src/admin/views/metaboxes/box-option-controls.php:160
|
385 |
msgid "Yes, when at %s of page height"
|
386 |
msgstr ""
|
387 |
|
388 |
+
#: src/admin/views/metaboxes/box-option-controls.php:161
|
389 |
msgid "Yes, when at element %s"
|
390 |
msgstr ""
|
391 |
|
392 |
+
#: src/admin/views/metaboxes/box-option-controls.php:161
|
393 |
msgid "Example: #comments"
|
394 |
msgstr ""
|
395 |
|
396 |
+
#: src/admin/views/metaboxes/box-option-controls.php:167
|
397 |
msgid "Cookie expiration"
|
398 |
msgstr ""
|
399 |
|
400 |
+
#: src/admin/views/metaboxes/box-option-controls.php:172, src/admin/views/metaboxes/box-option-controls.php:177
|
401 |
msgid "hours"
|
402 |
msgstr ""
|
403 |
|
404 |
+
#: src/admin/views/metaboxes/box-option-controls.php:181
|
405 |
msgid "After this box is triggered or dismissed, how many hours should it stay hidden?"
|
406 |
msgstr ""
|
407 |
|
408 |
+
#: src/admin/views/metaboxes/box-option-controls.php:185
|
409 |
msgid "Screen width"
|
410 |
msgstr ""
|
411 |
|
412 |
+
#: src/admin/views/metaboxes/box-option-controls.php:190
|
413 |
msgid "larger"
|
414 |
msgstr ""
|
415 |
|
416 |
+
#: src/admin/views/metaboxes/box-option-controls.php:190
|
417 |
msgid "smaller"
|
418 |
msgstr ""
|
419 |
|
420 |
+
#: src/admin/views/metaboxes/box-option-controls.php:191
|
421 |
msgid "Only show on screens %s than %s."
|
422 |
msgstr ""
|
423 |
|
424 |
+
#: src/admin/views/metaboxes/box-option-controls.php:192
|
425 |
msgid "Leave empty if you want to show the box on all screen sizes."
|
426 |
msgstr ""
|
427 |
|
428 |
+
#: src/admin/views/metaboxes/box-option-controls.php:197
|
429 |
msgid "Auto-hide?"
|
430 |
msgstr ""
|
431 |
|
432 |
+
#: src/admin/views/metaboxes/box-option-controls.php:201
|
433 |
msgid "Hide box again when visitors scroll back up?"
|
434 |
msgstr ""
|
435 |
|
436 |
+
#: src/admin/views/metaboxes/box-option-controls.php:205
|
437 |
msgid "Show close icon?"
|
438 |
msgstr ""
|
439 |
|
440 |
+
#: src/admin/views/metaboxes/box-option-controls.php:210
|
441 |
msgid "If you decide to hide the close icon, make sure to offer an alternative way to close the box."
|
442 |
msgstr ""
|
443 |
|
444 |
+
#: src/admin/views/metaboxes/box-option-controls.php:211
|
445 |
msgid "Example: "
|
446 |
msgstr ""
|
447 |
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: Ibericode, DvanKooten, hchouhan, lapzor
|
|
3 |
Donate link: https://boxzillaplugin.com/#utm_source=wp-plugin-repo&utm_medium=boxzilla&utm_campaign=donate-link
|
4 |
Tags: scroll triggered box, cta, social, pop-up, newsletter, call to action, mailchimp, contact form 7, social media, mc4wp, ibericode
|
5 |
Requires at least: 4.1
|
6 |
-
Tested up to: 5.
|
7 |
-
Stable tag: 3.2.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
Requires PHP: 5.3
|
@@ -130,6 +130,17 @@ Have a look at the [frequently asked questions](https://wordpress.org/plugins/bo
|
|
130 |
== Changelog ==
|
131 |
|
132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
#### 3.2.9 - December 5, 2018
|
134 |
|
135 |
**Improvements**
|
3 |
Donate link: https://boxzillaplugin.com/#utm_source=wp-plugin-repo&utm_medium=boxzilla&utm_campaign=donate-link
|
4 |
Tags: scroll triggered box, cta, social, pop-up, newsletter, call to action, mailchimp, contact form 7, social media, mc4wp, ibericode
|
5 |
Requires at least: 4.1
|
6 |
+
Tested up to: 5.1
|
7 |
+
Stable tag: 3.2.10
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
Requires PHP: 5.3
|
130 |
== Changelog ==
|
131 |
|
132 |
|
133 |
+
#### 3.2.10 - February 15, 2019
|
134 |
+
|
135 |
+
**Improvements**
|
136 |
+
|
137 |
+
- Better [exit intent detection](https://boxzillaplugin.com/add-ons/exit-intent/) for mobile devices.
|
138 |
+
|
139 |
+
**Additions**
|
140 |
+
|
141 |
+
- New bulk action to quickly duplicate a box with all of its settings.
|
142 |
+
|
143 |
+
|
144 |
#### 3.2.9 - December 5, 2018
|
145 |
|
146 |
**Improvements**
|
src/admin/class-admin.php
CHANGED
@@ -1,763 +1,812 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Boxzilla\Admin;
|
4 |
-
|
5 |
-
use Boxzilla\Plugin
|
6 |
-
|
7 |
-
|
8 |
-
use WP_Post;
|
9 |
-
use WP_Screen;
|
10 |
-
|
11 |
-
class Admin
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Boxzilla\Admin;
|
4 |
+
|
5 |
+
use Boxzilla\Plugin;
|
6 |
+
use Boxzilla\Box;
|
7 |
+
use Boxzilla\Boxzilla;
|
8 |
+
use WP_Post;
|
9 |
+
use WP_Screen;
|
10 |
+
|
11 |
+
class Admin
|
12 |
+
{
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var Plugin $plugin
|
16 |
+
*/
|
17 |
+
private $plugin;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @var Boxzilla
|
21 |
+
*/
|
22 |
+
protected $boxzilla;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var ReviewNotice
|
26 |
+
*/
|
27 |
+
protected $review_notice;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param Plugin $plugin
|
31 |
+
* @param Boxzilla $boxzilla
|
32 |
+
*/
|
33 |
+
public function __construct(Plugin $plugin, Boxzilla $boxzilla)
|
34 |
+
{
|
35 |
+
$this->plugin = $plugin;
|
36 |
+
$this->boxzilla = $boxzilla;
|
37 |
+
$this->review_notice = new ReviewNotice();
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Initialise the all admin related stuff
|
42 |
+
*/
|
43 |
+
public function init()
|
44 |
+
{
|
45 |
+
|
46 |
+
// Load the plugin textdomain
|
47 |
+
load_plugin_textdomain('boxzilla', null, basename($this->plugin->dir()) . '/languages');
|
48 |
+
|
49 |
+
// action hooks
|
50 |
+
$this->add_hooks();
|
51 |
+
$this->run_migrations();
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Add necessary hooks
|
56 |
+
*/
|
57 |
+
protected function add_hooks()
|
58 |
+
{
|
59 |
+
add_action('admin_init', array( $this, 'lazy_add_hooks' ));
|
60 |
+
add_action('admin_init', array( $this, 'register' ));
|
61 |
+
add_action('init', array( $this, 'listen_for_actions' ));
|
62 |
+
add_action('admin_menu', array( $this, 'menu' ));
|
63 |
+
add_action('admin_notices', array( $this, 'notices' ));
|
64 |
+
add_action('save_post_boxzilla-box', array( $this, 'save_box_options' ), 20, 2);
|
65 |
+
add_action('trashed_post', array( $this, 'flush_rules' ));
|
66 |
+
add_action('untrashed_post', array( $this, 'flush_rules' ));
|
67 |
+
add_filter( 'bulk_actions-edit-boxzilla-box', array( $this, 'bulk_action_add') );
|
68 |
+
add_filter( 'handle_bulk_actions-edit-boxzilla-box', array( $this, 'bulk_action_handle' ), 10, 3 );
|
69 |
+
|
70 |
+
$this->review_notice->add_hooks();
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Listen for admin actions.
|
75 |
+
*/
|
76 |
+
public function listen_for_actions()
|
77 |
+
{
|
78 |
+
// triggered?
|
79 |
+
$vars = array_merge($_POST, $_GET);
|
80 |
+
if (empty($vars['_boxzilla_admin_action'])) {
|
81 |
+
return false;
|
82 |
+
}
|
83 |
+
|
84 |
+
// authorized?
|
85 |
+
if (! current_user_can('edit_posts')) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
// fire action
|
90 |
+
$action = $vars['_boxzilla_admin_action'];
|
91 |
+
do_action('boxzilla_admin_' . $action);
|
92 |
+
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
|
96 |
+
public function bulk_action_add( $bulk_actions ) {
|
97 |
+
$bulk_actions['boxzilla_duplicate_box'] = __( 'Duplicate box', 'boxzilla');
|
98 |
+
return $bulk_actions;
|
99 |
+
}
|
100 |
+
|
101 |
+
public function bulk_action_handle( $redirect_to, $doaction, $post_ids ) {
|
102 |
+
if ( $doaction !== 'boxzilla_duplicate_box' || empty( $post_ids )) {
|
103 |
+
return $redirect_to;
|
104 |
+
}
|
105 |
+
|
106 |
+
foreach ($post_ids as $post_id) {
|
107 |
+
$post = get_post($post_id);
|
108 |
+
|
109 |
+
$new_post_id = wp_insert_post(array(
|
110 |
+
'post_type' => $post->post_type,
|
111 |
+
'post_title' => $post->post_title,
|
112 |
+
'post_content' => $post->post_content,
|
113 |
+
'post_status' => 'draft',
|
114 |
+
));
|
115 |
+
|
116 |
+
$options = get_post_meta($post_id, 'boxzilla_options', true);
|
117 |
+
add_post_meta($new_post_id, 'boxzilla_options', $options);
|
118 |
+
}
|
119 |
+
|
120 |
+
return $redirect_to;
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* All logic for admin notices lives here.
|
125 |
+
*/
|
126 |
+
public function notices()
|
127 |
+
{
|
128 |
+
global $pagenow,
|
129 |
+
$current_screen;
|
130 |
+
|
131 |
+
if (($pagenow === 'plugins.php' || ($current_screen && $current_screen->post_type === 'boxzilla-box'))
|
132 |
+
&& current_user_can('install_plugins')
|
133 |
+
&& is_plugin_active('scroll-triggered-boxes/index.php')) {
|
134 |
+
$url = wp_nonce_url('plugins.php?action=deactivate&plugin=scroll-triggered-boxes/index.php', 'deactivate-plugin_' . 'scroll-triggered-boxes/index.php'); ?>
|
135 |
+
<div class="notice notice-info">
|
136 |
+
<p><?php printf(__('Awesome, you are using Boxzilla! You can now safely <a href="%s">deactivate the Scroll Triggered Boxes plugin</a>.', 'boxzilla'), $url); ?></p>
|
137 |
+
</div>
|
138 |
+
<?php
|
139 |
+
}
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Checks current version against stored version & runs necessary update routines.
|
144 |
+
*
|
145 |
+
* @return bool
|
146 |
+
*/
|
147 |
+
protected function run_migrations()
|
148 |
+
{
|
149 |
+
|
150 |
+
// Only run if db option is at older version than code constant
|
151 |
+
$previous_version = get_option('boxzilla_version', '0');
|
152 |
+
$current_version = $this->plugin->version();
|
153 |
+
|
154 |
+
if (version_compare($current_version, $previous_version, '<=')) {
|
155 |
+
return false;
|
156 |
+
}
|
157 |
+
|
158 |
+
$upgrade_routines = new Migrations($previous_version, $current_version, __DIR__ . '/migrations');
|
159 |
+
$upgrade_routines->run();
|
160 |
+
update_option('boxzilla_version', $current_version);
|
161 |
+
}
|
162 |
+
|
163 |
+
public function lazy_add_hooks()
|
164 |
+
{
|
165 |
+
global $pagenow;
|
166 |
+
|
167 |
+
add_action('admin_enqueue_scripts', array( $this, 'load_assets' ));
|
168 |
+
add_action('add_meta_boxes', array( $this, 'add_meta_boxes' ));
|
169 |
+
add_filter('tiny_mce_before_init', array( $this, 'tinymce_init' ));
|
170 |
+
add_filter('manage_edit-boxzilla-box_columns', array( $this, 'post_type_column_titles' ));
|
171 |
+
add_action('manage_boxzilla-box_posts_custom_column', array( $this, 'post_type_column_content' ), 10, 2);
|
172 |
+
add_filter('admin_footer_text', array( $this, 'admin_footer_text' ));
|
173 |
+
|
174 |
+
if ($pagenow === 'plugins.php') {
|
175 |
+
add_filter('plugin_action_links', array( $this, 'add_plugin_settings_link' ), 10, 2);
|
176 |
+
add_filter('plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2);
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* @param $post_id
|
182 |
+
*/
|
183 |
+
public function post_type_column_box_id_content($post_id)
|
184 |
+
{
|
185 |
+
echo $post_id;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* @param $column
|
190 |
+
* @param $post_id
|
191 |
+
*/
|
192 |
+
public function post_type_column_content($column, $post_id)
|
193 |
+
{
|
194 |
+
$method_name = 'post_type_column_' . $column . '_content';
|
195 |
+
if (method_exists($this, $method_name)) {
|
196 |
+
call_user_func(array( $this, $method_name ), $post_id);
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* @param $columns
|
202 |
+
*
|
203 |
+
* @return mixed
|
204 |
+
*/
|
205 |
+
public function post_type_column_titles($columns)
|
206 |
+
{
|
207 |
+
$columns = self::array_insert($columns, array(
|
208 |
+
'box_id' => __('Box ID', 'boxzilla')
|
209 |
+
), 1);
|
210 |
+
|
211 |
+
$columns['title'] = __('Box Title', 'boxzilla');
|
212 |
+
|
213 |
+
return $columns;
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Register stuffs
|
218 |
+
*/
|
219 |
+
public function register()
|
220 |
+
{
|
221 |
+
|
222 |
+
// register settings
|
223 |
+
register_setting('boxzilla_settings', 'boxzilla_settings', array( $this, 'sanitize_settings' ));
|
224 |
+
|
225 |
+
// register scripts
|
226 |
+
$pre_suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
227 |
+
|
228 |
+
wp_register_script('boxzilla-admin', $this->plugin->url('/assets/js/admin-script' . $pre_suffix . '.js'), array(
|
229 |
+
'jquery',
|
230 |
+
'wp-util',
|
231 |
+
'wp-color-picker',
|
232 |
+
'suggest'
|
233 |
+
), $this->plugin->version(), true);
|
234 |
+
|
235 |
+
// load stylesheets
|
236 |
+
wp_register_style('boxzilla-admin', $this->plugin->url('/assets/css/admin-styles' . $pre_suffix . '.css'), array(), $this->plugin->version());
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Renders the STB Menu items
|
241 |
+
*/
|
242 |
+
public function menu()
|
243 |
+
{
|
244 |
+
$menu_items = array(
|
245 |
+
array(
|
246 |
+
__('Settings', 'boxzilla'),
|
247 |
+
__('Settings', 'boxzilla'),
|
248 |
+
'boxzilla-settings',
|
249 |
+
array( $this, 'show_settings_page' )
|
250 |
+
),
|
251 |
+
array(
|
252 |
+
__('Extensions', 'boxzilla'),
|
253 |
+
'<span style="color: orange">' . __('Extensions', 'boxzilla') . '</span>',
|
254 |
+
'boxzilla-extensions',
|
255 |
+
array( $this, 'show_extensions_page' )
|
256 |
+
)
|
257 |
+
);
|
258 |
+
|
259 |
+
$menu_items = apply_filters('boxzilla_admin_menu_items', $menu_items);
|
260 |
+
|
261 |
+
foreach ($menu_items as $item) {
|
262 |
+
add_submenu_page('edit.php?post_type=boxzilla-box', $item[0] . '- Boxzilla', $item[1], 'manage_options', $item[2], $item[3]);
|
263 |
+
}
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Shows the settings page
|
268 |
+
*/
|
269 |
+
public function show_settings_page()
|
270 |
+
{
|
271 |
+
$opts = $this->boxzilla->options;
|
272 |
+
require __DIR__ . '/views/settings.php';
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Shows the extensions page
|
277 |
+
*/
|
278 |
+
public function show_extensions_page()
|
279 |
+
{
|
280 |
+
$extensions = $this->fetch_extensions();
|
281 |
+
require __DIR__ . '/views/extensions.php';
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Are we currently editing a box?
|
286 |
+
*
|
287 |
+
* @return bool
|
288 |
+
*/
|
289 |
+
protected function on_edit_box_page()
|
290 |
+
{
|
291 |
+
global $pagenow;
|
292 |
+
|
293 |
+
if (! in_array($pagenow, array( 'post-new.php', 'post.php' ))) {
|
294 |
+
return false;
|
295 |
+
}
|
296 |
+
|
297 |
+
if (isset($_GET['post_type']) && $_GET['post_type'] === 'boxzilla-box') {
|
298 |
+
return true;
|
299 |
+
}
|
300 |
+
|
301 |
+
if (get_post_type() === 'boxzilla-box') {
|
302 |
+
return true;
|
303 |
+
}
|
304 |
+
|
305 |
+
return false;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* @param $args
|
310 |
+
*
|
311 |
+
* @return mixed
|
312 |
+
*/
|
313 |
+
public function tinymce_init($args)
|
314 |
+
{
|
315 |
+
|
316 |
+
// only act on our post type
|
317 |
+
if (get_post_type() !== 'boxzilla-box') {
|
318 |
+
return $args;
|
319 |
+
}
|
320 |
+
|
321 |
+
$args['setup'] = 'function( editor ) { if(typeof(window.Boxzilla_Admin) === \'undefined\') { return; } editor.on("PreInit", window.Boxzilla_Admin.Designer.init ); }';
|
322 |
+
|
323 |
+
return $args;
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
* Load plugin assets
|
328 |
+
*/
|
329 |
+
public function load_assets()
|
330 |
+
{
|
331 |
+
$screen = get_current_screen();
|
332 |
+
|
333 |
+
if (! $screen instanceof WP_Screen) {
|
334 |
+
return false;
|
335 |
+
}
|
336 |
+
|
337 |
+
if ($screen->base === 'edit' && $screen->post_type === 'boxzilla-box') {
|
338 |
+
wp_enqueue_style('boxzilla-admin');
|
339 |
+
}
|
340 |
+
|
341 |
+
if ($screen->base === 'post' && $screen->post_type === 'boxzilla-box') {
|
342 |
+
// color picker
|
343 |
+
wp_enqueue_style('wp-color-picker');
|
344 |
+
|
345 |
+
// load scripts
|
346 |
+
wp_enqueue_script('boxzilla-admin');
|
347 |
+
|
348 |
+
$data = array(
|
349 |
+
'and' => __('and', 'boxzilla'),
|
350 |
+
'or' => __('or', 'boxzilla'),
|
351 |
+
'enterCommaSeparatedValues' => __('Enter a comma-separated list of values.', 'boxzilla'),
|
352 |
+
'enterCommaSeparatedPosts' => __("Enter a comma-separated list of post slugs or post ID's..", 'boxzilla'),
|
353 |
+
'enterCommaSeparatedPages' => __("Enter a comma-separated list of page slugs or page ID's..", 'boxzilla'),
|
354 |
+
'enterCommaSeparatedPostTypes' => __("Enter a comma-separated list of post types..", 'boxzilla'),
|
355 |
+
'enterCommaSeparatedRelativeUrls' => __("Enter a comma-separated list of relative URL's, eg /contact/", 'boxzilla'),
|
356 |
+
);
|
357 |
+
wp_localize_script('boxzilla-admin', 'boxzilla_i18n', $data);
|
358 |
+
|
359 |
+
// load stylesheets
|
360 |
+
wp_enqueue_style('boxzilla-admin');
|
361 |
+
|
362 |
+
// allow add-ons to easily load their own scripts or stylesheets
|
363 |
+
do_action('boxzilla_load_admin_assets');
|
364 |
+
}
|
365 |
+
|
366 |
+
if (isset($_GET['page']) && $_GET['page'] === 'boxzilla-settings') {
|
367 |
+
wp_enqueue_style('boxzilla-admin');
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Register meta boxes
|
373 |
+
*
|
374 |
+
* @param string $post_type
|
375 |
+
*
|
376 |
+
* @return bool
|
377 |
+
*/
|
378 |
+
public function add_meta_boxes($post_type)
|
379 |
+
{
|
380 |
+
if ($post_type !== 'boxzilla-box') {
|
381 |
+
return false;
|
382 |
+
}
|
383 |
+
|
384 |
+
add_meta_box(
|
385 |
+
'boxzilla-box-appearance-controls',
|
386 |
+
__('Box Appearance', 'boxzilla'),
|
387 |
+
array( $this, 'metabox_box_appearance_controls' ),
|
388 |
+
'boxzilla-box',
|
389 |
+
'normal',
|
390 |
+
'core'
|
391 |
+
);
|
392 |
+
|
393 |
+
add_meta_box(
|
394 |
+
'boxzilla-box-options-controls',
|
395 |
+
__('Box Options', 'boxzilla'),
|
396 |
+
array( $this, 'metabox_box_option_controls' ),
|
397 |
+
'boxzilla-box',
|
398 |
+
'normal',
|
399 |
+
'core'
|
400 |
+
);
|
401 |
+
|
402 |
+
add_meta_box(
|
403 |
+
'boxzilla-support',
|
404 |
+
__('Looking for help?', 'boxzilla'),
|
405 |
+
array( $this, 'metabox_support' ),
|
406 |
+
'boxzilla-box',
|
407 |
+
'side'
|
408 |
+
);
|
409 |
+
|
410 |
+
add_meta_box(
|
411 |
+
'boxzilla-email-optin',
|
412 |
+
__('Subscribe to our newsletter', 'boxzilla'),
|
413 |
+
array( $this, 'metabox_email_optin' ),
|
414 |
+
'boxzilla-box',
|
415 |
+
'side'
|
416 |
+
);
|
417 |
+
|
418 |
+
return true;
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* @param \WP_Post $post
|
423 |
+
* @param $metabox
|
424 |
+
*/
|
425 |
+
public function metabox_box_appearance_controls(\WP_Post $post, $metabox)
|
426 |
+
{
|
427 |
+
|
428 |
+
// get box options
|
429 |
+
$box = new Box($post);
|
430 |
+
$opts = $box->get_options();
|
431 |
+
|
432 |
+
// include view
|
433 |
+
include __DIR__ . '/views/metaboxes/box-appearance-controls.php';
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* @param \WP_Post $post
|
438 |
+
* @param $metabox
|
439 |
+
*/
|
440 |
+
public function metabox_box_option_controls(\WP_Post $post, $metabox)
|
441 |
+
{
|
442 |
+
|
443 |
+
// get box options
|
444 |
+
$box = new Box($post);
|
445 |
+
$opts = $box->get_options();
|
446 |
+
$global_opts = $this->boxzilla->options;
|
447 |
+
|
448 |
+
if (empty($opts['rules'])) {
|
449 |
+
$opts['rules'][] = array( 'condition' => '', 'qualifier' => 1, 'value' => '' );
|
450 |
+
}
|
451 |
+
|
452 |
+
// include view
|
453 |
+
include __DIR__ . '/views/metaboxes/box-option-controls.php';
|
454 |
+
}
|
455 |
+
|
456 |
+
/**
|
457 |
+
* @param \WP_Post $post
|
458 |
+
* @param $metabox
|
459 |
+
*/
|
460 |
+
public function metabox_email_optin(\WP_Post $post, $metabox)
|
461 |
+
{
|
462 |
+
include __DIR__ . '/views/metaboxes/email-optin.php';
|
463 |
+
}
|
464 |
+
|
465 |
+
/**
|
466 |
+
* @param \WP_Post $post
|
467 |
+
* @param $metabox
|
468 |
+
*/
|
469 |
+
public function metabox_support(\WP_Post $post, $metabox)
|
470 |
+
{
|
471 |
+
include __DIR__ . '/views/metaboxes/need-help.php';
|
472 |
+
}
|
473 |
+
|
474 |
+
|
475 |
+
/**
|
476 |
+
* Saves box options and rules
|
477 |
+
*
|
478 |
+
* @param int $box_id
|
479 |
+
*
|
480 |
+
* @return bool
|
481 |
+
*/
|
482 |
+
public function save_box_options($box_id, $post)
|
483 |
+
{
|
484 |
+
|
485 |
+
// Only act on our own post type
|
486 |
+
if ($post->post_type !== 'boxzilla-box') {
|
487 |
+
return false;
|
488 |
+
}
|
489 |
+
|
490 |
+
// is this a revision save?
|
491 |
+
if (wp_is_post_revision($box_id) || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)) {
|
492 |
+
return false;
|
493 |
+
}
|
494 |
+
|
495 |
+
// can user edit this post?
|
496 |
+
if (! current_user_can('edit_post', $box_id)) {
|
497 |
+
return false;
|
498 |
+
}
|
499 |
+
|
500 |
+
// make sure options array is set
|
501 |
+
if (! isset($_POST['boxzilla_box']) || ! is_array($_POST['boxzilla_box'])) {
|
502 |
+
return false;
|
503 |
+
}
|
504 |
+
|
505 |
+
// get new options from $_POST
|
506 |
+
$opts = $this->sanitize_box_options($_POST['boxzilla_box']);
|
507 |
+
|
508 |
+
// allow extensions to filter the saved options
|
509 |
+
$opts = apply_filters('boxzilla_saved_options', $opts, $box_id);
|
510 |
+
|
511 |
+
// save individual box settings
|
512 |
+
update_post_meta($box_id, 'boxzilla_options', $opts);
|
513 |
+
|
514 |
+
// update global settings if given
|
515 |
+
if (! empty($_POST['boxzilla_global_settings'])) {
|
516 |
+
$global_settings = get_option('boxzilla_settings', array());
|
517 |
+
if (! is_array($global_settings)) {
|
518 |
+
$global_settings = array();
|
519 |
+
}
|
520 |
+
$global_settings = array_merge($global_settings, $_POST['boxzilla_global_settings']);
|
521 |
+
update_option('boxzilla_settings', $global_settings);
|
522 |
+
}
|
523 |
+
|
524 |
+
$this->flush_rules($box_id);
|
525 |
+
|
526 |
+
return true;
|
527 |
+
}
|
528 |
+
|
529 |
+
/**
|
530 |
+
* @param array $opts
|
531 |
+
*
|
532 |
+
* @return array
|
533 |
+
*/
|
534 |
+
public function sanitize_settings($opts)
|
535 |
+
{
|
536 |
+
return $opts;
|
537 |
+
}
|
538 |
+
|
539 |
+
/**
|
540 |
+
* @param string $url_string
|
541 |
+
*
|
542 |
+
* @return string
|
543 |
+
*/
|
544 |
+
public function sanitize_url($url_string)
|
545 |
+
{
|
546 |
+
|
547 |
+
// if empty, just return a slash
|
548 |
+
if (empty($url_string)) {
|
549 |
+
return '/';
|
550 |
+
}
|
551 |
+
|
552 |
+
// if string looks like an absolute URL, extract just the path
|
553 |
+
if (preg_match('/^((https|http)?\:\/\/)?(\w+\.)?\w+\.\w+\.*/i', $url_string)) {
|
554 |
+
|
555 |
+
// make sure URL has scheme prepended, to make parse_url() understand..
|
556 |
+
$url_string = 'https://' . str_replace(array( 'http://', 'https://' ), '', $url_string);
|
557 |
+
|
558 |
+
// get just the path
|
559 |
+
$url_string = parse_url($url_string, PHP_URL_PATH);
|
560 |
+
}
|
561 |
+
|
562 |
+
// leading slash it
|
563 |
+
return $url_string;
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* @param array $rule
|
568 |
+
* @return array The sanitized rule array
|
569 |
+
*/
|
570 |
+
public function sanitize_box_rule($rule)
|
571 |
+
{
|
572 |
+
$rule['value'] = trim($rule['value']);
|
573 |
+
|
574 |
+
// convert to array
|
575 |
+
$rule['value'] = explode(',', trim($rule['value'], ','));
|
576 |
+
|
577 |
+
// trim all whitespace in value field
|
578 |
+
$rule['value'] = array_map('trim', $rule['value']);
|
579 |
+
|
580 |
+
// Make sure "is_url" values have a leading slash
|
581 |
+
if ($rule['condition'] === 'is_url') {
|
582 |
+
$rule['value'] = array_map(array( $this, 'sanitize_url' ), $rule['value']);
|
583 |
+
}
|
584 |
+
|
585 |
+
// (re)set value to 0 when condition is everywhere
|
586 |
+
if ($rule['condition'] === 'everywhere') {
|
587 |
+
$rule['value'] = '';
|
588 |
+
}
|
589 |
+
|
590 |
+
// convert back to string before saving
|
591 |
+
if (is_array($rule['value'])) {
|
592 |
+
$rule['value'] = join(',', $rule['value']);
|
593 |
+
}
|
594 |
+
|
595 |
+
return $rule;
|
596 |
+
}
|
597 |
+
|
598 |
+
/**
|
599 |
+
* @param array $css
|
600 |
+
* @return array
|
601 |
+
*/
|
602 |
+
public function sanitize_box_css($css)
|
603 |
+
{
|
604 |
+
|
605 |
+
// sanitize settings
|
606 |
+
if ('' !== $css['width']) {
|
607 |
+
$css['width'] = absint($css['width']);
|
608 |
+
}
|
609 |
+
|
610 |
+
if ('' !== $css['border_width']) {
|
611 |
+
$css['border_width'] = absint($css['border_width']);
|
612 |
+
}
|
613 |
+
|
614 |
+
// make sure colors start with `#`
|
615 |
+
$color_keys = array( 'color', 'background_color', 'border_color' );
|
616 |
+
foreach ($color_keys as $key) {
|
617 |
+
$value = $css[ $key ];
|
618 |
+
$color = sanitize_text_field($value);
|
619 |
+
|
620 |
+
// make sure color starts with `#`
|
621 |
+
if ('' !== $color && $color[0] !== '#') {
|
622 |
+
$color = '#' . $color;
|
623 |
+
}
|
624 |
+
$css[ $key ] = $color;
|
625 |
+
}
|
626 |
+
|
627 |
+
return $css;
|
628 |
+
}
|
629 |
+
|
630 |
+
/**
|
631 |
+
* Sanitize the options for this box.
|
632 |
+
*
|
633 |
+
* @param array $opts
|
634 |
+
*
|
635 |
+
* @return array
|
636 |
+
*/
|
637 |
+
protected function sanitize_box_options($opts)
|
638 |
+
{
|
639 |
+
$defaults = array(
|
640 |
+
'rules' => array(),
|
641 |
+
'css' => array()
|
642 |
+
);
|
643 |
+
|
644 |
+
$opts = array_replace_recursive($defaults, $opts);
|
645 |
+
|
646 |
+
$opts['rules'] = array_map(array( $this, 'sanitize_box_rule' ), $opts['rules']);
|
647 |
+
$opts['css'] = $this->sanitize_box_css($opts['css']);
|
648 |
+
$opts['cookie']['triggered'] = absint($opts['cookie']['triggered']);
|
649 |
+
$opts['cookie']['dismissed'] = absint($opts['cookie']['dismissed']);
|
650 |
+
$opts['trigger'] = sanitize_text_field($opts['trigger']);
|
651 |
+
$opts['trigger_percentage'] = absint($opts['trigger_percentage']);
|
652 |
+
$opts['trigger_element'] = sanitize_text_field($opts['trigger_element']);
|
653 |
+
$opts['screen_size_condition']['value'] = intval($opts['screen_size_condition']['value']);
|
654 |
+
|
655 |
+
return $opts;
|
656 |
+
}
|
657 |
+
|
658 |
+
/**
|
659 |
+
* Add the settings link to the Plugins overview
|
660 |
+
*
|
661 |
+
* @param array $links
|
662 |
+
* @param string $slug
|
663 |
+
*
|
664 |
+
* @return array
|
665 |
+
*/
|
666 |
+
public function add_plugin_settings_link($links, $slug)
|
667 |
+
{
|
668 |
+
if ($slug !== $this->plugin->slug() || ! is_array($links)) {
|
669 |
+
return $links;
|
670 |
+
}
|
671 |
+
|
672 |
+
$settings_link = '<a href="' . admin_url('edit.php?post_type=boxzilla-box') . '">' . __('Boxes') . '</a>';
|
673 |
+
array_unshift($links, $settings_link);
|
674 |
+
|
675 |
+
return $links;
|
676 |
+
}
|
677 |
+
|
678 |
+
/**
|
679 |
+
* Adds meta links to the plugin in the WP Admin > Plugins screen
|
680 |
+
*
|
681 |
+
* @param array $links
|
682 |
+
* @param string $slug
|
683 |
+
*
|
684 |
+
* @return array
|
685 |
+
*/
|
686 |
+
public function add_plugin_meta_links($links, $slug)
|
687 |
+
{
|
688 |
+
if ($slug !== $this->plugin->slug()) {
|
689 |
+
return $links;
|
690 |
+
}
|
691 |
+
|
692 |
+
$links[] = '<a href="https://kb.boxzillaplugin.com/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=plugins-page">Documentation</a>';
|
693 |
+
$links[] = '<a href="https://boxzillaplugin.com/add-ons/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=plugins-page">Add-ons</a>';
|
694 |
+
|
695 |
+
return $links;
|
696 |
+
}
|
697 |
+
|
698 |
+
/**
|
699 |
+
* Flush all box rules
|
700 |
+
*
|
701 |
+
* Loops through all published boxes and fills the rules option
|
702 |
+
*
|
703 |
+
* @param int $post_id
|
704 |
+
*/
|
705 |
+
public function flush_rules($post_id)
|
706 |
+
{
|
707 |
+
|
708 |
+
// only act on our own post type
|
709 |
+
$post = get_post($post_id);
|
710 |
+
if (! $post instanceof WP_Post || $post->post_type !== 'boxzilla-box') {
|
711 |
+
return;
|
712 |
+
}
|
713 |
+
|
714 |
+
// get all published boxes
|
715 |
+
$boxes = get_posts(
|
716 |
+
array(
|
717 |
+
'post_type' => 'boxzilla-box',
|
718 |
+
'post_status' => 'publish',
|
719 |
+
'numberposts' => - 1
|
720 |
+
)
|
721 |
+
);
|
722 |
+
|
723 |
+
// setup empty array of rules
|
724 |
+
$rules = array();
|
725 |
+
|
726 |
+
// fill rules array
|
727 |
+
if (is_array($boxes)) {
|
728 |
+
foreach ($boxes as $box) {
|
729 |
+
// get box meta data
|
730 |
+
$box_meta = get_post_meta($box->ID, 'boxzilla_options', true);
|
731 |
+
|
732 |
+
// add box rules to all rules
|
733 |
+
$rules[ $box->ID ] = $box_meta['rules'];
|
734 |
+
$rules[ $box->ID ]['comparision'] = isset($box_meta['rules_comparision']) ? $box_meta['rules_comparision'] : 'any';
|
735 |
+
}
|
736 |
+
}
|
737 |
+
|
738 |
+
update_option('boxzilla_rules', $rules);
|
739 |
+
}
|
740 |
+
|
741 |
+
/**
|
742 |
+
* Fetches a list of available add-on plugins
|
743 |
+
*
|
744 |
+
* @return array
|
745 |
+
*/
|
746 |
+
protected function fetch_extensions()
|
747 |
+
{
|
748 |
+
$extensions = get_transient('boxzilla_remote_extensions');
|
749 |
+
if ($extensions) {
|
750 |
+
return $extensions;
|
751 |
+
}
|
752 |
+
|
753 |
+
$response = wp_remote_get('https://my.boxzillaplugin.com/api/v2/plugins');
|
754 |
+
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) >= 400) {
|
755 |
+
return array();
|
756 |
+
}
|
757 |
+
|
758 |
+
$body = wp_remote_retrieve_body($response);
|
759 |
+
$data = json_decode($body);
|
760 |
+
if (is_array($data)) {
|
761 |
+
set_transient('boxzilla_remote_extensions', $data, 24 * HOUR_IN_SECONDS);
|
762 |
+
return $data;
|
763 |
+
}
|
764 |
+
|
765 |
+
return array();
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
* @param $arr
|
770 |
+
* @param $insert
|
771 |
+
* @param $position
|
772 |
+
*
|
773 |
+
* @return array
|
774 |
+
*/
|
775 |
+
public static function array_insert($arr, $insert, $position)
|
776 |
+
{
|
777 |
+
$i = 0;
|
778 |
+
$ret = array();
|
779 |
+
foreach ($arr as $key => $value) {
|
780 |
+
if ($i == $position) {
|
781 |
+
foreach ($insert as $ikey => $ivalue) {
|
782 |
+
$ret[ $ikey ] = $ivalue;
|
783 |
+
}
|
784 |
+
}
|
785 |
+
$ret[ $key ] = $value;
|
786 |
+
$i ++;
|
787 |
+
}
|
788 |
+
|
789 |
+
return $ret;
|
790 |
+
}
|
791 |
+
|
792 |
+
/**
|
793 |
+
* @param string $text
|
794 |
+
*
|
795 |
+
* @return string
|
796 |
+
*/
|
797 |
+
public function admin_footer_text($text)
|
798 |
+
{
|
799 |
+
$screen = get_current_screen();
|
800 |
+
|
801 |
+
if (! $screen instanceof WP_Screen) {
|
802 |
+
return $text;
|
803 |
+
}
|
804 |
+
|
805 |
+
$on_edit_page = $screen->parent_base === 'edit' && $screen->post_type === 'boxzilla-box';
|
806 |
+
if ($on_edit_page) {
|
807 |
+
return sprintf('If you enjoy using <strong>Boxzilla</strong>, please <a href="%s" target="_blank">leave us a ★★★★★ rating</a>. A <strong style="text-decoration: underline;">huge</strong> thank you in advance!', 'https://wordpress.org/support/view/plugin-reviews/boxzilla?rate=5#postform');
|
808 |
+
}
|
809 |
+
|
810 |
+
return $text;
|
811 |
+
}
|
812 |
+
}
|
src/admin/class-autocomplete.php
CHANGED
@@ -2,94 +2,100 @@
|
|
2 |
|
3 |
namespace Boxzilla\Filter;
|
4 |
|
5 |
-
class Autocomplete
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
namespace Boxzilla\Filter;
|
4 |
|
5 |
+
class Autocomplete
|
6 |
+
{
|
7 |
+
public function add_hooks()
|
8 |
+
{
|
9 |
+
add_action('wp_ajax_boxzilla_autocomplete', array( $this, 'ajax' ));
|
10 |
+
}
|
11 |
+
|
12 |
+
/**
|
13 |
+
* AJAX listener for autocomplete
|
14 |
+
*/
|
15 |
+
public function ajax()
|
16 |
+
{
|
17 |
+
$q = (isset($_GET['q'])) ? sanitize_text_field($_GET['q']) : '';
|
18 |
+
$type = (isset($_GET['type']) && in_array($_GET['type'], array( 'page', 'post', 'category', 'post_type', 'post_tag' ))) ? $_GET['type'] : 'post';
|
19 |
+
|
20 |
+
// do nothing if supplied 'q' parameter is omitted or empty
|
21 |
+
// or less than 2 characters long
|
22 |
+
if (empty($q) || strlen($q) < 2) {
|
23 |
+
die();
|
24 |
+
}
|
25 |
+
|
26 |
+
switch ($type) {
|
27 |
+
|
28 |
+
default:
|
29 |
+
case 'post':
|
30 |
+
case 'page':
|
31 |
+
echo $this->list_posts($q, $type);
|
32 |
+
break;
|
33 |
+
|
34 |
+
case 'category':
|
35 |
+
echo $this->list_categories($q);
|
36 |
+
break;
|
37 |
+
|
38 |
+
case 'post_type':
|
39 |
+
echo $this->list_post_types($q);
|
40 |
+
break;
|
41 |
+
|
42 |
+
case 'post_tag':
|
43 |
+
echo $this->list_tags($q);
|
44 |
+
break;
|
45 |
+
}
|
46 |
+
|
47 |
+
die();
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @param string $query
|
52 |
+
* @param string $post_type
|
53 |
+
*
|
54 |
+
* @return string
|
55 |
+
*/
|
56 |
+
protected function list_posts($query, $post_type = 'post')
|
57 |
+
{
|
58 |
+
global $wpdb;
|
59 |
+
$sql = $wpdb->prepare("SELECT p.post_name FROM $wpdb->posts p WHERE p.post_type = '%s' AND p.post_status = 'publish' AND ( p.post_title LIKE '%s' OR p.post_name LIKE '%s' ) GROUP BY p.post_name", $post_type, $query . '%%', $query . '%%');
|
60 |
+
$post_slugs = $wpdb->get_col($sql);
|
61 |
+
return join($post_slugs, PHP_EOL);
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param string $query
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
protected function list_categories($query)
|
70 |
+
{
|
71 |
+
$terms = get_terms('category', array( 'name__like' => $query, 'fields' => 'names', 'hide_empty' => false ));
|
72 |
+
return join($terms, PHP_EOL);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @param string $query
|
77 |
+
*
|
78 |
+
* @return string
|
79 |
+
*/
|
80 |
+
protected function list_tags($query)
|
81 |
+
{
|
82 |
+
$terms = get_terms('post_tag', array( 'name__like' => $query, 'fields' => 'names', 'hide_empty' => false ));
|
83 |
+
return join($terms, PHP_EOL);
|
84 |
+
}
|
85 |
+
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param string $query
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
protected function list_post_types($query)
|
93 |
+
{
|
94 |
+
$post_types = get_post_types(array( 'public' => true ), 'names');
|
95 |
+
$matched_post_types = array_filter($post_types, function ($name) use ($query) {
|
96 |
+
return strpos($name, $query) === 0;
|
97 |
+
});
|
98 |
+
|
99 |
+
return join($matched_post_types, PHP_EOL);
|
100 |
+
}
|
101 |
+
}
|
src/admin/class-installer.php
CHANGED
@@ -3,91 +3,96 @@
|
|
3 |
|
4 |
namespace Boxzilla\Admin;
|
5 |
|
6 |
-
class Installer
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
namespace Boxzilla\Admin;
|
5 |
|
6 |
+
class Installer
|
7 |
+
{
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Run the installer
|
11 |
+
*/
|
12 |
+
public static function run()
|
13 |
+
{
|
14 |
+
$installer = new self;
|
15 |
+
$installer->install();
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* The main install method
|
20 |
+
*/
|
21 |
+
public function install()
|
22 |
+
{
|
23 |
+
|
24 |
+
// don't install sample boxes on multisite
|
25 |
+
if (is_multisite()) {
|
26 |
+
return;
|
27 |
+
}
|
28 |
+
|
29 |
+
$this->transfer_from_stb();
|
30 |
+
$this->create_sample_box();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
*
|
35 |
+
*/
|
36 |
+
public function transfer_from_stb()
|
37 |
+
{
|
38 |
+
global $wpdb;
|
39 |
+
|
40 |
+
// transfer post types
|
41 |
+
$query = $wpdb->prepare("UPDATE {$wpdb->posts} SET post_type = %s WHERE post_type = %s", 'boxzilla-box', 'scroll-triggered-box');
|
42 |
+
$wpdb->query($query);
|
43 |
+
|
44 |
+
// transfer post meta
|
45 |
+
$query = $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_key = %s WHERE meta_key = %s", 'boxzilla_options', 'stb_options');
|
46 |
+
$wpdb->query($query);
|
47 |
+
|
48 |
+
// transfer rules
|
49 |
+
$query = $wpdb->prepare("UPDATE {$wpdb->options} SET option_name = %s WHERE option_name = %s", 'boxzilla_rules', 'stb_rules');
|
50 |
+
$wpdb->query($query);
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @return bool
|
55 |
+
*/
|
56 |
+
protected function create_sample_box()
|
57 |
+
{
|
58 |
+
|
59 |
+
// only create sample box if no boxes were found
|
60 |
+
$boxes = get_posts(
|
61 |
+
array(
|
62 |
+
'post_type' => 'boxzilla-box',
|
63 |
+
'post_status' => array( 'publish', 'draft' )
|
64 |
+
)
|
65 |
+
);
|
66 |
+
|
67 |
+
if (! empty($boxes)) {
|
68 |
+
return false;
|
69 |
+
}
|
70 |
+
|
71 |
+
$box_id = wp_insert_post(
|
72 |
+
array(
|
73 |
+
'post_type' => 'boxzilla-box',
|
74 |
+
'post_title' => "Sample Box",
|
75 |
+
'post_content' => "<h4>Hello world.</h4><p>This is a sample box, with some sample content in it.</p>",
|
76 |
+
'post_status' => 'draft',
|
77 |
+
)
|
78 |
+
);
|
79 |
+
|
80 |
+
// set box settings
|
81 |
+
$settings = array(
|
82 |
+
'css' => array(
|
83 |
+
'background_color' => '#edf9ff',
|
84 |
+
'color' => '',
|
85 |
+
'width' => '340',
|
86 |
+
'border_color' => '#dd7575',
|
87 |
+
'border_width' => '4',
|
88 |
+
'border_style' => 'dashed',
|
89 |
+
'position' => 'bottom-right',
|
90 |
+
'manual' => ''
|
91 |
+
)
|
92 |
+
);
|
93 |
+
|
94 |
+
update_post_meta($box_id, 'boxzilla_options', $settings);
|
95 |
+
|
96 |
+
return true;
|
97 |
+
}
|
98 |
+
}
|
src/admin/class-migrations.php
CHANGED
@@ -7,7 +7,8 @@ use Exception;
|
|
7 |
/**
|
8 |
*
|
9 |
*/
|
10 |
-
class Migrations
|
|
|
11 |
|
12 |
/**
|
13 |
* @var float
|
@@ -29,7 +30,8 @@ class Migrations {
|
|
29 |
* @param float $to
|
30 |
* @param string $migrations_dir
|
31 |
*/
|
32 |
-
public function __construct(
|
|
|
33 |
$this->version_from = $from;
|
34 |
$this->version_to = $to;
|
35 |
$this->migrations_dir = $migrations_dir;
|
@@ -38,36 +40,38 @@ class Migrations {
|
|
38 |
/**
|
39 |
* Run the various upgrade routines, all the way up to the latest version
|
40 |
*/
|
41 |
-
public function run()
|
|
|
42 |
$migrations = $this->find_migrations();
|
43 |
// run in sub-function for scope
|
44 |
-
array_map(
|
45 |
}
|
46 |
|
47 |
/**
|
48 |
* @return array
|
49 |
*/
|
50 |
-
public function find_migrations()
|
51 |
-
|
|
|
52 |
$migrations = array();
|
53 |
|
54 |
// return empty array when glob returns non-array value.
|
55 |
-
if(
|
56 |
return $migrations;
|
57 |
}
|
58 |
|
59 |
-
foreach(
|
60 |
-
$migration = basename(
|
61 |
-
$parts = explode(
|
62 |
$version = $parts[0];
|
63 |
|
64 |
// check if migration file is not for an even higher version
|
65 |
-
if(
|
66 |
continue;
|
67 |
}
|
68 |
|
69 |
// check if we ran migration file before.
|
70 |
-
if(
|
71 |
continue;
|
72 |
}
|
73 |
|
@@ -85,12 +89,12 @@ class Migrations {
|
|
85 |
*
|
86 |
* @throws Exception
|
87 |
*/
|
88 |
-
protected function run_migration(
|
89 |
-
|
90 |
-
if(
|
91 |
-
throw new Exception(
|
92 |
}
|
93 |
|
94 |
include $file;
|
95 |
}
|
96 |
-
}
|
7 |
/**
|
8 |
*
|
9 |
*/
|
10 |
+
class Migrations
|
11 |
+
{
|
12 |
|
13 |
/**
|
14 |
* @var float
|
30 |
* @param float $to
|
31 |
* @param string $migrations_dir
|
32 |
*/
|
33 |
+
public function __construct($from, $to, $migrations_dir)
|
34 |
+
{
|
35 |
$this->version_from = $from;
|
36 |
$this->version_to = $to;
|
37 |
$this->migrations_dir = $migrations_dir;
|
40 |
/**
|
41 |
* Run the various upgrade routines, all the way up to the latest version
|
42 |
*/
|
43 |
+
public function run()
|
44 |
+
{
|
45 |
$migrations = $this->find_migrations();
|
46 |
// run in sub-function for scope
|
47 |
+
array_map(array( $this, 'run_migration' ), $migrations);
|
48 |
}
|
49 |
|
50 |
/**
|
51 |
* @return array
|
52 |
*/
|
53 |
+
public function find_migrations()
|
54 |
+
{
|
55 |
+
$files = glob(rtrim($this->migrations_dir, '/') . '/*.php');
|
56 |
$migrations = array();
|
57 |
|
58 |
// return empty array when glob returns non-array value.
|
59 |
+
if (! is_array($files)) {
|
60 |
return $migrations;
|
61 |
}
|
62 |
|
63 |
+
foreach ($files as $file) {
|
64 |
+
$migration = basename($file);
|
65 |
+
$parts = explode('-', $migration);
|
66 |
$version = $parts[0];
|
67 |
|
68 |
// check if migration file is not for an even higher version
|
69 |
+
if (version_compare($version, $this->version_to, '>')) {
|
70 |
continue;
|
71 |
}
|
72 |
|
73 |
// check if we ran migration file before.
|
74 |
+
if (version_compare($this->version_from, $version, '>=')) {
|
75 |
continue;
|
76 |
}
|
77 |
|
89 |
*
|
90 |
* @throws Exception
|
91 |
*/
|
92 |
+
protected function run_migration($file)
|
93 |
+
{
|
94 |
+
if (! file_exists($file)) {
|
95 |
+
throw new Exception("Migration file $file does not exist.");
|
96 |
}
|
97 |
|
98 |
include $file;
|
99 |
}
|
100 |
+
}
|
src/admin/class-notices.php
CHANGED
@@ -2,41 +2,45 @@
|
|
2 |
|
3 |
namespace Boxzilla\Admin;
|
4 |
|
5 |
-
class Notices
|
|
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
30 |
|
31 |
-
|
32 |
-
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
42 |
}
|
2 |
|
3 |
namespace Boxzilla\Admin;
|
4 |
|
5 |
+
class Notices
|
6 |
+
{
|
7 |
|
8 |
+
/**
|
9 |
+
* @var array
|
10 |
+
*/
|
11 |
+
protected $notices = array();
|
12 |
|
13 |
+
/**
|
14 |
+
* Constructor
|
15 |
+
*/
|
16 |
+
public function __construct()
|
17 |
+
{
|
18 |
+
add_action('admin_notices', array( $this, 'show' ));
|
19 |
+
}
|
20 |
|
21 |
+
/**
|
22 |
+
* @param $message
|
23 |
+
* @param $type
|
24 |
+
*
|
25 |
+
* @return $this
|
26 |
+
*/
|
27 |
+
public function add($message, $type = 'updated')
|
28 |
+
{
|
29 |
+
$this->notices[] = array(
|
30 |
+
'message' => $message,
|
31 |
+
'type' => $type,
|
32 |
+
);
|
33 |
|
34 |
+
return $this;
|
35 |
+
}
|
36 |
|
37 |
+
/**
|
38 |
+
* Output the registered notices
|
39 |
+
*/
|
40 |
+
public function show()
|
41 |
+
{
|
42 |
+
foreach ($this->notices as $notice) {
|
43 |
+
echo sprintf('<div class="notice notice-%s"><p>%s</p></div>', $notice['type'], $notice['message']);
|
44 |
+
}
|
45 |
+
}
|
46 |
}
|
src/admin/class-review-notice.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
namespace Boxzilla\Admin;
|
|
|
4 |
use WP_Screen;
|
5 |
|
6 |
/**
|
@@ -8,7 +9,8 @@ use WP_Screen;
|
|
8 |
*
|
9 |
* @ignore
|
10 |
*/
|
11 |
-
class ReviewNotice
|
|
|
12 |
|
13 |
/**
|
14 |
* @var string
|
@@ -18,63 +20,66 @@ class ReviewNotice {
|
|
18 |
/**
|
19 |
* Constructor.
|
20 |
*/
|
21 |
-
public function __construct()
|
22 |
-
|
23 |
}
|
24 |
|
25 |
/**
|
26 |
* Add action & filter hooks.
|
27 |
*/
|
28 |
-
public function add_hooks()
|
29 |
-
|
30 |
-
add_action(
|
|
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
* Set flag in user meta so notice won't be shown.
|
35 |
*/
|
36 |
-
public function dismiss()
|
|
|
37 |
$user = wp_get_current_user();
|
38 |
-
update_user_meta(
|
39 |
}
|
40 |
|
41 |
/**
|
42 |
* @return bool
|
43 |
*/
|
44 |
-
public function show()
|
|
|
45 |
$screen = get_current_screen();
|
46 |
-
if(
|
47 |
return false;
|
48 |
}
|
49 |
|
50 |
// on some boxzilla screen?
|
51 |
-
if(
|
52 |
return false;
|
53 |
}
|
54 |
|
55 |
// authorized?
|
56 |
-
if(
|
57 |
return false;
|
58 |
}
|
59 |
|
60 |
// only show if 2 weeks have passed since first use.
|
61 |
-
$two_weeks_in_seconds = (
|
62 |
-
if(
|
63 |
return false;
|
64 |
}
|
65 |
|
66 |
// only show if user did not dismiss before
|
67 |
$user = wp_get_current_user();
|
68 |
-
if(
|
69 |
return false;
|
70 |
}
|
71 |
|
72 |
echo '<div class="notice notice-info boxzilla-is-dismissible">';
|
73 |
echo '<p>';
|
74 |
-
echo __(
|
75 |
-
echo sprintf(
|
76 |
echo '</p>';
|
77 |
-
echo '<form method="POST"><button type="submit" class="notice-dismiss"><span class="screen-reader-text">'. __(
|
78 |
echo '</div>';
|
79 |
return true;
|
80 |
}
|
@@ -82,15 +87,16 @@ class ReviewNotice {
|
|
82 |
/**
|
83 |
* @return int
|
84 |
*/
|
85 |
-
private function time_since_first_use()
|
86 |
-
|
|
|
87 |
|
88 |
// option was never added before, do it now.
|
89 |
-
if(
|
90 |
$options['first_activated_on'] = time();
|
91 |
-
update_option(
|
92 |
}
|
93 |
|
94 |
return time() - $options['first_activated_on'];
|
95 |
}
|
96 |
-
}
|
1 |
<?php
|
2 |
|
3 |
namespace Boxzilla\Admin;
|
4 |
+
|
5 |
use WP_Screen;
|
6 |
|
7 |
/**
|
9 |
*
|
10 |
* @ignore
|
11 |
*/
|
12 |
+
class ReviewNotice
|
13 |
+
{
|
14 |
|
15 |
/**
|
16 |
* @var string
|
20 |
/**
|
21 |
* Constructor.
|
22 |
*/
|
23 |
+
public function __construct()
|
24 |
+
{
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
* Add action & filter hooks.
|
29 |
*/
|
30 |
+
public function add_hooks()
|
31 |
+
{
|
32 |
+
add_action('admin_notices', array( $this, 'show' ));
|
33 |
+
add_action('boxzilla_admin_dismiss_review_notice', array( $this, 'dismiss' ));
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* Set flag in user meta so notice won't be shown.
|
38 |
*/
|
39 |
+
public function dismiss()
|
40 |
+
{
|
41 |
$user = wp_get_current_user();
|
42 |
+
update_user_meta($user->ID, $this->meta_key_dismissed, 1);
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* @return bool
|
47 |
*/
|
48 |
+
public function show()
|
49 |
+
{
|
50 |
$screen = get_current_screen();
|
51 |
+
if (! $screen instanceof WP_Screen) {
|
52 |
return false;
|
53 |
}
|
54 |
|
55 |
// on some boxzilla screen?
|
56 |
+
if ($screen->post_type !== 'boxzilla-box') {
|
57 |
return false;
|
58 |
}
|
59 |
|
60 |
// authorized?
|
61 |
+
if (! current_user_can('edit_posts')) {
|
62 |
return false;
|
63 |
}
|
64 |
|
65 |
// only show if 2 weeks have passed since first use.
|
66 |
+
$two_weeks_in_seconds = (60 * 60 * 24 * 14);
|
67 |
+
if ($this->time_since_first_use() <= $two_weeks_in_seconds) {
|
68 |
return false;
|
69 |
}
|
70 |
|
71 |
// only show if user did not dismiss before
|
72 |
$user = wp_get_current_user();
|
73 |
+
if (get_user_meta($user->ID, $this->meta_key_dismissed, true)) {
|
74 |
return false;
|
75 |
}
|
76 |
|
77 |
echo '<div class="notice notice-info boxzilla-is-dismissible">';
|
78 |
echo '<p>';
|
79 |
+
echo __('You\'ve been using Boxzilla for some time now; we hope you love it!', 'boxzilla') . ' <br />';
|
80 |
+
echo sprintf(__('If you do, please <a href="%s">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us.', 'boxzilla'), 'https://wordpress.org/support/view/plugin-reviews/boxzilla?rate=5#new-post');
|
81 |
echo '</p>';
|
82 |
+
echo '<form method="POST"><button type="submit" class="notice-dismiss"><span class="screen-reader-text">'. __('Dismiss this notice.', 'boxzilla') .'</span></button><input type="hidden" name="_boxzilla_admin_action" value="dismiss_review_notice"/></form>';
|
83 |
echo '</div>';
|
84 |
return true;
|
85 |
}
|
87 |
/**
|
88 |
* @return int
|
89 |
*/
|
90 |
+
private function time_since_first_use()
|
91 |
+
{
|
92 |
+
$options = get_option('boxzilla_settings');
|
93 |
|
94 |
// option was never added before, do it now.
|
95 |
+
if (empty($options['first_activated_on'])) {
|
96 |
$options['first_activated_on'] = time();
|
97 |
+
update_option('boxzilla_settings', $options);
|
98 |
}
|
99 |
|
100 |
return time() - $options['first_activated_on'];
|
101 |
}
|
102 |
+
}
|
src/admin/migrations/3.1-cookie-option.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
defined(
|
4 |
|
5 |
-
$posts = get_posts(
|
6 |
|
7 |
-
if(
|
8 |
-
foreach(
|
9 |
-
$settings = get_post_meta(
|
10 |
|
11 |
-
if(
|
12 |
continue;
|
13 |
}
|
14 |
|
15 |
// translate from days to hours
|
16 |
-
$new_value = intval(
|
17 |
|
18 |
// store in new location
|
19 |
$settings['cookie'] = array(
|
20 |
'dismissed' => $new_value
|
21 |
);
|
22 |
-
update_post_meta(
|
23 |
}
|
24 |
-
}
|
1 |
<?php
|
2 |
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
|
5 |
+
$posts = get_posts(array( 'post_type' => 'boxzilla-box' ));
|
6 |
|
7 |
+
if (! empty($posts)) {
|
8 |
+
foreach ($posts as $post) {
|
9 |
+
$settings = get_post_meta($post->ID, 'boxzilla_options', true);
|
10 |
|
11 |
+
if (! is_array($settings)) {
|
12 |
continue;
|
13 |
}
|
14 |
|
15 |
// translate from days to hours
|
16 |
+
$new_value = intval($settings['cookie']) * 24;
|
17 |
|
18 |
// store in new location
|
19 |
$settings['cookie'] = array(
|
20 |
'dismissed' => $new_value
|
21 |
);
|
22 |
+
update_post_meta($post->ID, 'boxzilla_options', $settings);
|
23 |
}
|
24 |
+
}
|
src/admin/migrations/3.1.11-screen-width-condition.php
CHANGED
@@ -1,29 +1,29 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
defined(
|
4 |
|
5 |
-
$posts = get_posts(
|
6 |
|
7 |
-
if(
|
8 |
-
foreach(
|
9 |
-
$settings = get_post_meta(
|
10 |
|
11 |
-
if(
|
12 |
continue;
|
13 |
}
|
14 |
|
15 |
-
if(
|
16 |
continue;
|
17 |
}
|
18 |
|
19 |
// set updated option
|
20 |
$settings['screen_size_condition'] = array(
|
21 |
'condition' => 'larger',
|
22 |
-
'value' => intval(
|
23 |
);
|
24 |
|
25 |
-
unset(
|
26 |
|
27 |
-
update_post_meta(
|
28 |
}
|
29 |
-
}
|
1 |
<?php
|
2 |
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
|
5 |
+
$posts = get_posts(array( 'post_type' => 'boxzilla-box' ));
|
6 |
|
7 |
+
if (! empty($posts)) {
|
8 |
+
foreach ($posts as $post) {
|
9 |
+
$settings = get_post_meta($post->ID, 'boxzilla_options', true);
|
10 |
|
11 |
+
if (! is_array($settings)) {
|
12 |
continue;
|
13 |
}
|
14 |
|
15 |
+
if (empty($settings['hide_on_screen_size'])) {
|
16 |
continue;
|
17 |
}
|
18 |
|
19 |
// set updated option
|
20 |
$settings['screen_size_condition'] = array(
|
21 |
'condition' => 'larger',
|
22 |
+
'value' => intval($settings['hide_on_screen_size']),
|
23 |
);
|
24 |
|
25 |
+
unset($settings['hide_on_screen_size']);
|
26 |
|
27 |
+
update_post_meta($post->ID, 'boxzilla_options', $settings);
|
28 |
}
|
29 |
+
}
|
src/admin/views/extensions.php
CHANGED
@@ -1,37 +1,39 @@
|
|
1 |
-
<?php defined(
|
2 |
<div class="wrap" id="boxzilla-admin" class="boxzilla-extensions">
|
3 |
|
4 |
-
<h2><?php _e(
|
5 |
<p>
|
6 |
-
<?php _e(
|
7 |
</p>
|
8 |
<p>
|
9 |
-
<?php printf(
|
10 |
</p>
|
11 |
|
12 |
-
<?php if(
|
13 |
<script>
|
14 |
window.setTimeout( function() {
|
15 |
window.location.href = 'https://boxzillaplugin.com/add-ons/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=extensions-page';
|
16 |
}, 2000 );
|
17 |
</script>
|
18 |
-
<p><?php _e(
|
19 |
-
<p><?php printf(
|
20 |
<?php else : ?>
|
21 |
|
22 |
-
<?php foreach(
|
23 |
<div class="plugin">
|
24 |
-
<a href="<?php echo esc_url(
|
25 |
<div class="caption">
|
26 |
-
<h3><a href="<?php echo esc_url(
|
27 |
-
<p><?php echo esc_html(
|
28 |
<p>
|
29 |
-
<a class="button" href="<?php echo esc_url(
|
30 |
-
<span class="type"
|
31 |
</p>
|
32 |
</div>
|
33 |
</div>
|
34 |
-
<?php if(($i+1) % 4 === 0) {
|
|
|
|
|
35 |
<?php endforeach; ?>
|
36 |
|
37 |
<br style="clear: both;" />
|
1 |
+
<?php defined('ABSPATH') or exit; ?>
|
2 |
<div class="wrap" id="boxzilla-admin" class="boxzilla-extensions">
|
3 |
|
4 |
+
<h2><?php _e('Available Add-On Plugins', 'boxzilla'); ?></h2>
|
5 |
<p>
|
6 |
+
<?php _e("There are various add-ons available for Boxzilla which further enhance the functionality of the core plugin.", 'boxzilla'); ?>
|
7 |
</p>
|
8 |
<p>
|
9 |
+
<?php printf(__('To gain instant access the premium add-on plugins listed here, <a href="%s">have a look at our pricing</a>.', 'boxzilla'), 'https://boxzillaplugin.com/pricing#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=extensions-page'); ?>
|
10 |
</p>
|
11 |
|
12 |
+
<?php if (empty($extensions)) : ?>
|
13 |
<script>
|
14 |
window.setTimeout( function() {
|
15 |
window.location.href = 'https://boxzillaplugin.com/add-ons/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=extensions-page';
|
16 |
}, 2000 );
|
17 |
</script>
|
18 |
+
<p><?php _e('You will be redirected to the Boxzilla site in a few seconds..', 'boxzilla'); ?></p>
|
19 |
+
<p><?php printf(__('If not, please click here: %s.', 'boxzilla'), '<a href="https://boxzillaplugin.com/add-ons/#utm_source=wp-plugin&utm_medium=boxzilla&utm_campaign=extensions-page" target="_blank">View add-on plugins</a>'); ?></p>
|
20 |
<?php else : ?>
|
21 |
|
22 |
+
<?php foreach ($extensions as $i => $plugin) : ?>
|
23 |
<div class="plugin">
|
24 |
+
<a href="<?php echo esc_url($plugin->page_url); ?>" class="unstyled"><img src="<?php echo esc_url($plugin->image_url); ?>" alt="<?php echo $plugin->name; ?>" width="280" height="220"></a>
|
25 |
<div class="caption">
|
26 |
+
<h3><a href="<?php echo esc_url($plugin->page_url); ?>" class="unstyled"><?php echo esc_html($plugin->name); ?></a></h3>
|
27 |
+
<p><?php echo esc_html($plugin->description); ?></p>
|
28 |
<p>
|
29 |
+
<a class="button" href="<?php echo esc_url($plugin->page_url); ?>" title="More about <?php echo esc_attr($plugin->name); ?>">Read More</a>
|
30 |
+
<span class="type">Premium</span>
|
31 |
</p>
|
32 |
</div>
|
33 |
</div>
|
34 |
+
<?php if (($i+1) % 4 === 0) {
|
35 |
+
echo '<div style="clear: both;"></div>';
|
36 |
+
} ?>
|
37 |
<?php endforeach; ?>
|
38 |
|
39 |
<br style="clear: both;" />
|
src/admin/views/metaboxes/box-appearance-controls.php
CHANGED
@@ -1,46 +1,46 @@
|
|
1 |
-
<?php defined(
|
2 |
-
<div id="notice-notinymce" class="error" style="display: none;"><p><?php _e(
|
3 |
|
4 |
<table class="form-table">
|
5 |
-
<?php do_action(
|
6 |
<tr valign="top">
|
7 |
<td>
|
8 |
-
<label class="boxzilla-label" for="boxzilla-background-color"><?php _e(
|
9 |
<input id="boxzilla-background-color" name="boxzilla_box[css][background_color]" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['background_color']); ?>" />
|
10 |
</td>
|
11 |
<td>
|
12 |
-
<label class="boxzilla-label" for="boxzilla-color"><?php _e(
|
13 |
<input id="boxzilla-color" name="boxzilla_box[css][color]" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['color']); ?>" />
|
14 |
</td>
|
15 |
<td>
|
16 |
-
<label class="boxzilla-label" for="boxzilla-width"><?php _e(
|
17 |
<input id="boxzilla-width" name="boxzilla_box[css][width]" id="boxzilla-box-width" min="0" max="3200" type="number" step="1" value="<?php echo esc_attr($opts['css']['width']); ?>" />
|
18 |
-
<p class="help"><?php _e(
|
19 |
</td>
|
20 |
</tr>
|
21 |
<tr valign="top">
|
22 |
<td>
|
23 |
-
<label class="boxzilla-label" for="boxzilla-border-color"><?php _e(
|
24 |
<input name="boxzilla_box[css][border_color]" id="boxzilla-border-color" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['border_color']); ?>" />
|
25 |
</td>
|
26 |
<td>
|
27 |
-
<label class="boxzilla-label" for="boxzilla-border-width"><?php _e(
|
28 |
<input name="boxzilla_box[css][border_width]" id="boxzilla-border-width" type="number" min="0" max="25" step="1" value="<?php echo esc_attr($opts['css']['border_width']); ?>" />
|
29 |
-
<p class="help"><?php _e(
|
30 |
</td>
|
31 |
<td>
|
32 |
-
<label class="boxzilla-label" for="boxzilla-border-style"><?php _e(
|
33 |
<select name="boxzilla_box[css][border_style]" id="boxzilla-border-style">
|
34 |
-
<option value="" <?php selected(
|
35 |
-
<option value="solid" <?php selected(
|
36 |
-
<option value="dashed" <?php selected(
|
37 |
-
<option value="dotted" <?php selected(
|
38 |
-
<option value="double" <?php selected(
|
39 |
</select>
|
40 |
-
<p class="help"><?php _e(
|
41 |
</td>
|
42 |
</tr>
|
43 |
-
<?php do_action(
|
44 |
</table>
|
45 |
|
46 |
-
<p><?php printf(
|
1 |
+
<?php defined('ABSPATH') or exit; ?>
|
2 |
+
<div id="notice-notinymce" class="error" style="display: none;"><p><?php _e('For the best experience when styling your box, please use the default WordPress visual editor.', 'boxzilla'); ?></p></div>
|
3 |
|
4 |
<table class="form-table">
|
5 |
+
<?php do_action('boxzilla_before_box_appearance_controls', $box, $opts); ?>
|
6 |
<tr valign="top">
|
7 |
<td>
|
8 |
+
<label class="boxzilla-label" for="boxzilla-background-color"><?php _e('Background color', 'boxzilla'); ?></label>
|
9 |
<input id="boxzilla-background-color" name="boxzilla_box[css][background_color]" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['background_color']); ?>" />
|
10 |
</td>
|
11 |
<td>
|
12 |
+
<label class="boxzilla-label" for="boxzilla-color"><?php _e('Text color', 'boxzilla'); ?></label>
|
13 |
<input id="boxzilla-color" name="boxzilla_box[css][color]" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['color']); ?>" />
|
14 |
</td>
|
15 |
<td>
|
16 |
+
<label class="boxzilla-label" for="boxzilla-width"><?php _e('Box width', 'boxzilla'); ?></label>
|
17 |
<input id="boxzilla-width" name="boxzilla_box[css][width]" id="boxzilla-box-width" min="0" max="3200" type="number" step="1" value="<?php echo esc_attr($opts['css']['width']); ?>" />
|
18 |
+
<p class="help"><?php _e('Width in px', 'boxzilla'); ?></p>
|
19 |
</td>
|
20 |
</tr>
|
21 |
<tr valign="top">
|
22 |
<td>
|
23 |
+
<label class="boxzilla-label" for="boxzilla-border-color"><?php _e('Border color', 'boxzilla'); ?></label>
|
24 |
<input name="boxzilla_box[css][border_color]" id="boxzilla-border-color" type="text" class="boxzilla-color-field" value="<?php echo esc_attr($opts['css']['border_color']); ?>" />
|
25 |
</td>
|
26 |
<td>
|
27 |
+
<label class="boxzilla-label" for="boxzilla-border-width"><?php _e('Border width', 'boxzilla'); ?></label>
|
28 |
<input name="boxzilla_box[css][border_width]" id="boxzilla-border-width" type="number" min="0" max="25" step="1" value="<?php echo esc_attr($opts['css']['border_width']); ?>" />
|
29 |
+
<p class="help"><?php _e('Width in px', 'boxzilla'); ?></p>
|
30 |
</td>
|
31 |
<td>
|
32 |
+
<label class="boxzilla-label" for="boxzilla-border-style"><?php _e('Border style', 'boxzilla'); ?></label>
|
33 |
<select name="boxzilla_box[css][border_style]" id="boxzilla-border-style">
|
34 |
+
<option value="" <?php selected($opts['css']['border_style'], ''); ?>><?php _e('Default', 'boxzilla-theme-pack'); ?></option>
|
35 |
+
<option value="solid" <?php selected($opts['css']['border_style'], 'solid'); ?>><?php _e('Solid', 'boxzilla-theme-pack'); ?></option>
|
36 |
+
<option value="dashed" <?php selected($opts['css']['border_style'], 'dashed'); ?>><?php _e('Dashed', 'boxzilla-theme-pack'); ?></option>
|
37 |
+
<option value="dotted" <?php selected($opts['css']['border_style'], 'dotted'); ?>><?php _e('Dotted', 'boxzilla-theme-pack'); ?></option>
|
38 |
+
<option value="double" <?php selected($opts['css']['border_style'], 'double'); ?>><?php _e('Double', 'boxzilla-theme-pack'); ?></option>
|
39 |
</select>
|
40 |
+
<p class="help"><?php _e('Border style', 'boxzilla'); ?></p>
|
41 |
</td>
|
42 |
</tr>
|
43 |
+
<?php do_action('boxzilla_after_box_appearance_controls', $box, $opts); ?>
|
44 |
</table>
|
45 |
|
46 |
+
<p><?php printf(__('<a href="%s">Click here to reset all styling settings</a>.', 'boxzilla'), 'javascript:Boxzilla_Admin.Designer.resetStyles();'); ?></p>
|
src/admin/views/metaboxes/box-option-controls.php
CHANGED
@@ -1,228 +1,231 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined(
|
4 |
-
|
5 |
-
/** @var \Boxzilla\Box $box */
|
6 |
-
/** @var array $opts */
|
7 |
-
/** @var array $global_opts */
|
8 |
-
|
9 |
-
/** @var array $rule_options */
|
10 |
-
$rule_options = array(
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
'is_user_logged_in' => __(
|
20 |
-
);
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @ignore
|
24 |
-
*/
|
25 |
-
$rule_options = apply_filters(
|
26 |
-
|
27 |
?>
|
28 |
<table class="form-table">
|
29 |
-
<?php
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
<tr>
|
38 |
-
<th><?php _e(
|
39 |
<td>
|
40 |
<label>
|
41 |
-
<?php _e(
|
42 |
<select name="boxzilla_box[rules_comparision]" id="boxzilla-rule-comparison">
|
43 |
-
<option value="any" <?php selected(
|
44 |
-
<option value="all" <?php selected(
|
45 |
</select>
|
46 |
-
<?php _e(
|
47 |
</label>
|
48 |
</td>
|
49 |
</tr>
|
50 |
<tbody id="boxzilla-box-rules">
|
51 |
-
<?php
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
69 |
<tr valign="top" class="boxzilla-rule-row boxzilla-rule-row-<?php echo $key; ?>">
|
70 |
<th style="text-align: right; font-weight: normal;">
|
71 |
-
<span class="boxzilla-close boxzilla-remove-rule" title="<?php esc_attr_e(
|
72 |
</th>
|
73 |
<td>
|
74 |
<select class="boxzilla-rule-condition" name="boxzilla_box[rules][<?php echo $key; ?>][condition]">
|
75 |
-
<?php foreach(
|
76 |
-
|
77 |
-
|
78 |
</select>
|
79 |
|
80 |
<select class="boxzilla-rule-qualifier" name="boxzilla_box[rules][<?php echo $key; ?>][qualifier]" style="min-width: 135px;">
|
81 |
-
<option value="1" <?php selected(
|
82 |
-
<option value="0" <?php selected(
|
83 |
-
<option value="contains" <?php selected(
|
84 |
-
<option value="not_contains" <?php selected(
|
85 |
</select>
|
86 |
|
87 |
-
<input class="boxzilla-rule-value regular-text" name="boxzilla_box[rules][<?php echo $key; ?>][value]" type="text" value="<?php echo esc_attr(
|
|
|
|
|
88 |
</td>
|
89 |
</tr>
|
90 |
-
<?php $key++;
|
91 |
-
|
92 |
</tbody>
|
93 |
<tr>
|
94 |
<th></th>
|
95 |
-
<td><button type="button" class="button boxzilla-add-rule"><?php _e(
|
96 |
</tr>
|
97 |
<tr valign="top">
|
98 |
-
<th><label for="boxzilla_position"><?php _e(
|
99 |
<td>
|
100 |
<table class="window-positions">
|
101 |
<tr>
|
102 |
<td>
|
103 |
-
<?php
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
</td>
|
108 |
<td></td>
|
109 |
<td>
|
110 |
-
<?php
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
</td>
|
115 |
</tr>
|
116 |
<tr>
|
117 |
<td></td>
|
118 |
<td>
|
119 |
-
<?php
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
</td>
|
124 |
<td></td>
|
125 |
</tr>
|
126 |
<tr>
|
127 |
<td>
|
128 |
-
<?php
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
</td>
|
133 |
<td></td>
|
134 |
<td>
|
135 |
-
<?php
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
</td>
|
140 |
</tr>
|
141 |
</table>
|
142 |
</td>
|
143 |
</tr>
|
144 |
<tr valign="top">
|
145 |
-
<th><label><?php _e(
|
146 |
<td>
|
147 |
-
<label><input type="radio" name="boxzilla_box[animation]" value="fade" <?php checked($opts['animation'], 'fade'); ?> /> <?php _e(
|
148 |
-
<label><input type="radio" name="boxzilla_box[animation]" value="slide" <?php checked($opts['animation'], 'slide'); ?> /> <?php _e(
|
149 |
-
<p class="help"><?php _e(
|
150 |
</td>
|
151 |
</tr>
|
152 |
<tr valign="top">
|
153 |
-
<th><label for="boxzilla_trigger"><?php _e(
|
154 |
<td>
|
155 |
-
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="" <?php checked(
|
156 |
-
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="time_on_page" <?php checked(
|
157 |
-
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="percentage" <?php checked(
|
158 |
-
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="element" <?php checked(
|
159 |
-
<?php do_action(
|
160 |
</td>
|
161 |
</tr>
|
162 |
-
<tbody class="boxzilla-trigger-options" style="display: <?php echo (
|
163 |
<tr valign="top">
|
164 |
-
<th><label for="boxzilla_cookie"><?php _e(
|
165 |
<td>
|
166 |
<div style="display: inline-block; margin-right: 20px;">
|
167 |
-
<label for="boxzilla_cookie_triggered" style="font-weight: bold; display: block;"><?php esc_html_e(
|
168 |
<input type="number" id="boxzilla_cookie_triggered" name="boxzilla_box[cookie][triggered]" min="0" step="1" value="<?php echo esc_attr($opts['cookie']['triggered']); ?>" />
|
169 |
-
<small><?php _e(
|
170 |
</div>
|
171 |
<div style="display: inline-block;">
|
172 |
-
<label for="boxzilla_cookie_dismissed" style="font-weight: bold; display: block;"><?php esc_html_e(
|
173 |
<input type="number" id="boxzilla_cookie_dismissed" name="boxzilla_box[cookie][dismissed]" min="0" step="1" value="<?php echo esc_attr($opts['cookie']['dismissed']); ?>" />
|
174 |
-
<small><?php _e(
|
175 |
</div>
|
176 |
<br />
|
177 |
|
178 |
-
<p class="help"><?php _e(
|
179 |
</td>
|
180 |
</tr>
|
181 |
<tr valign="top">
|
182 |
-
<th><label><?php _e(
|
183 |
<td>
|
184 |
-
<?php
|
185 |
-
$condition_type = $opts['screen_size_condition']['condition'];
|
186 |
-
$condition_value = $opts['screen_size_condition']['value'];
|
187 |
-
$condition_select = '<select name="boxzilla_box[screen_size_condition][condition]"><option value="larger" '. (
|
188 |
-
<p><?php printf(
|
189 |
-
<p class="help"><?php _e(
|
190 |
</td>
|
191 |
|
192 |
</tr>
|
193 |
<tr valign="top">
|
194 |
-
<th><label for="boxzilla_auto_hide"><?php _e(
|
195 |
<td>
|
196 |
-
<label><input type="radio" name="boxzilla_box[auto_hide]" value="1" <?php checked(
|
197 |
-
<label><input type="radio" name="boxzilla_box[auto_hide]" value="0" <?php checked(
|
198 |
-
<p class="help"><?php _e(
|
199 |
</td>
|
200 |
</tr>
|
201 |
<tr valign="top">
|
202 |
-
<th><label for="boxzilla_closable"><?php _e(
|
203 |
<td>
|
204 |
-
<label><input type="radio" id="boxzilla_closable_1" name="boxzilla_box[show_close_icon]" value="1" <?php checked(
|
205 |
-
<label><input type="radio" id="boxzilla_closable_0" name="boxzilla_box[show_close_icon]" value="0" <?php checked(
|
206 |
<p class="help">
|
207 |
-
<?php _e(
|
208 |
-
<?php _e
|
209 |
</p>
|
210 |
</td>
|
211 |
</tr>
|
212 |
<tr valign="top">
|
213 |
-
<th><label for="boxzilla_test_mode"><?php _e(
|
214 |
<td>
|
215 |
-
<label><input type="radio" id="boxzilla_test_mode_1" name="boxzilla_global_settings[test_mode]" value="1" <?php checked(
|
216 |
-
<label><input type="radio" id="boxzilla_test_mode_0" name="boxzilla_global_settings[test_mode]" value="0" <?php checked(
|
217 |
-
<p class="help"><?php _e(
|
218 |
</td>
|
219 |
</tr>
|
220 |
-
<?php
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
</tbody>
|
227 |
</table>
|
228 |
|
@@ -234,22 +237,22 @@ $rule_options = apply_filters( 'boxzilla_rules_options', $rule_options );
|
|
234 |
</tr>
|
235 |
<tr valign="top" class="boxzilla-rule-row boxzilla-rule-row-{{{data.key}}}">
|
236 |
<th style="text-align: right; font-weight: normal;">
|
237 |
-
<span class="boxzilla-close boxzilla-remove-rule" title="<?php esc_attr_e(
|
238 |
</th>
|
239 |
<td class="boxzilla-sm">
|
240 |
<select class="boxzilla-rule-condition" name="boxzilla_box[rules][{{{data.key}}}][condition]">
|
241 |
-
<?php foreach(
|
242 |
-
|
243 |
-
|
244 |
</select>
|
245 |
<select class="boxzilla-rule-qualifier" name="boxzilla_box[rules][{{{data.key}}}][qualifier]" style="display: none; min-width: 135px;" >
|
246 |
-
<option value="1" selected><?php _e(
|
247 |
-
<option value="0"><?php _e(
|
248 |
-
<option value="contains" style="display: none;"><?php _e(
|
249 |
-
<option value="not_contains" style="display: none;"><?php _e(
|
250 |
</select>
|
251 |
|
252 |
-
<input class="boxzilla-rule-value regular-text" name="boxzilla_box[rules][{{{data.key}}}][value]" type="text" value="" placeholder="<?php _e(
|
253 |
</td>
|
254 |
</tr>
|
255 |
</script>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
+
|
5 |
+
/** @var \Boxzilla\Box $box */
|
6 |
+
/** @var array $opts */
|
7 |
+
/** @var array $global_opts */
|
8 |
+
|
9 |
+
/** @var array $rule_options */
|
10 |
+
$rule_options = array(
|
11 |
+
'everywhere' => __('everywhere', 'boxzilla'),
|
12 |
+
'is_page' => __('if page', 'boxzilla'),
|
13 |
+
'is_single' => __('if post', 'boxzilla'),
|
14 |
+
'is_post_with_tag' => __('if post tag', 'boxzilla'),
|
15 |
+
'is_post_in_category' => __('if post category', 'boxzilla'),
|
16 |
+
'is_post_type' => __('if post type', 'boxzilla'),
|
17 |
+
'is_url' => __('if URL', 'boxzilla'),
|
18 |
+
'is_referer' => __('if referer', 'boxzilla'),
|
19 |
+
'is_user_logged_in' => __('if user', 'boxzilla'),
|
20 |
+
);
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @ignore
|
24 |
+
*/
|
25 |
+
$rule_options = apply_filters('boxzilla_rules_options', $rule_options);
|
26 |
+
|
27 |
?>
|
28 |
<table class="form-table">
|
29 |
+
<?php
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @ignore
|
33 |
+
*/
|
34 |
+
do_action('boxzilla_before_box_option_controls', $box, $opts);
|
35 |
+
|
36 |
+
?>
|
37 |
<tr>
|
38 |
+
<th><?php _e('Load this box if', 'boxzilla'); ?></th>
|
39 |
<td>
|
40 |
<label>
|
41 |
+
<?php _e('Request matches', 'boxzilla'); ?>
|
42 |
<select name="boxzilla_box[rules_comparision]" id="boxzilla-rule-comparison">
|
43 |
+
<option value="any" <?php selected($opts['rules_comparision'], 'any'); ?>><?php _e('any', 'boxzilla'); ?></option>
|
44 |
+
<option value="all" <?php selected($opts['rules_comparision'], 'all'); ?>><?php _e('all', 'boxzilla'); ?></option>
|
45 |
</select>
|
46 |
+
<?php _e('of the following conditions.', 'boxzilla'); ?>
|
47 |
</label>
|
48 |
</td>
|
49 |
</tr>
|
50 |
<tbody id="boxzilla-box-rules">
|
51 |
+
<?php
|
52 |
+
$key = 0;
|
53 |
+
foreach ($opts['rules'] as $rule) {
|
54 |
+
// skip invalid looking rules
|
55 |
+
if (! array_key_exists('condition', $rule)) {
|
56 |
+
continue;
|
57 |
+
}
|
58 |
+
|
59 |
+
// output row showing "and" or "or" between rules
|
60 |
+
if ($key > 0) {
|
61 |
+
$or = __('or', 'boxzilla');
|
62 |
+
$and = __('and', 'boxzilla');
|
63 |
+
$text = $opts['rules_comparision'] === 'any' ? $or : $and;
|
64 |
+
|
65 |
+
echo '<tr>';
|
66 |
+
echo '<th class="boxzilla-no-vpadding"></th>';
|
67 |
+
echo '<td class="boxzilla-no-vpadding"><span class="boxzilla-andor boxzilla-muted">' . $text . '</span></td>';
|
68 |
+
echo '</tr>';
|
69 |
+
} ?>
|
70 |
<tr valign="top" class="boxzilla-rule-row boxzilla-rule-row-<?php echo $key; ?>">
|
71 |
<th style="text-align: right; font-weight: normal;">
|
72 |
+
<span class="boxzilla-close boxzilla-remove-rule" title="<?php esc_attr_e('Remove rule', 'boxzilla'); ?>"><span class="dashicons dashicons-dismiss"></span></span>
|
73 |
</th>
|
74 |
<td>
|
75 |
<select class="boxzilla-rule-condition" name="boxzilla_box[rules][<?php echo $key; ?>][condition]">
|
76 |
+
<?php foreach ($rule_options as $value => $label) {
|
77 |
+
printf('<option value="%s" %s>%s</option>', $value, selected($rule['condition'], $value), $label);
|
78 |
+
} ?>
|
79 |
</select>
|
80 |
|
81 |
<select class="boxzilla-rule-qualifier" name="boxzilla_box[rules][<?php echo $key; ?>][qualifier]" style="min-width: 135px;">
|
82 |
+
<option value="1" <?php selected(! isset($rule['qualifier']) || $rule['qualifier']); ?>><?php _e('is', 'boxzilla'); ?></option>
|
83 |
+
<option value="0" <?php selected(isset($rule['qualifier']) && !$rule['qualifier']); ?>><?php _e('is not', 'boxzilla'); ?></option>
|
84 |
+
<option value="contains" <?php selected(isset($rule['qualifier']) && $rule['qualifier'] === 'contains'); ?> style="display: none;"><?php _e('contains', 'boxzilla'); ?>
|
85 |
+
<option value="not_contains" <?php selected(isset($rule['qualifier']) && $rule['qualifier'] === 'not_contains'); ?> style="display: none;"><?php _e('does not contain', 'boxzilla'); ?></option>
|
86 |
</select>
|
87 |
|
88 |
+
<input class="boxzilla-rule-value regular-text" name="boxzilla_box[rules][<?php echo $key; ?>][value]" type="text" value="<?php echo esc_attr($rule['value']); ?>" placeholder="<?php _e('Leave empty for any or enter (comma-separated) names or ID\'s', 'boxzilla'); ?>" style="<?php if (in_array($rule['condition'], array( '', 'everywhere' ))) {
|
89 |
+
echo 'display: none;';
|
90 |
+
} ?>" />
|
91 |
</td>
|
92 |
</tr>
|
93 |
+
<?php $key++;
|
94 |
+
} ?>
|
95 |
</tbody>
|
96 |
<tr>
|
97 |
<th></th>
|
98 |
+
<td><button type="button" class="button boxzilla-add-rule"><?php _e('Add another rule', 'boxzilla'); ?></button></td>
|
99 |
</tr>
|
100 |
<tr valign="top">
|
101 |
+
<th><label for="boxzilla_position"><?php _e('Box Position', 'boxzilla'); ?></label></th>
|
102 |
<td>
|
103 |
<table class="window-positions">
|
104 |
<tr>
|
105 |
<td>
|
106 |
+
<?php
|
107 |
+
$value = 'top-left'; $label = __('Top Left', 'boxzilla');
|
108 |
+
printf('<label><input type="radio" name="boxzilla_box[css][position]" value="%s" %s> %s</label>', $value, checked($opts['css']['position'], $value, false), $label);
|
109 |
+
?>
|
110 |
</td>
|
111 |
<td></td>
|
112 |
<td>
|
113 |
+
<?php
|
114 |
+
$value = 'top-right'; $label = __('Top Right', 'boxzilla');
|
115 |
+
printf('<label><input type="radio" name="boxzilla_box[css][position]" value="%s" %s> %s</label>', $value, checked($opts['css']['position'], $value, false), $label);
|
116 |
+
?>
|
117 |
</td>
|
118 |
</tr>
|
119 |
<tr>
|
120 |
<td></td>
|
121 |
<td>
|
122 |
+
<?php
|
123 |
+
$value = 'center'; $label = __('Center', 'boxzilla');
|
124 |
+
printf('<label><input type="radio" name="boxzilla_box[css][position]" value="%s" %s> %s</label>', $value, checked($opts['css']['position'], $value, false), $label);
|
125 |
+
?>
|
126 |
</td>
|
127 |
<td></td>
|
128 |
</tr>
|
129 |
<tr>
|
130 |
<td>
|
131 |
+
<?php
|
132 |
+
$value = 'bottom-left'; $label = __('Bottom Left', 'boxzilla');
|
133 |
+
printf('<label><input type="radio" name="boxzilla_box[css][position]" value="%s" %s> %s</label>', $value, checked($opts['css']['position'], $value, false), $label);
|
134 |
+
?>
|
135 |
</td>
|
136 |
<td></td>
|
137 |
<td>
|
138 |
+
<?php
|
139 |
+
$value = 'bottom-right'; $label = __('Bottom Right', 'boxzilla');
|
140 |
+
printf('<label><input type="radio" name="boxzilla_box[css][position]" value="%s" %s> %s</label>', $value, checked($opts['css']['position'], $value, false), $label);
|
141 |
+
?>
|
142 |
</td>
|
143 |
</tr>
|
144 |
</table>
|
145 |
</td>
|
146 |
</tr>
|
147 |
<tr valign="top">
|
148 |
+
<th><label><?php _e('Animation', 'boxzilla'); ?></label></th>
|
149 |
<td>
|
150 |
+
<label><input type="radio" name="boxzilla_box[animation]" value="fade" <?php checked($opts['animation'], 'fade'); ?> /> <?php _e('Fade In', 'boxzilla'); ?></label>
|
151 |
+
<label><input type="radio" name="boxzilla_box[animation]" value="slide" <?php checked($opts['animation'], 'slide'); ?> /> <?php _e('Slide In', 'boxzilla'); ?></label>
|
152 |
+
<p class="help"><?php _e('Which animation type should be used to show the box when triggered?', 'boxzilla'); ?></p>
|
153 |
</td>
|
154 |
</tr>
|
155 |
<tr valign="top">
|
156 |
+
<th><label for="boxzilla_trigger"><?php _e('Auto-show box?', 'boxzilla'); ?></label></th>
|
157 |
<td>
|
158 |
+
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="" <?php checked($opts['trigger'], ''); ?> /> <?php _e('Never', 'boxzilla'); ?></label><br />
|
159 |
+
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="time_on_page" <?php checked($opts['trigger'], 'time_on_page'); ?> /> <?php printf(__('Yes, after %s seconds on the page.', 'boxzilla'), '<input type="number" name="boxzilla_box[trigger_time_on_page]" min="0" value="' . esc_attr($opts['trigger_time_on_page']) . '" />'); ?></label><br />
|
160 |
+
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="percentage" <?php checked($opts['trigger'], 'percentage'); ?> /> <?php printf(__('Yes, when at %s of page height', 'boxzilla'), '<input type="number" name="boxzilla_box[trigger_percentage]" min="0" max="100" value="' . esc_attr($opts['trigger_percentage']) . '" />%'); ?></label><br />
|
161 |
+
<label><input type="radio" class="boxzilla-auto-show-trigger" name="boxzilla_box[trigger]" value="element" <?php checked($opts['trigger'], 'element'); ?> /> <?php printf(__('Yes, when at element %s', 'boxzilla'), '<input type="text" name="boxzilla_box[trigger_element]" value="' . esc_attr($opts['trigger_element']) . '" placeholder="' . __('Example: #comments', 'boxzilla') .'" />'); ?></label><br />
|
162 |
+
<?php do_action('boxzilla_output_auto_show_trigger_options', $opts); ?>
|
163 |
</td>
|
164 |
</tr>
|
165 |
+
<tbody class="boxzilla-trigger-options" style="display: <?php echo ($opts['trigger'] === '') ? 'none' : 'table-row-group'; ?>;">
|
166 |
<tr valign="top">
|
167 |
+
<th><label for="boxzilla_cookie"><?php _e('Cookie expiration', 'boxzilla'); ?></label></th>
|
168 |
<td>
|
169 |
<div style="display: inline-block; margin-right: 20px;">
|
170 |
+
<label for="boxzilla_cookie_triggered" style="font-weight: bold; display: block;"><?php esc_html_e('Triggered', 'mailchimp-for-wp'); ?></label>
|
171 |
<input type="number" id="boxzilla_cookie_triggered" name="boxzilla_box[cookie][triggered]" min="0" step="1" value="<?php echo esc_attr($opts['cookie']['triggered']); ?>" />
|
172 |
+
<small><?php _e('hours', 'boxzilla'); ?></small>
|
173 |
</div>
|
174 |
<div style="display: inline-block;">
|
175 |
+
<label for="boxzilla_cookie_dismissed" style="font-weight: bold; display: block;"><?php esc_html_e('Dismissed', 'mailchimp-for-wp'); ?></label>
|
176 |
<input type="number" id="boxzilla_cookie_dismissed" name="boxzilla_box[cookie][dismissed]" min="0" step="1" value="<?php echo esc_attr($opts['cookie']['dismissed']); ?>" />
|
177 |
+
<small><?php _e('hours', 'boxzilla'); ?></small>
|
178 |
</div>
|
179 |
<br />
|
180 |
|
181 |
+
<p class="help"><?php _e('After this box is triggered or dismissed, how many hours should it stay hidden?', 'boxzilla'); ?></p>
|
182 |
</td>
|
183 |
</tr>
|
184 |
<tr valign="top">
|
185 |
+
<th><label><?php _e('Screen width', 'boxzilla'); ?></label></th>
|
186 |
<td>
|
187 |
+
<?php
|
188 |
+
$condition_type = $opts['screen_size_condition']['condition'];
|
189 |
+
$condition_value = $opts['screen_size_condition']['value'];
|
190 |
+
$condition_select = '<select name="boxzilla_box[screen_size_condition][condition]"><option value="larger" '. ($condition_type === 'larger' ? 'selected' : '') .'>' . __('larger', 'boxzilla') . '</option><option value="smaller" '. ($condition_type === 'smaller' ? 'selected' : '') .'>' . __('smaller', 'boxzilla') . '</option></select>'; ?>
|
191 |
+
<p><?php printf(__('Only show on screens %s than %s.', 'boxzilla'), $condition_select, '<input type="number" min="0" name="boxzilla_box[screen_size_condition][value]" value="' . esc_attr($condition_value) . '" style="max-width: 70px;" />px'); ?></p>
|
192 |
+
<p class="help"><?php _e('Leave empty if you want to show the box on all screen sizes.', 'boxzilla'); ?></p>
|
193 |
</td>
|
194 |
|
195 |
</tr>
|
196 |
<tr valign="top">
|
197 |
+
<th><label for="boxzilla_auto_hide"><?php _e('Auto-hide?', 'boxzilla'); ?></label></th>
|
198 |
<td>
|
199 |
+
<label><input type="radio" name="boxzilla_box[auto_hide]" value="1" <?php checked($opts['auto_hide'], 1); ?> /> <?php _e('Yes'); ?></label>
|
200 |
+
<label><input type="radio" name="boxzilla_box[auto_hide]" value="0" <?php checked($opts['auto_hide'], 0); ?> /> <?php _e('No'); ?></label>
|
201 |
+
<p class="help"><?php _e('Hide box again when visitors scroll back up?', 'boxzilla'); ?></p>
|
202 |
</td>
|
203 |
</tr>
|
204 |
<tr valign="top">
|
205 |
+
<th><label for="boxzilla_closable"><?php _e('Show close icon?', 'boxzilla'); ?></label></th>
|
206 |
<td>
|
207 |
+
<label><input type="radio" id="boxzilla_closable_1" name="boxzilla_box[show_close_icon]" value="1" <?php checked($opts['show_close_icon'], 1); ?> /> <?php _e('Yes'); ?></label>
|
208 |
+
<label><input type="radio" id="boxzilla_closable_0" name="boxzilla_box[show_close_icon]" value="0" <?php checked($opts['show_close_icon'], 0); ?> /> <?php _e('No'); ?></label>
|
209 |
<p class="help">
|
210 |
+
<?php _e('If you decide to hide the close icon, make sure to offer an alternative way to close the box.', 'boxzilla'); ?><br />
|
211 |
+
<?php _e('Example: ', 'boxzilla'); ?> <code>[boxzilla-close]No, thanks![/boxzilla-close]</code>
|
212 |
</p>
|
213 |
</td>
|
214 |
</tr>
|
215 |
<tr valign="top">
|
216 |
+
<th><label for="boxzilla_test_mode"><?php _e('Enable test mode?', 'boxzilla'); ?></label></th>
|
217 |
<td>
|
218 |
+
<label><input type="radio" id="boxzilla_test_mode_1" name="boxzilla_global_settings[test_mode]" value="1" <?php checked($global_opts['test_mode'], 1); ?> /> <?php _e('Yes'); ?></label>
|
219 |
+
<label><input type="radio" id="boxzilla_test_mode_0" name="boxzilla_global_settings[test_mode]" value="0" <?php checked($global_opts['test_mode'], 0); ?> /> <?php _e('No'); ?></label>
|
220 |
+
<p class="help"><?php _e('If test mode is enabled, all boxes will show up regardless of whether a cookie has been set.', 'boxzilla'); ?></p>
|
221 |
</td>
|
222 |
</tr>
|
223 |
+
<?php
|
224 |
+
|
225 |
+
/**
|
226 |
+
* @ignore
|
227 |
+
*/
|
228 |
+
do_action('boxzilla_after_box_option_controls', $box, $opts); ?>
|
229 |
</tbody>
|
230 |
</table>
|
231 |
|
237 |
</tr>
|
238 |
<tr valign="top" class="boxzilla-rule-row boxzilla-rule-row-{{{data.key}}}">
|
239 |
<th style="text-align: right; font-weight: normal;">
|
240 |
+
<span class="boxzilla-close boxzilla-remove-rule" title="<?php esc_attr_e('Remove rule', 'boxzilla'); ?>"><span class="dashicons dashicons-dismiss"></span></span>
|
241 |
</th>
|
242 |
<td class="boxzilla-sm">
|
243 |
<select class="boxzilla-rule-condition" name="boxzilla_box[rules][{{{data.key}}}][condition]">
|
244 |
+
<?php foreach ($rule_options as $value => $label) {
|
245 |
+
printf('<option value="%s" %s %s>%s</option>', $value, disabled($value, '', false), '', $label);
|
246 |
+
} ?>
|
247 |
</select>
|
248 |
<select class="boxzilla-rule-qualifier" name="boxzilla_box[rules][{{{data.key}}}][qualifier]" style="display: none; min-width: 135px;" >
|
249 |
+
<option value="1" selected><?php _e('is', 'boxzilla'); ?></option>
|
250 |
+
<option value="0"><?php _e('is not', 'boxzilla'); ?></option>
|
251 |
+
<option value="contains" style="display: none;"><?php _e('contains', 'boxzilla'); ?></option>
|
252 |
+
<option value="not_contains" style="display: none;"><?php _e('does not contain', 'boxzilla'); ?></option>
|
253 |
</select>
|
254 |
|
255 |
+
<input class="boxzilla-rule-value regular-text" name="boxzilla_box[rules][{{{data.key}}}][value]" type="text" value="" placeholder="<?php _e('Leave empty for any or enter (comma-separated) names or ID\'s', 'boxzilla'); ?>" style="display: none;" />
|
256 |
</td>
|
257 |
</tr>
|
258 |
</script>
|
src/admin/views/metaboxes/email-optin.php
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
<?php
|
2 |
-
defined(
|
3 |
$user = wp_get_current_user(); ?>
|
4 |
<form action="//dannyvankooten.us1.list-manage.com/subscribe/post?u=a2d08947dcd3683512ce174c5&id=e3e1e0f8d8" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
5 |
<p>Get the most out of the Boxzilla plugin by subscribing to our newsletter filled with tips & tricks.</p>
|
6 |
|
7 |
<p class="mc-field-group">
|
8 |
<label for="mce-EMAIL" style="margin-bottom: 0;">Email Address <span style="color: red;">*</span></label>
|
9 |
-
<input type="email" value="<?php echo esc_attr(
|
10 |
</p>
|
11 |
<p class="mc-field-group">
|
12 |
<label for="mce-FNAME" style="margin-bottom: 0;">First Name <small style="font-weight: normal;">(optional)</small></label>
|
13 |
-
<input type="text" value="<?php echo esc_attr(
|
14 |
</p>
|
15 |
<div id="mce-responses" class="clear">
|
16 |
<div class="response" id="mce-error-response" style="display:none"></div>
|
1 |
<?php
|
2 |
+
defined('ABSPATH') or exit;
|
3 |
$user = wp_get_current_user(); ?>
|
4 |
<form action="//dannyvankooten.us1.list-manage.com/subscribe/post?u=a2d08947dcd3683512ce174c5&id=e3e1e0f8d8" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
5 |
<p>Get the most out of the Boxzilla plugin by subscribing to our newsletter filled with tips & tricks.</p>
|
6 |
|
7 |
<p class="mc-field-group">
|
8 |
<label for="mce-EMAIL" style="margin-bottom: 0;">Email Address <span style="color: red;">*</span></label>
|
9 |
+
<input type="email" value="<?php echo esc_attr($user->user_email); ?>" name="EMAIL" class="widefat" id="mce-EMAIL">
|
10 |
</p>
|
11 |
<p class="mc-field-group">
|
12 |
<label for="mce-FNAME" style="margin-bottom: 0;">First Name <small style="font-weight: normal;">(optional)</small></label>
|
13 |
+
<input type="text" value="<?php echo esc_attr($user->first_name); ?>" name="FNAME" class="widefat" id="mce-FNAME">
|
14 |
</p>
|
15 |
<div id="mce-responses" class="clear">
|
16 |
<div class="response" id="mce-error-response" style="display:none"></div>
|
src/admin/views/metaboxes/need-help.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
<?php defined(
|
2 |
-
<p><?php _e(
|
3 |
<ul class="ul-square">
|
4 |
<li><a href="https://kb.boxzillaplugin.com/">Knowledge Base</a></li>
|
5 |
<li><a href="https://wordpress.org/plugins/boxzilla/faq/">Frequently Asked Questions</a></li>
|
1 |
+
<?php defined('ABSPATH') or exit; ?>
|
2 |
+
<p><?php _e('Please make sure to look at the following available resources.', 'boxzilla'); ?></p>
|
3 |
<ul class="ul-square">
|
4 |
<li><a href="https://kb.boxzillaplugin.com/">Knowledge Base</a></li>
|
5 |
<li><a href="https://wordpress.org/plugins/boxzilla/faq/">Frequently Asked Questions</a></li>
|
src/admin/views/settings.php
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
<?php defined(
|
2 |
<div class="wrap" id="boxzilla-admin" class="boxzilla-settings">
|
3 |
|
4 |
<div class="boxzilla-row">
|
5 |
<div class="boxzilla-col-two-third">
|
6 |
|
7 |
-
<h2><?php _e(
|
8 |
|
9 |
-
<?php do_action(
|
10 |
|
11 |
-
<form action="<?php echo admin_url(
|
12 |
|
13 |
-
<?php settings_fields(
|
14 |
|
15 |
<table class="form-table">
|
16 |
|
17 |
-
<?php do_action(
|
18 |
|
19 |
<tr valign="top">
|
20 |
-
<th><label for="boxzilla_test_mode"><?php _e(
|
21 |
<td>
|
22 |
-
<label><input type="radio" id="boxzilla_test_mode_1" name="boxzilla_settings[test_mode]" value="1" <?php checked(
|
23 |
-
<label><input type="radio" id="boxzilla_test_mode_0" name="boxzilla_settings[test_mode]" value="0" <?php checked(
|
24 |
-
<p class="help"><?php _e(
|
25 |
</td>
|
26 |
</tr>
|
27 |
|
28 |
-
<?php do_action(
|
29 |
</table>
|
30 |
|
31 |
<?php submit_button(); ?>
|
32 |
</form>
|
33 |
|
34 |
-
<?php do_action(
|
35 |
</div>
|
36 |
|
37 |
<div class="boxzilla-sidebar boxzilla-col-one-third">
|
1 |
+
<?php defined('ABSPATH') or exit; ?>
|
2 |
<div class="wrap" id="boxzilla-admin" class="boxzilla-settings">
|
3 |
|
4 |
<div class="boxzilla-row">
|
5 |
<div class="boxzilla-col-two-third">
|
6 |
|
7 |
+
<h2><?php _e('Settings', 'boxzilla'); ?></h2>
|
8 |
|
9 |
+
<?php do_action('boxzilla_before_settings'); ?>
|
10 |
|
11 |
+
<form action="<?php echo admin_url('options.php'); ?>" method="post">
|
12 |
|
13 |
+
<?php settings_fields('boxzilla_settings'); ?>
|
14 |
|
15 |
<table class="form-table">
|
16 |
|
17 |
+
<?php do_action('boxzilla_before_settings_rows'); ?>
|
18 |
|
19 |
<tr valign="top">
|
20 |
+
<th><label for="boxzilla_test_mode"><?php _e('Enable test mode?', 'boxzilla'); ?></label></th>
|
21 |
<td>
|
22 |
+
<label><input type="radio" id="boxzilla_test_mode_1" name="boxzilla_settings[test_mode]" value="1" <?php checked($opts['test_mode'], 1); ?> /> <?php _e('Yes'); ?></label>
|
23 |
+
<label><input type="radio" id="boxzilla_test_mode_0" name="boxzilla_settings[test_mode]" value="0" <?php checked($opts['test_mode'], 0); ?> /> <?php _e('No'); ?></label>
|
24 |
+
<p class="help"><?php _e('If test mode is enabled, all boxes will show up regardless of whether a cookie has been set.', 'boxzilla'); ?></p>
|
25 |
</td>
|
26 |
</tr>
|
27 |
|
28 |
+
<?php do_action('boxzilla_after_settings_rows'); ?>
|
29 |
</table>
|
30 |
|
31 |
<?php submit_button(); ?>
|
32 |
</form>
|
33 |
|
34 |
+
<?php do_action('boxzilla_after_settings'); ?>
|
35 |
</div>
|
36 |
|
37 |
<div class="boxzilla-sidebar boxzilla-col-one-third">
|
src/class-bootstrapper.php
CHANGED
@@ -14,7 +14,8 @@ use InvalidArgumentException;
|
|
14 |
* @method void ajax( callable $callback )
|
15 |
* @method void cli( callable $callback )
|
16 |
*/
|
17 |
-
class Bootstrapper
|
|
|
18 |
|
19 |
/**
|
20 |
* @var array
|
@@ -32,14 +33,14 @@ class Bootstrapper {
|
|
32 |
* @param string $section
|
33 |
* @param callable $callable
|
34 |
*/
|
35 |
-
public function register(
|
36 |
-
|
37 |
-
if(
|
38 |
-
throw new InvalidArgumentException(
|
39 |
}
|
40 |
|
41 |
-
if(
|
42 |
-
throw new InvalidArgumentException(
|
43 |
}
|
44 |
|
45 |
$this->bootstrappers[ $section ][] = $callable;
|
@@ -49,9 +50,10 @@ class Bootstrapper {
|
|
49 |
* @param string $name
|
50 |
* @param array $arguments
|
51 |
*/
|
52 |
-
public function __call(
|
53 |
-
|
54 |
-
|
|
|
55 |
}
|
56 |
}
|
57 |
|
@@ -60,19 +62,19 @@ class Bootstrapper {
|
|
60 |
*
|
61 |
* @param string $section
|
62 |
*/
|
63 |
-
public function run(
|
64 |
-
|
65 |
-
if(
|
66 |
$section = $this->section();
|
67 |
}
|
68 |
|
69 |
// call all global callbacks
|
70 |
-
foreach(
|
71 |
$callback();
|
72 |
}
|
73 |
|
74 |
// call section specific callbacks
|
75 |
-
foreach(
|
76 |
$callback();
|
77 |
}
|
78 |
}
|
@@ -82,22 +84,22 @@ class Bootstrapper {
|
|
82 |
*
|
83 |
* @return string
|
84 |
*/
|
85 |
-
public function section()
|
86 |
-
|
87 |
-
|
|
|
88 |
return 'ajax';
|
89 |
} else {
|
90 |
return 'admin';
|
91 |
}
|
92 |
} else {
|
93 |
-
if(
|
94 |
return 'cron';
|
95 |
-
}
|
96 |
return 'cli';
|
97 |
} else {
|
98 |
return 'front';
|
99 |
}
|
100 |
}
|
101 |
}
|
102 |
-
|
103 |
-
}
|
14 |
* @method void ajax( callable $callback )
|
15 |
* @method void cli( callable $callback )
|
16 |
*/
|
17 |
+
class Bootstrapper
|
18 |
+
{
|
19 |
|
20 |
/**
|
21 |
* @var array
|
33 |
* @param string $section
|
34 |
* @param callable $callable
|
35 |
*/
|
36 |
+
public function register($section, $callable)
|
37 |
+
{
|
38 |
+
if (! isset($this->bootstrappers[ $section ])) {
|
39 |
+
throw new InvalidArgumentException("Section $section is invalid.");
|
40 |
}
|
41 |
|
42 |
+
if (! is_callable($callable)) {
|
43 |
+
throw new InvalidArgumentException('Callable argument is not callable.');
|
44 |
}
|
45 |
|
46 |
$this->bootstrappers[ $section ][] = $callable;
|
50 |
* @param string $name
|
51 |
* @param array $arguments
|
52 |
*/
|
53 |
+
public function __call($name, $arguments)
|
54 |
+
{
|
55 |
+
if (isset($this->bootstrappers[ $name ])) {
|
56 |
+
$this->register($name, $arguments[0]);
|
57 |
}
|
58 |
}
|
59 |
|
62 |
*
|
63 |
* @param string $section
|
64 |
*/
|
65 |
+
public function run($section = '')
|
66 |
+
{
|
67 |
+
if (! $section) {
|
68 |
$section = $this->section();
|
69 |
}
|
70 |
|
71 |
// call all global callbacks
|
72 |
+
foreach ($this->bootstrappers['global'] as $callback) {
|
73 |
$callback();
|
74 |
}
|
75 |
|
76 |
// call section specific callbacks
|
77 |
+
foreach ($this->bootstrappers[ $section ] as $callback) {
|
78 |
$callback();
|
79 |
}
|
80 |
}
|
84 |
*
|
85 |
* @return string
|
86 |
*/
|
87 |
+
public function section()
|
88 |
+
{
|
89 |
+
if (is_admin()) {
|
90 |
+
if (defined('DOING_AJAX') && DOING_AJAX) {
|
91 |
return 'ajax';
|
92 |
} else {
|
93 |
return 'admin';
|
94 |
}
|
95 |
} else {
|
96 |
+
if (defined('DOING_CRON') && DOING_CRON) {
|
97 |
return 'cron';
|
98 |
+
} elseif (defined('WP_CLI') && WP_CLI) {
|
99 |
return 'cli';
|
100 |
} else {
|
101 |
return 'front';
|
102 |
}
|
103 |
}
|
104 |
}
|
105 |
+
}
|
|
src/class-box.php
CHANGED
@@ -4,181 +4,187 @@ namespace Boxzilla;
|
|
4 |
|
5 |
use WP_Post;
|
6 |
|
7 |
-
class Box
|
|
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
|
34 |
/**
|
35 |
* @var WP_Post
|
36 |
*/
|
37 |
private $post;
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
102 |
'screen_size_condition' => array(
|
103 |
'condition' => 'larger',
|
104 |
'value' => 0,
|
105 |
),
|
106 |
-
|
107 |
'show_close_icon' => 1,
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
|
|
|
|
155 |
}
|
156 |
|
157 |
-
|
158 |
-
|
159 |
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
|
168 |
-
|
169 |
-
|
170 |
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
|
|
179 |
|
180 |
-
|
181 |
-
$close_link = sprintf('<a href="javascript:Boxzilla.dismiss(%d);">', $this->ID
|
182 |
|
183 |
$replacements = array(
|
184 |
'[boxzilla_close]' => $close_link, // accept underscore and dash here for consistency with other shortcode
|
@@ -187,77 +193,77 @@ class Box {
|
|
187 |
'[/boxzilla-close]' => '</a>',
|
188 |
);
|
189 |
|
190 |
-
$content = str_replace(
|
191 |
|
192 |
/**
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
|
202 |
/**
|
203 |
* Get options object for JS script.
|
204 |
*
|
205 |
* @return array
|
206 |
*/
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
|
|
214 |
);
|
215 |
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
$screen_width_condition = array(
|
225 |
'condition' => $box->options['screen_size_condition']['condition'],
|
226 |
-
'value' => intval(
|
227 |
);
|
228 |
}
|
229 |
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
'screenWidthCondition' => $screen_width_condition,
|
244 |
-
|
245 |
'post' => array(
|
246 |
'id' => $this->post->ID,
|
247 |
'title' => $this->post->post_title,
|
248 |
'slug' => $this->post->post_name,
|
249 |
),
|
250 |
-
|
251 |
-
|
252 |
-
/**
|
253 |
-
* Filter the final options for the JS Boxzilla client.
|
254 |
-
*
|
255 |
-
* @param array $client_options
|
256 |
-
* @param Box $box
|
257 |
-
*/
|
258 |
-
$client_options = apply_filters( 'boxzilla_box_client_options', $client_options, $box );
|
259 |
-
|
260 |
-
return $client_options;
|
261 |
-
}
|
262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
}
|
4 |
|
5 |
use WP_Post;
|
6 |
|
7 |
+
class Box
|
8 |
+
{
|
9 |
|
10 |
+
/**
|
11 |
+
* @var int
|
12 |
+
*/
|
13 |
+
public $ID;
|
14 |
|
15 |
+
/**
|
16 |
+
* @var array
|
17 |
+
*/
|
18 |
+
public $options = array();
|
19 |
|
20 |
+
/**
|
21 |
+
* @var string
|
22 |
+
*/
|
23 |
+
public $title = '';
|
24 |
|
25 |
+
/**
|
26 |
+
* @var string
|
27 |
+
*/
|
28 |
+
protected $content = '';
|
29 |
|
30 |
+
/**
|
31 |
+
* @var bool
|
32 |
+
*/
|
33 |
+
public $enabled = false;
|
34 |
|
35 |
/**
|
36 |
* @var WP_Post
|
37 |
*/
|
38 |
private $post;
|
39 |
|
40 |
+
/**
|
41 |
+
* @param WP_Post|int $post
|
42 |
+
*/
|
43 |
+
public function __construct($post)
|
44 |
+
{
|
45 |
+
|
46 |
+
// fetch post if it hasn't been fetched yet
|
47 |
+
if (! $post instanceof WP_Post) {
|
48 |
+
$post = get_post($post);
|
49 |
+
}
|
50 |
+
|
51 |
+
// store ref to post
|
52 |
+
$this->post = $post;
|
53 |
+
|
54 |
+
// store ID in property for quick access
|
55 |
+
$this->ID = $post->ID;
|
56 |
+
|
57 |
+
// store title in property
|
58 |
+
$this->title = $post->post_title;
|
59 |
+
|
60 |
+
// store content in property
|
61 |
+
$this->content = $post->post_content;
|
62 |
+
|
63 |
+
// is this box enabled?
|
64 |
+
$this->enabled = ($post->post_status === 'publish');
|
65 |
+
|
66 |
+
// load and store options in property
|
67 |
+
$this->options = $this->load_options();
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Get the options for this box.
|
72 |
+
**
|
73 |
+
* @return array Array of box options
|
74 |
+
*/
|
75 |
+
protected function load_options()
|
76 |
+
{
|
77 |
+
$defaults = array(
|
78 |
+
'css' => array(
|
79 |
+
'background_color' => '',
|
80 |
+
'color' => '',
|
81 |
+
'width' => '',
|
82 |
+
'border_color' => '',
|
83 |
+
'border_width' => '',
|
84 |
+
'border_style' => '',
|
85 |
+
'position' => 'bottom-right',
|
86 |
+
),
|
87 |
+
'rules' => array(
|
88 |
+
0 => array(
|
89 |
+
'condition' => '',
|
90 |
+
'value' => '',
|
91 |
+
),
|
92 |
+
),
|
93 |
+
'rules_comparision' => 'any',
|
94 |
+
'cookie' => array(
|
95 |
+
'triggered' => 0,
|
96 |
+
'dismissed' => 0,
|
97 |
+
),
|
98 |
+
'trigger' => 'percentage',
|
99 |
+
'trigger_percentage' => 65,
|
100 |
+
'trigger_element' => '',
|
101 |
+
'trigger_time_on_site' => 0,
|
102 |
+
'trigger_time_on_page' => 0,
|
103 |
+
'animation' => 'fade',
|
104 |
+
'auto_hide' => 0,
|
105 |
'screen_size_condition' => array(
|
106 |
'condition' => 'larger',
|
107 |
'value' => 0,
|
108 |
),
|
109 |
+
'closable' => 1,
|
110 |
'show_close_icon' => 1,
|
111 |
+
);
|
112 |
+
$box = $this;
|
113 |
+
|
114 |
+
$options = get_post_meta($this->ID, 'boxzilla_options', true);
|
115 |
+
$options = is_array($options) ? $options : array();
|
116 |
+
|
117 |
+
|
118 |
+
// merge options with default options
|
119 |
+
$options = array_replace_recursive($defaults, $options);
|
120 |
+
|
121 |
+
// allow others to filter the final array of options
|
122 |
+
/**
|
123 |
+
* Filter the options for a given box
|
124 |
+
*
|
125 |
+
* @param array $options
|
126 |
+
* @param Box $box
|
127 |
+
*/
|
128 |
+
$options = apply_filters('boxzilla_box_options', $options, $box);
|
129 |
+
|
130 |
+
return $options;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @return bool
|
135 |
+
*/
|
136 |
+
public function is_enabled()
|
137 |
+
{
|
138 |
+
return $this->enabled;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Get the options for this box
|
143 |
+
*
|
144 |
+
* @return array
|
145 |
+
*/
|
146 |
+
public function get_options()
|
147 |
+
{
|
148 |
+
return $this->options;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Get the close / hide icon for this box
|
153 |
+
*
|
154 |
+
* @return string
|
155 |
+
*/
|
156 |
+
public function get_close_icon()
|
157 |
+
{
|
158 |
+
if (! $this->options['show_close_icon']) {
|
159 |
+
return '';
|
160 |
}
|
161 |
|
162 |
+
$box = $this;
|
163 |
+
$html = '×';
|
164 |
|
165 |
+
/**
|
166 |
+
* Filters the HTML for the close icon.
|
167 |
+
*
|
168 |
+
* @param string $html
|
169 |
+
* @param Box $box
|
170 |
+
*/
|
171 |
+
$close_icon = (string) apply_filters('boxzilla_box_close_icon', $html, $box);
|
172 |
|
173 |
+
return $close_icon;
|
174 |
+
}
|
175 |
|
176 |
+
/**
|
177 |
+
* Get the content of this box
|
178 |
+
*
|
179 |
+
* @return string
|
180 |
+
*/
|
181 |
+
public function get_content()
|
182 |
+
{
|
183 |
+
$content = $this->content;
|
184 |
+
$box = $this;
|
185 |
|
186 |
+
// replace boxzilla specific shortcodes
|
187 |
+
$close_link = sprintf('<a href="javascript:Boxzilla.dismiss(%d);">', $this->ID);
|
188 |
|
189 |
$replacements = array(
|
190 |
'[boxzilla_close]' => $close_link, // accept underscore and dash here for consistency with other shortcode
|
193 |
'[/boxzilla-close]' => '</a>',
|
194 |
);
|
195 |
|
196 |
+
$content = str_replace(array_keys($replacements), array_values($replacements), $content);
|
197 |
|
198 |
/**
|
199 |
+
* Filters the HTML for the box content
|
200 |
+
*
|
201 |
+
* @param string $content
|
202 |
+
* @param Box $box
|
203 |
+
*/
|
204 |
+
$content = apply_filters('boxzilla_box_content', $content, $box);
|
205 |
+
return $content;
|
206 |
+
}
|
207 |
|
208 |
/**
|
209 |
* Get options object for JS script.
|
210 |
*
|
211 |
* @return array
|
212 |
*/
|
213 |
+
public function get_client_options()
|
214 |
+
{
|
215 |
+
$box = $this;
|
216 |
+
|
217 |
+
$trigger = false;
|
218 |
+
if ($box->options['trigger']) {
|
219 |
+
$trigger = array(
|
220 |
+
'method' => $this->options['trigger']
|
221 |
);
|
222 |
|
223 |
+
if (isset($this->options[ 'trigger_' . $this->options['trigger'] ])) {
|
224 |
+
$trigger['value'] = $this->options[ 'trigger_' . $this->options['trigger'] ];
|
225 |
+
}
|
226 |
+
}
|
227 |
|
228 |
+
// build screenWidthCondition object (or null)
|
229 |
+
$screen_width_condition = null;
|
230 |
+
if ($box->options['screen_size_condition']['value'] > 0) {
|
231 |
$screen_width_condition = array(
|
232 |
'condition' => $box->options['screen_size_condition']['condition'],
|
233 |
+
'value' => intval($box->options['screen_size_condition']['value']),
|
234 |
);
|
235 |
}
|
236 |
|
237 |
+
$client_options = array(
|
238 |
+
'id' => $box->ID,
|
239 |
+
'icon' => $box->get_close_icon(),
|
240 |
+
'content' => '', // we grab this later from an HTML element
|
241 |
+
'css' => array_filter($box->options['css']),
|
242 |
+
'trigger' => $trigger,
|
243 |
+
'animation' => $box->options['animation'],
|
244 |
+
'cookie' => array(
|
245 |
+
'triggered' => absint($box->options['cookie']['triggered']),
|
246 |
+
'dismissed' => absint($box->options['cookie']['dismissed']),
|
247 |
+
),
|
248 |
+
'rehide' => (bool) $box->options['auto_hide'],
|
249 |
+
'position' => $box->options['css']['position'],
|
250 |
'screenWidthCondition' => $screen_width_condition,
|
251 |
+
'closable' => !!$box->options['closable'],
|
252 |
'post' => array(
|
253 |
'id' => $this->post->ID,
|
254 |
'title' => $this->post->post_title,
|
255 |
'slug' => $this->post->post_name,
|
256 |
),
|
257 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
|
259 |
+
/**
|
260 |
+
* Filter the final options for the JS Boxzilla client.
|
261 |
+
*
|
262 |
+
* @param array $client_options
|
263 |
+
* @param Box $box
|
264 |
+
*/
|
265 |
+
$client_options = apply_filters('boxzilla_box_client_options', $client_options, $box);
|
266 |
+
|
267 |
+
return $client_options;
|
268 |
+
}
|
269 |
}
|
src/class-boxzilla-service-provider.php
CHANGED
@@ -7,68 +7,63 @@ use Boxzilla\Admin\Notices;
|
|
7 |
use Boxzilla\DI\Container;
|
8 |
use Boxzilla\DI\ServiceProviderInterface;
|
9 |
|
10 |
-
class BoxzillaServiceProvider implements ServiceProviderInterface
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
}
|
74 |
}
|
7 |
use Boxzilla\DI\Container;
|
8 |
use Boxzilla\DI\ServiceProviderInterface;
|
9 |
|
10 |
+
class BoxzillaServiceProvider implements ServiceProviderInterface
|
11 |
+
{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Registers services on the given container.
|
15 |
+
*
|
16 |
+
* This method should only be used to configure services and parameters.
|
17 |
+
* It should not get services.
|
18 |
+
*
|
19 |
+
* @param Container $container An Container instance
|
20 |
+
*/
|
21 |
+
public function register(Container $container)
|
22 |
+
{
|
23 |
+
$container['admin'] = function ($container) {
|
24 |
+
return new Admin($container->plugin, $container);
|
25 |
+
};
|
26 |
+
|
27 |
+
$container['bootstrapper'] = new Bootstrapper();
|
28 |
+
|
29 |
+
$container['box_loader'] = function ($container) {
|
30 |
+
return new BoxLoader($container->plugin, $container->options);
|
31 |
+
};
|
32 |
+
|
33 |
+
$container['filter.autocomplete'] = function ($container) {
|
34 |
+
return new Filter\Autocomplete();
|
35 |
+
};
|
36 |
+
|
37 |
+
$container['notices'] = function ($container) {
|
38 |
+
return new Notices();
|
39 |
+
};
|
40 |
+
|
41 |
+
$container['options'] = function ($container) {
|
42 |
+
$defaults = array(
|
43 |
+
'test_mode' => 0
|
44 |
+
);
|
45 |
+
|
46 |
+
$options = (array) get_option('boxzilla_settings', $defaults);
|
47 |
+
$options = array_merge($defaults, $options);
|
48 |
+
return $options;
|
49 |
+
};
|
50 |
+
|
51 |
+
$container['plugin'] = new Plugin(
|
52 |
+
'boxzilla',
|
53 |
+
'Boxzilla',
|
54 |
+
BOXZILLA_VERSION,
|
55 |
+
BOXZILLA_FILE,
|
56 |
+
dirname(BOXZILLA_FILE)
|
57 |
+
);
|
58 |
+
|
59 |
+
$container['plugins'] = function ($container) {
|
60 |
+
$raw = (array) apply_filters('boxzilla_extensions', array());
|
61 |
+
|
62 |
+
$plugins = array();
|
63 |
+
foreach ($raw as $p) {
|
64 |
+
$plugins[ $p->id() ] = $p;
|
65 |
+
}
|
66 |
+
return $plugins;
|
67 |
+
};
|
68 |
+
}
|
|
|
|
|
|
|
|
|
|
|
69 |
}
|
src/class-boxzilla.php
CHANGED
@@ -17,4 +17,6 @@ use Boxzilla\Licensing\License;
|
|
17 |
* @property Bootstrapper $bootstrapper
|
18 |
*
|
19 |
*/
|
20 |
-
class Boxzilla extends ContainerWithPropertyAccess
|
|
|
|
17 |
* @property Bootstrapper $bootstrapper
|
18 |
*
|
19 |
*/
|
20 |
+
class Boxzilla extends ContainerWithPropertyAccess
|
21 |
+
{
|
22 |
+
}
|
src/class-loader.php
CHANGED
@@ -1,332 +1,336 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Boxzilla;
|
4 |
-
|
5 |
-
class BoxLoader
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Boxzilla;
|
4 |
+
|
5 |
+
class BoxLoader
|
6 |
+
{
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @var Plugin
|
10 |
+
*/
|
11 |
+
private $plugin;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array
|
15 |
+
*/
|
16 |
+
private $box_ids_to_load = array();
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var array
|
20 |
+
*/
|
21 |
+
protected $options;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Constructor
|
25 |
+
*
|
26 |
+
* @param Plugin $plugin
|
27 |
+
* @param array $options
|
28 |
+
*/
|
29 |
+
public function __construct(Plugin $plugin, array $options)
|
30 |
+
{
|
31 |
+
$this->plugin = $plugin;
|
32 |
+
$this->options = $options;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Initializes the plugin, runs on `wp` hook.
|
37 |
+
*/
|
38 |
+
public function init()
|
39 |
+
{
|
40 |
+
$this->box_ids_to_load = $this->filter_boxes();
|
41 |
+
|
42 |
+
// Only add other hooks if necessary
|
43 |
+
if (count($this->box_ids_to_load) > 0) {
|
44 |
+
add_action('wp_footer', array( $this, 'print_boxes_content' ), 1);
|
45 |
+
add_action('wp_enqueue_scripts', array( $this, 'load_assets' ), 90);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Get global rules for all boxes
|
51 |
+
*
|
52 |
+
* @return array
|
53 |
+
*/
|
54 |
+
protected function get_filter_rules()
|
55 |
+
{
|
56 |
+
$rules = get_option('boxzilla_rules', array());
|
57 |
+
|
58 |
+
if (! is_array($rules)) {
|
59 |
+
return array();
|
60 |
+
}
|
61 |
+
|
62 |
+
return $rules;
|
63 |
+
}
|
64 |
+
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Match a string against an array of patterns, glob-style.
|
68 |
+
*
|
69 |
+
* @param string $string
|
70 |
+
* @param array $patterns
|
71 |
+
*
|
72 |
+
* @return boolean
|
73 |
+
*/
|
74 |
+
protected function match_patterns($string, $patterns, $contains = false)
|
75 |
+
{
|
76 |
+
$string = strtolower($string);
|
77 |
+
|
78 |
+
foreach ($patterns as $pattern) {
|
79 |
+
$pattern = rtrim($pattern, '/');
|
80 |
+
$pattern = strtolower($pattern);
|
81 |
+
|
82 |
+
// contains means we should do a simple occurrence check
|
83 |
+
// does not support wildcards
|
84 |
+
if ($contains) {
|
85 |
+
return strpos($string, $pattern) !== false;
|
86 |
+
}
|
87 |
+
|
88 |
+
if (function_exists('fnmatch')) {
|
89 |
+
$match = fnmatch($pattern, $string);
|
90 |
+
} else {
|
91 |
+
$match = ($pattern === $string);
|
92 |
+
}
|
93 |
+
|
94 |
+
if ($match) {
|
95 |
+
return true;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @return string
|
104 |
+
*/
|
105 |
+
protected function get_request_url()
|
106 |
+
{
|
107 |
+
// strip trailing slashes
|
108 |
+
$request_uri = rtrim($_SERVER['REQUEST_URI'], '/');
|
109 |
+
return $request_uri;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Check if this rule passes (conditional matches expected value)
|
114 |
+
*
|
115 |
+
* @param string $condition
|
116 |
+
* @param string $value
|
117 |
+
* @param boolean $qualifier
|
118 |
+
*
|
119 |
+
* @return bool
|
120 |
+
*/
|
121 |
+
protected function match_rule($condition, $value, $qualifier = true)
|
122 |
+
{
|
123 |
+
$matched = false;
|
124 |
+
|
125 |
+
// cast value to array & trim whitespace or excess comma's
|
126 |
+
$value = array_map('trim', explode(',', rtrim(trim($value), ',')));
|
127 |
+
|
128 |
+
switch ($condition) {
|
129 |
+
case 'everywhere':
|
130 |
+
$matched = true;
|
131 |
+
break;
|
132 |
+
|
133 |
+
case 'is_url':
|
134 |
+
$url = $this->get_request_url();
|
135 |
+
$matched = $this->match_patterns($url, $value, $qualifier === 'contains' || $qualifier === 'not_contains');
|
136 |
+
break;
|
137 |
+
|
138 |
+
case 'is_referer':
|
139 |
+
if (! empty($_SERVER['HTTP_REFERER'])) {
|
140 |
+
$referer = $_SERVER['HTTP_REFERER'];
|
141 |
+
$matched = $this->match_patterns($referer, $value, $qualifier === 'contains' || $qualifier === 'not_contains');
|
142 |
+
}
|
143 |
+
break;
|
144 |
+
|
145 |
+
case 'is_post_type':
|
146 |
+
$post_type = (string) get_post_type();
|
147 |
+
$matched = in_array($post_type, (array) $value);
|
148 |
+
break;
|
149 |
+
|
150 |
+
case 'is_single':
|
151 |
+
case 'is_post':
|
152 |
+
// convert to empty string if array with just empty string in it
|
153 |
+
$value = ($value === array( '' )) ? '' : $value;
|
154 |
+
$matched = is_single($value);
|
155 |
+
break;
|
156 |
+
|
157 |
+
case 'is_post_in_category':
|
158 |
+
$matched = is_singular('post') && has_category($value);
|
159 |
+
break;
|
160 |
+
|
161 |
+
|
162 |
+
case 'is_page':
|
163 |
+
$matched = is_page($value);
|
164 |
+
break;
|
165 |
+
|
166 |
+
case 'is_post_with_tag':
|
167 |
+
$matched = is_singular('post') && has_tag($value);
|
168 |
+
break;
|
169 |
+
|
170 |
+
case 'is_user_logged_in':
|
171 |
+
$matched = is_user_logged_in();
|
172 |
+
break;
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Filters whether a given box rule matches the condition and expected value.
|
177 |
+
*
|
178 |
+
* The dynamic portion of the hook, `$condition`, refers to the condition being matched.
|
179 |
+
*
|
180 |
+
* @param boolean $matched
|
181 |
+
* @param array $value
|
182 |
+
*/
|
183 |
+
$matched = apply_filters('boxzilla_box_rule_matches_' . $condition, $matched, $value);
|
184 |
+
|
185 |
+
// if qualifier is set to false, we need to reverse this value here.
|
186 |
+
if (! $qualifier || $qualifier === 'not_contains') {
|
187 |
+
$matched = ! $matched;
|
188 |
+
}
|
189 |
+
|
190 |
+
return $matched;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Checks which boxes should be loaded for this request.
|
195 |
+
*
|
196 |
+
* @return array
|
197 |
+
*/
|
198 |
+
private function filter_boxes()
|
199 |
+
{
|
200 |
+
$box_ids_to_load = array();
|
201 |
+
$rules = $this->get_filter_rules();
|
202 |
+
|
203 |
+
foreach ($rules as $box_id => $box_rules) {
|
204 |
+
$matched = false;
|
205 |
+
$comparision = isset($box_rules['comparision']) ? $box_rules['comparision'] : 'any';
|
206 |
+
|
207 |
+
// loop through all rules for all boxes
|
208 |
+
foreach ($box_rules as $rule) {
|
209 |
+
|
210 |
+
// skip faulty values (and comparision rule)
|
211 |
+
if (empty($rule['condition'])) {
|
212 |
+
continue;
|
213 |
+
}
|
214 |
+
|
215 |
+
$qualifier = isset($rule['qualifier']) ? $rule['qualifier'] : true;
|
216 |
+
$matched = $this->match_rule($rule['condition'], $rule['value'], $qualifier);
|
217 |
+
|
218 |
+
// break out of loop if we've already matched
|
219 |
+
if ($comparision === 'any' && $matched) {
|
220 |
+
break;
|
221 |
+
}
|
222 |
+
|
223 |
+
// no need to continue if this rule didn't match
|
224 |
+
if ($comparision === 'all' && ! $matched) {
|
225 |
+
break;
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
// value of $matched at this point determines whether box should be loaded
|
230 |
+
$load_box = $matched;
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Filters whether a box should be loaded into the page HTML.
|
234 |
+
*
|
235 |
+
* The dynamic portion of the hook, `$box_id`, refers to the ID of the box. Return true if you want to output the box.
|
236 |
+
*
|
237 |
+
* @param boolean $load_box
|
238 |
+
*/
|
239 |
+
$load_box = apply_filters('boxzilla_load_box_' . $box_id, $load_box);
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Filters whether a box should be loaded into the page HTML.
|
243 |
+
*
|
244 |
+
* @param boolean $load_box
|
245 |
+
* @param int $box_id
|
246 |
+
*/
|
247 |
+
$load_box = apply_filters('boxzilla_load_box', $load_box, $box_id);
|
248 |
+
|
249 |
+
// if matched, box should be loaded on this page
|
250 |
+
if ($load_box) {
|
251 |
+
$box_ids_to_load[] = $box_id;
|
252 |
+
}
|
253 |
+
}
|
254 |
+
|
255 |
+
return $box_ids_to_load;
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Load plugin styles
|
260 |
+
*/
|
261 |
+
public function load_assets()
|
262 |
+
{
|
263 |
+
$pre_suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
264 |
+
wp_enqueue_script('boxzilla', $this->plugin->url('/assets/js/script' . $pre_suffix . '.js'), array(), $this->plugin->version(), true);
|
265 |
+
|
266 |
+
// create boxzilla_Global_Options object
|
267 |
+
$plugin_options = $this->options;
|
268 |
+
$boxes = $this->get_matched_boxes();
|
269 |
+
|
270 |
+
$data = array(
|
271 |
+
'testMode' => (bool) $plugin_options['test_mode'],
|
272 |
+
'boxes' => (array) array_map(function (Box $box) {
|
273 |
+
return $box->get_client_options();
|
274 |
+
}, $boxes),
|
275 |
+
);
|
276 |
+
|
277 |
+
wp_localize_script('boxzilla', 'boxzilla_options', $data);
|
278 |
+
|
279 |
+
do_action('boxzilla_load_assets', $this);
|
280 |
+
}
|
281 |
+
|
282 |
+
public function print_boxes_content()
|
283 |
+
{
|
284 |
+
$boxes = $this->get_matched_boxes();
|
285 |
+
if (empty($boxes)) {
|
286 |
+
return;
|
287 |
+
}
|
288 |
+
|
289 |
+
echo '<div style="display: none;">';
|
290 |
+
foreach ($boxes as $box) {
|
291 |
+
echo sprintf('<div id="boxzilla-box-%d-content">', $box->ID) . $box->get_content() . '</div>';
|
292 |
+
}
|
293 |
+
echo '</div>';
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Get an array of Box objects. These are the boxes that will be loaded for the current request.
|
298 |
+
*
|
299 |
+
* @return Box[]
|
300 |
+
*/
|
301 |
+
public function get_matched_boxes()
|
302 |
+
{
|
303 |
+
static $boxes;
|
304 |
+
|
305 |
+
if (is_null($boxes)) {
|
306 |
+
if (count($this->box_ids_to_load) === 0) {
|
307 |
+
$boxes = array();
|
308 |
+
return $boxes;
|
309 |
+
}
|
310 |
+
|
311 |
+
// query Box posts
|
312 |
+
$posts = get_posts(
|
313 |
+
array(
|
314 |
+
'post_type' => 'boxzilla-box',
|
315 |
+
'post_status' => 'publish',
|
316 |
+
'post__in' => $this->box_ids_to_load,
|
317 |
+
'numberposts' => -1
|
318 |
+
)
|
319 |
+
);
|
320 |
+
|
321 |
+
// create `Box` instances out of \WP_Post instances
|
322 |
+
$boxes = array();
|
323 |
+
foreach ($posts as $key => $post) {
|
324 |
+
// skip posts with no content
|
325 |
+
$post_content = trim($post->post_content);
|
326 |
+
if (empty($post_content)) {
|
327 |
+
continue;
|
328 |
+
}
|
329 |
+
|
330 |
+
$boxes[ $key ] = new Box($post);
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
return $boxes;
|
335 |
+
}
|
336 |
+
}
|
src/class-php-fallback.php
CHANGED
@@ -1,62 +1,64 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class Boxzilla_PHP_Fallback
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
55 |
<div class="updated">
|
56 |
-
<p><?php printf(
|
57 |
-
<p><?php printf(
|
58 |
</div>
|
59 |
<?php
|
60 |
-
|
61 |
-
|
62 |
}
|
1 |
<?php
|
2 |
|
3 |
+
class Boxzilla_PHP_Fallback
|
4 |
+
{
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var string
|
8 |
+
*/
|
9 |
+
private $plugin_name = '';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var string
|
13 |
+
*/
|
14 |
+
private $plugin_file = '';
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @param $plugin_name
|
18 |
+
* @param $plugin_file
|
19 |
+
*/
|
20 |
+
public function __construct($plugin_name, $plugin_file)
|
21 |
+
{
|
22 |
+
$this->plugin_name = $plugin_name;
|
23 |
+
$this->plugin_file = $plugin_file;
|
24 |
+
|
25 |
+
// deactivate plugin straight away
|
26 |
+
add_action('admin_init', array( $this, 'deactivate_self' ));
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @return bool
|
31 |
+
*/
|
32 |
+
public function deactivate_self()
|
33 |
+
{
|
34 |
+
if (! current_user_can('activate_plugins')) {
|
35 |
+
return false;
|
36 |
+
}
|
37 |
+
|
38 |
+
// deactivate self
|
39 |
+
deactivate_plugins($this->plugin_file);
|
40 |
+
|
41 |
+
// get rid of "Plugin activated" notice
|
42 |
+
if (isset($_GET['activate'])) {
|
43 |
+
unset($_GET['activate']);
|
44 |
+
}
|
45 |
+
|
46 |
+
// show notice to user
|
47 |
+
add_action('admin_notices', array( $this, 'show_notice' ));
|
48 |
+
|
49 |
+
return true;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @return void
|
54 |
+
*/
|
55 |
+
public function show_notice()
|
56 |
+
{
|
57 |
+
?>
|
58 |
<div class="updated">
|
59 |
+
<p><?php printf('<strong>%s</strong> did not activate because it requires <strong>PHP v5.3</strong> or higher, while your server is running <strong>PHP v%s</strong>.', $this->plugin_name, PHP_VERSION); ?>
|
60 |
+
<p><?php printf('<a href="%s">Updating your PHP version</a> makes your site faster, more secure and should be easy for your host.', 'http://www.wpupdatephp.com/update/#utm_source=wp-plugin&utm_medium=boxzillas&utm_campaign=activation-notice'); ?></p>
|
61 |
</div>
|
62 |
<?php
|
63 |
+
}
|
|
|
64 |
}
|
src/class-plugin.php
CHANGED
@@ -2,108 +2,117 @@
|
|
2 |
|
3 |
namespace Boxzilla;
|
4 |
|
5 |
-
class Plugin
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
namespace Boxzilla;
|
4 |
|
5 |
+
class Plugin
|
6 |
+
{
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @var string The current version of the plugin
|
10 |
+
*/
|
11 |
+
protected $version = '1.0';
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var string
|
15 |
+
*/
|
16 |
+
protected $file = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var string
|
20 |
+
*/
|
21 |
+
protected $dir = '';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var string
|
25 |
+
*/
|
26 |
+
protected $name = '';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
protected $slug = '';
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var int
|
35 |
+
*/
|
36 |
+
protected $id = 0;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Constructor
|
40 |
+
*
|
41 |
+
* @param int $id
|
42 |
+
* @param string $name
|
43 |
+
* @param string $version
|
44 |
+
* @param string $file
|
45 |
+
* @param string $dir (optional)
|
46 |
+
*/
|
47 |
+
public function __construct($id, $name, $version, $file, $dir = '')
|
48 |
+
{
|
49 |
+
$this->id = $id;
|
50 |
+
$this->name = $name;
|
51 |
+
$this->version = $version;
|
52 |
+
$this->file = $file;
|
53 |
+
$this->dir = $dir;
|
54 |
+
$this->slug = plugin_basename($file);
|
55 |
+
|
56 |
+
if (empty($dir)) {
|
57 |
+
$this->dir = dirname($file);
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @return int
|
63 |
+
*/
|
64 |
+
public function id()
|
65 |
+
{
|
66 |
+
return $this->id;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return string
|
71 |
+
*/
|
72 |
+
public function slug()
|
73 |
+
{
|
74 |
+
return $this->slug;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @return string
|
79 |
+
*/
|
80 |
+
public function name()
|
81 |
+
{
|
82 |
+
return $this->name;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* @return string
|
87 |
+
*/
|
88 |
+
public function version()
|
89 |
+
{
|
90 |
+
return $this->version;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @return string
|
95 |
+
*/
|
96 |
+
public function file()
|
97 |
+
{
|
98 |
+
return $this->file;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return string
|
103 |
+
*/
|
104 |
+
public function dir()
|
105 |
+
{
|
106 |
+
return $this->dir;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* @param string $path
|
111 |
+
*
|
112 |
+
* @return mixed
|
113 |
+
*/
|
114 |
+
public function url($path = '')
|
115 |
+
{
|
116 |
+
return plugins_url($path, $this->file());
|
117 |
+
}
|
118 |
+
}
|
src/default-actions.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
defined(
|
4 |
|
5 |
$boxzilla = boxzilla();
|
6 |
|
7 |
// Register custom post type
|
8 |
-
add_action(
|
9 |
$args = array(
|
10 |
'public' => false,
|
11 |
'labels' => array(
|
12 |
-
'name' => __(
|
13 |
-
'singular_name' => __(
|
14 |
-
'add_new' => __(
|
15 |
-
'add_new_item' => __(
|
16 |
-
'edit_item' => __(
|
17 |
-
'new_item' => __(
|
18 |
-
'all_items' => __(
|
19 |
-
'view_item' => __(
|
20 |
-
'search_items' => __(
|
21 |
-
'not_found' => __(
|
22 |
-
'not_found_in_trash' => __(
|
23 |
'parent_item_colon' => '',
|
24 |
-
'menu_name' => __(
|
25 |
),
|
26 |
'show_ui' => true,
|
27 |
'menu_position' => '108.1337133',
|
28 |
-
'menu_icon' => 'data:image/svg+xml;base64,' . base64_encode(
|
29 |
'query_var' => false,
|
30 |
'capability_type' => 'box',
|
31 |
'capabilities' => array(
|
@@ -39,15 +39,15 @@ add_action( 'init', function() use( $boxzilla ){
|
|
39 |
),
|
40 |
);
|
41 |
|
42 |
-
register_post_type(
|
43 |
|
44 |
-
add_shortcode(
|
45 |
});
|
46 |
|
47 |
-
add_action(
|
48 |
-
$admins = get_role(
|
49 |
|
50 |
-
if(
|
51 |
$admins->add_cap('edit_box');
|
52 |
$admins->add_cap('edit_boxes');
|
53 |
$admins->add_cap('edit_other_boxes');
|
@@ -58,15 +58,16 @@ add_action( 'admin_init', function() {
|
|
58 |
}
|
59 |
});
|
60 |
|
61 |
-
function boxzilla_get_link_html(
|
|
|
62 |
$valid_actions = array(
|
63 |
'show',
|
64 |
'toggle',
|
65 |
'hide',
|
66 |
'dismiss'
|
67 |
);
|
68 |
-
$box_id = empty(
|
69 |
-
$class_attr = empty(
|
70 |
-
$action = empty(
|
71 |
-
return sprintf(
|
72 |
}
|
1 |
<?php
|
2 |
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
|
5 |
$boxzilla = boxzilla();
|
6 |
|
7 |
// Register custom post type
|
8 |
+
add_action('init', function () use ($boxzilla) {
|
9 |
$args = array(
|
10 |
'public' => false,
|
11 |
'labels' => array(
|
12 |
+
'name' => __('Boxzilla', 'boxzilla'),
|
13 |
+
'singular_name' => __('Box', 'boxzilla'),
|
14 |
+
'add_new' => __('Add New', 'boxzilla'),
|
15 |
+
'add_new_item' => __('Add New Box', 'boxzilla'),
|
16 |
+
'edit_item' => __('Edit Box', 'boxzilla'),
|
17 |
+
'new_item' => __('New Box', 'boxzilla'),
|
18 |
+
'all_items' => __('All Boxes', 'boxzilla'),
|
19 |
+
'view_item' => __('View Box', 'boxzilla'),
|
20 |
+
'search_items' => __('Search Boxes', 'boxzilla'),
|
21 |
+
'not_found' => __('No Boxes found', 'boxzilla'),
|
22 |
+
'not_found_in_trash' => __('No Boxes found in Trash', 'boxzilla'),
|
23 |
'parent_item_colon' => '',
|
24 |
+
'menu_name' => __('Boxzilla', 'boxzilla')
|
25 |
),
|
26 |
'show_ui' => true,
|
27 |
'menu_position' => '108.1337133',
|
28 |
+
'menu_icon' => 'data:image/svg+xml;base64,' . base64_encode('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16" width="16" height="16"><defs><path d="M0 0L16 0L16 16L0 16L0 16L0 0ZM6.72 13.59L6.72 12.47L7.71 13.28L8.94 13.59L10.17 13.28L11.17 12.46L11.85 11.25L12.1 9.76L11.85 8.27L11.17 7.05L10.17 6.23L8.94 5.93L7.71 6.23L6.72 7.04L6.72 2.27L4.16 2.27L4.16 13.59L4.16 13.59L6.72 13.59ZM9.93 9.03L10.06 9.76L9.93 10.49L9.56 11.08L9.01 11.48L8.35 11.63L7.68 11.48L7.13 11.08L6.76 10.49L6.72 10.26L6.72 9.25L6.76 9.03L7.13 8.43L7.68 8.03L8.35 7.88L9.01 8.03L9.56 8.43L9.56 8.43L9.93 9.03Z" id="c1kAiZqIlD"></path></defs><g><g><g><use xlink:href="#c1kAiZqIlD" opacity="1" fill="black" fill-opacity="1"></use></g></g></g></svg>'),
|
29 |
'query_var' => false,
|
30 |
'capability_type' => 'box',
|
31 |
'capabilities' => array(
|
39 |
),
|
40 |
);
|
41 |
|
42 |
+
register_post_type('boxzilla-box', $args);
|
43 |
|
44 |
+
add_shortcode('boxzilla_link', 'boxzilla_get_link_html');
|
45 |
});
|
46 |
|
47 |
+
add_action('admin_init', function () {
|
48 |
+
$admins = get_role('administrator');
|
49 |
|
50 |
+
if (! $admins->has_cap('edit_box')) {
|
51 |
$admins->add_cap('edit_box');
|
52 |
$admins->add_cap('edit_boxes');
|
53 |
$admins->add_cap('edit_other_boxes');
|
58 |
}
|
59 |
});
|
60 |
|
61 |
+
function boxzilla_get_link_html($args = array(), $content = '')
|
62 |
+
{
|
63 |
$valid_actions = array(
|
64 |
'show',
|
65 |
'toggle',
|
66 |
'hide',
|
67 |
'dismiss'
|
68 |
);
|
69 |
+
$box_id = empty($args['box']) ? '' : absint($args['box']);
|
70 |
+
$class_attr = empty($args['class']) ? '' : esc_attr($args['class']);
|
71 |
+
$action = empty($args['action']) || ! in_array($args['action'], $valid_actions) ? 'show' : $args['action'];
|
72 |
+
return sprintf('<a href="javascript:Boxzilla.%s(%s)" class="%s">', $action, $box_id, $class_attr) . $content . '</a>';
|
73 |
}
|
src/default-filters.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
defined(
|
4 |
|
5 |
-
add_filter(
|
6 |
-
add_filter(
|
7 |
-
add_filter(
|
8 |
-
add_filter(
|
9 |
-
add_filter(
|
10 |
-
add_filter(
|
11 |
|
12 |
/**
|
13 |
* Allow Jetpack Photon to filter on Boxzilla box content.
|
14 |
*/
|
15 |
-
if (
|
16 |
-
|
17 |
}
|
1 |
<?php
|
2 |
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
|
5 |
+
add_filter('boxzilla_box_content', 'wptexturize') ;
|
6 |
+
add_filter('boxzilla_box_content', 'convert_smilies');
|
7 |
+
add_filter('boxzilla_box_content', 'convert_chars');
|
8 |
+
add_filter('boxzilla_box_content', 'wpautop');
|
9 |
+
add_filter('boxzilla_box_content', 'shortcode_unautop');
|
10 |
+
add_filter('boxzilla_box_content', 'do_shortcode', 11);
|
11 |
|
12 |
/**
|
13 |
* Allow Jetpack Photon to filter on Boxzilla box content.
|
14 |
*/
|
15 |
+
if (class_exists('Jetpack') && class_exists('Jetpack_Photon') && Jetpack::is_module_active('photon')) {
|
16 |
+
add_filter('boxzilla_box_content', array( 'Jetpack_Photon', 'filter_the_content' ), 999999);
|
17 |
}
|
src/di/class-container-with-property-access.php
CHANGED
@@ -9,46 +9,51 @@ namespace Boxzilla\DI;
|
|
9 |
*
|
10 |
* @package Boxzilla\DI
|
11 |
*/
|
12 |
-
class ContainerWithPropertyAccess extends Container
|
|
|
13 |
|
14 |
/**
|
15 |
* @param string $name
|
16 |
* @return mixed
|
17 |
*/
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
29 |
|
30 |
/**
|
31 |
* @param string $name
|
32 |
* @return bool
|
33 |
*/
|
34 |
-
public function __isset(
|
35 |
-
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
* @param string $name
|
40 |
* @return bool
|
41 |
*/
|
42 |
-
public function has(
|
43 |
-
|
|
|
44 |
}
|
45 |
|
46 |
/**
|
47 |
* @param string $name
|
48 |
* @return mixed
|
49 |
*/
|
50 |
-
public function get(
|
51 |
-
|
|
|
52 |
}
|
53 |
-
|
54 |
-
}
|
9 |
*
|
10 |
* @package Boxzilla\DI
|
11 |
*/
|
12 |
+
class ContainerWithPropertyAccess extends Container
|
13 |
+
{
|
14 |
|
15 |
/**
|
16 |
* @param string $name
|
17 |
* @return mixed
|
18 |
*/
|
19 |
+
public function __get($name)
|
20 |
+
{
|
21 |
+
return $this->offsetGet($name);
|
22 |
+
}
|
23 |
|
24 |
+
/**
|
25 |
+
* @param string $name
|
26 |
+
* @param mixed $value
|
27 |
+
*/
|
28 |
+
public function __set($name, $value)
|
29 |
+
{
|
30 |
+
$this[ $name ] = $value;
|
31 |
+
}
|
32 |
|
33 |
/**
|
34 |
* @param string $name
|
35 |
* @return bool
|
36 |
*/
|
37 |
+
public function __isset($name)
|
38 |
+
{
|
39 |
+
return $this->offsetExists($name);
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
* @param string $name
|
44 |
* @return bool
|
45 |
*/
|
46 |
+
public function has($name)
|
47 |
+
{
|
48 |
+
return $this->offsetExists($name);
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
* @param string $name
|
53 |
* @return mixed
|
54 |
*/
|
55 |
+
public function get($name)
|
56 |
+
{
|
57 |
+
return $this->offsetGet($name);
|
58 |
}
|
59 |
+
}
|
|
src/functions.php
CHANGED
@@ -5,13 +5,13 @@ use Boxzilla\Boxzilla;
|
|
5 |
/**
|
6 |
* @return Boxzilla
|
7 |
*/
|
8 |
-
function boxzilla()
|
|
|
9 |
static $instance;
|
10 |
|
11 |
-
if(
|
12 |
-
|
13 |
}
|
14 |
|
15 |
return $instance;
|
16 |
}
|
17 |
-
|
5 |
/**
|
6 |
* @return Boxzilla
|
7 |
*/
|
8 |
+
function boxzilla()
|
9 |
+
{
|
10 |
static $instance;
|
11 |
|
12 |
+
if (is_null($instance)) {
|
13 |
+
$instance = new Boxzilla();
|
14 |
}
|
15 |
|
16 |
return $instance;
|
17 |
}
|
|
src/licensing/class-api-exception.php
CHANGED
@@ -4,30 +4,32 @@ namespace Boxzilla\Licensing;
|
|
4 |
|
5 |
use Exception;
|
6 |
|
7 |
-
class API_Exception extends Exception
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
|
4 |
|
5 |
use Exception;
|
6 |
|
7 |
+
class API_Exception extends Exception
|
8 |
+
{
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var string
|
12 |
+
*/
|
13 |
+
protected $apiCode;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* API_Exception constructor.
|
17 |
+
*
|
18 |
+
* @param string $message
|
19 |
+
* @param string $apiCode (optional)
|
20 |
+
*/
|
21 |
+
public function __construct($message, $apiCode = '')
|
22 |
+
{
|
23 |
+
parent::__construct($message);
|
24 |
+
|
25 |
+
$this->apiCode = $apiCode;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @return string
|
30 |
+
*/
|
31 |
+
public function getApiCode()
|
32 |
+
{
|
33 |
+
return $this->apiCode;
|
34 |
+
}
|
35 |
+
}
|
src/licensing/class-api.php
CHANGED
@@ -6,172 +6,178 @@ use Boxzilla\Plugin;
|
|
6 |
use Exception;
|
7 |
use WP_Error;
|
8 |
|
9 |
-
class API
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
}
|
6 |
use Exception;
|
7 |
use WP_Error;
|
8 |
|
9 |
+
class API
|
10 |
+
{
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var License
|
14 |
+
*/
|
15 |
+
protected $license;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The API url
|
19 |
+
*
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
public $url = '';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var int
|
26 |
+
*/
|
27 |
+
protected $error_code = 0;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
protected $error_message = '';
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @var
|
36 |
+
*/
|
37 |
+
protected $last_response;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @param string $url
|
41 |
+
* @param License $license
|
42 |
+
*/
|
43 |
+
public function __construct($url, License $license)
|
44 |
+
{
|
45 |
+
$this->url = $url;
|
46 |
+
$this->license = $license;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Gets license status
|
51 |
+
*
|
52 |
+
* @return object
|
53 |
+
*/
|
54 |
+
public function get_license()
|
55 |
+
{
|
56 |
+
$endpoint = '/license';
|
57 |
+
$response = $this->request('GET', $endpoint);
|
58 |
+
return $response;
|
59 |
+
}
|
60 |
+
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Logs the current site in to the remote API
|
64 |
+
*
|
65 |
+
* @return object
|
66 |
+
*/
|
67 |
+
public function activate_license()
|
68 |
+
{
|
69 |
+
$endpoint = '/license/activations';
|
70 |
+
$args = array(
|
71 |
+
'site_url' => get_option('siteurl')
|
72 |
+
);
|
73 |
+
$response = $this->request('POST', $endpoint, $args);
|
74 |
+
return $response;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Logs the current site out of the remote API
|
79 |
+
*
|
80 |
+
* @return object
|
81 |
+
*/
|
82 |
+
public function deactivate_license()
|
83 |
+
{
|
84 |
+
$endpoint = sprintf('/license/activations/%s', $this->license->activation_key);
|
85 |
+
$response = $this->request('DELETE', $endpoint);
|
86 |
+
return $response;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param Plugin $plugin
|
91 |
+
* @return object
|
92 |
+
*/
|
93 |
+
public function get_plugin(Plugin $plugin)
|
94 |
+
{
|
95 |
+
$endpoint = sprintf('/plugins/%s?format=wp', $plugin->id());
|
96 |
+
$response = $this->request('GET', $endpoint);
|
97 |
+
return $response;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @param Plugin[] $plugins (optional)
|
102 |
+
* @return object
|
103 |
+
*/
|
104 |
+
public function get_plugins($plugins = null)
|
105 |
+
{
|
106 |
+
$args = array(
|
107 |
+
'format' => 'wp',
|
108 |
+
);
|
109 |
+
|
110 |
+
$endpoint = add_query_arg($args, '/plugins');
|
111 |
+
$response = $this->request('GET', $endpoint);
|
112 |
+
return $response;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @param string $method
|
117 |
+
* @param string $endpoint
|
118 |
+
* @param array $data
|
119 |
+
*
|
120 |
+
* @return object|array
|
121 |
+
*/
|
122 |
+
public function request($method, $endpoint, $data = array())
|
123 |
+
{
|
124 |
+
$url = $this->url . $endpoint;
|
125 |
+
$args = array(
|
126 |
+
'method' => $method,
|
127 |
+
'headers' => array(
|
128 |
+
'Content-Type' => 'application/json',
|
129 |
+
'Accepts' => 'application/json',
|
130 |
+
),
|
131 |
+
);
|
132 |
+
|
133 |
+
// add license key to headers if set
|
134 |
+
if (! empty($this->license->key)) {
|
135 |
+
$args['headers']['Authorization'] = 'Bearer ' . urlencode($this->license->key);
|
136 |
+
}
|
137 |
+
|
138 |
+
if (! empty($data)) {
|
139 |
+
if (in_array($method, array( 'GET', 'DELETE' ))) {
|
140 |
+
$url = add_query_arg($data, $url);
|
141 |
+
} else {
|
142 |
+
$args['body'] = json_encode($data);
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
$response = wp_remote_request($url, $args);
|
147 |
+
return $this->parse_response($response);
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param mixed $response
|
152 |
+
*
|
153 |
+
* @return object|null
|
154 |
+
*
|
155 |
+
* @throws API_Exception
|
156 |
+
*/
|
157 |
+
public function parse_response($response)
|
158 |
+
{
|
159 |
+
// test for wp errors (request failures)
|
160 |
+
if ($response instanceof WP_Error) {
|
161 |
+
throw new API_Exception($response->get_error_message());
|
162 |
+
}
|
163 |
+
|
164 |
+
// retrieve response body
|
165 |
+
$body = wp_remote_retrieve_body($response);
|
166 |
+
if (empty($body)) {
|
167 |
+
return null;
|
168 |
+
}
|
169 |
+
|
170 |
+
$json = json_decode($body, false);
|
171 |
+
if (is_null($json)) {
|
172 |
+
throw new API_Exception(__("The Boxzilla server returned an invalid response.", 'boxzilla'));
|
173 |
+
}
|
174 |
+
|
175 |
+
// did request return an error response?
|
176 |
+
if (wp_remote_retrieve_response_code($response) >= 400) {
|
177 |
+
throw new API_Exception($json->message, $json->code);
|
178 |
+
}
|
179 |
+
|
180 |
+
// return actual response data
|
181 |
+
return $json;
|
182 |
+
}
|
183 |
}
|
src/licensing/class-license-manager.php
CHANGED
@@ -6,177 +6,185 @@ use Boxzilla\Admin\Notices;
|
|
6 |
use Boxzilla\Collection;
|
7 |
use Exception;
|
8 |
|
9 |
-
class LicenseManager
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
6 |
use Boxzilla\Collection;
|
7 |
use Exception;
|
8 |
|
9 |
+
class LicenseManager
|
10 |
+
{
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var array
|
14 |
+
*/
|
15 |
+
protected $extensions = array();
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var License
|
19 |
+
*/
|
20 |
+
protected $license;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var API
|
24 |
+
*/
|
25 |
+
protected $api;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var array
|
29 |
+
*/
|
30 |
+
protected $notices = array();
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @param array $extensions
|
34 |
+
* @param API $api
|
35 |
+
* @param License $license
|
36 |
+
* @param Notices $notices
|
37 |
+
*/
|
38 |
+
public function __construct(array $extensions, API $api, License $license)
|
39 |
+
{
|
40 |
+
$this->extensions = $extensions;
|
41 |
+
$this->license = $license;
|
42 |
+
$this->api = $api;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param mixed $object
|
47 |
+
* @param string $property
|
48 |
+
* @param string $default
|
49 |
+
*
|
50 |
+
* @return string
|
51 |
+
*/
|
52 |
+
protected function get_object_property($object, $property, $default = '')
|
53 |
+
{
|
54 |
+
return isset($object->$property) ? $object->$property : $default;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @return void
|
59 |
+
*/
|
60 |
+
public function hook()
|
61 |
+
{
|
62 |
+
|
63 |
+
// do nothing if no extensions are registered at this point
|
64 |
+
if (empty($this->extensions)) {
|
65 |
+
return;
|
66 |
+
}
|
67 |
+
|
68 |
+
// hooks
|
69 |
+
add_action('boxzilla_after_settings', array( $this, 'show_license_form' ));
|
70 |
+
add_action('admin_notices', array( $this, 'show_notice' ), 1);
|
71 |
+
|
72 |
+
// listen for activation / deactivation requests
|
73 |
+
$this->listen();
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Maybe show notice to activate license.
|
78 |
+
*/
|
79 |
+
public function show_notice()
|
80 |
+
{
|
81 |
+
global $current_screen;
|
82 |
+
|
83 |
+
if ($this->license->activated) {
|
84 |
+
return;
|
85 |
+
}
|
86 |
+
|
87 |
+
if ($this->get_object_property($current_screen, 'post_type') !== 'boxzilla-box') {
|
88 |
+
return;
|
89 |
+
}
|
90 |
+
|
91 |
+
$plugin = $this->extensions[ array_rand($this->extensions) ];
|
92 |
+
$message = sprintf('Please <a href="%s">activate your Boxzilla license</a> to use %s.', admin_url('edit.php?post_type=boxzilla-box&page=boxzilla-settings'), '<strong>' . $plugin->name() . '</strong>');
|
93 |
+
echo sprintf('<div class="notice notice-%s"><p>%s</p></div>', 'warning', $message);
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* @return void
|
98 |
+
*/
|
99 |
+
protected function listen()
|
100 |
+
{
|
101 |
+
|
102 |
+
// do nothing if not authenticated
|
103 |
+
if (! current_user_can('manage_options')) {
|
104 |
+
return;
|
105 |
+
}
|
106 |
+
|
107 |
+
// nothing to do
|
108 |
+
if (! isset($_POST['boxzilla_license_form'])) {
|
109 |
+
return;
|
110 |
+
}
|
111 |
+
|
112 |
+
$action = isset($_POST['action']) ? $_POST['action'] : 'activate';
|
113 |
+
$key_changed = false;
|
114 |
+
|
115 |
+
// did key change or was "activate" button pressed?
|
116 |
+
$new_license_key = sanitize_text_field($_POST['boxzilla_license_key']);
|
117 |
+
if ($new_license_key !== $this->license->key) {
|
118 |
+
$this->license->key = $new_license_key;
|
119 |
+
$key_changed = true;
|
120 |
+
}
|
121 |
+
|
122 |
+
// run actions
|
123 |
+
if ($action === 'deactivate') {
|
124 |
+
$this->deactivate_license();
|
125 |
+
} elseif ($action === 'activate' || $key_changed) {
|
126 |
+
$this->activate_license();
|
127 |
+
}
|
128 |
+
|
129 |
+
$this->license->save();
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Deactivate the license
|
134 |
+
*/
|
135 |
+
protected function deactivate_license()
|
136 |
+
{
|
137 |
+
try {
|
138 |
+
$this->api->deactivate_license();
|
139 |
+
$this->notices[] = array(
|
140 |
+
'type' => 'info',
|
141 |
+
'message' => 'Your license was successfully deactivated!',
|
142 |
+
);
|
143 |
+
} catch (API_Exception $e) {
|
144 |
+
$this->notices[] = array(
|
145 |
+
'type' => 'warning',
|
146 |
+
'message' => $e->getMessage(),
|
147 |
+
);
|
148 |
+
}
|
149 |
+
|
150 |
+
$this->license->activated = false;
|
151 |
+
$this->license->activation_key = '';
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Activate the license
|
156 |
+
*/
|
157 |
+
protected function activate_license()
|
158 |
+
{
|
159 |
+
try {
|
160 |
+
$activation = $this->api->activate_license();
|
161 |
+
} catch (API_Exception $e) {
|
162 |
+
$message = $e->getMessage();
|
163 |
+
if ($e->getApiCode() == 'license_at_limit') {
|
164 |
+
$message .= ' You can <a href="https://platform.boxzillaplugin.com/licenses">manage your site activations here</a>.';
|
165 |
+
}
|
166 |
+
$this->notices[] = array(
|
167 |
+
'type' => 'warning',
|
168 |
+
'message' => $message,
|
169 |
+
);
|
170 |
+
return;
|
171 |
+
}
|
172 |
+
|
173 |
+
$this->license->activation_key = $activation->token;
|
174 |
+
$this->license->activated = true;
|
175 |
+
|
176 |
+
$this->notices[] = array(
|
177 |
+
'type' => 'info',
|
178 |
+
'message' => 'Your license was successfully activated!',
|
179 |
+
);
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Shows the license form
|
184 |
+
*/
|
185 |
+
public function show_license_form()
|
186 |
+
{
|
187 |
+
$license = $this->license;
|
188 |
+
require __DIR__ . '/views/license-form.php';
|
189 |
+
}
|
190 |
}
|
src/licensing/class-license-service-provider.php
CHANGED
@@ -2,38 +2,38 @@
|
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
-
use Boxzilla\DI\Container
|
6 |
-
|
7 |
-
|
8 |
-
class LicenseServiceProvider implements ServiceProviderInterface
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
}
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
+
use Boxzilla\DI\Container;
|
6 |
+
use Boxzilla\DI\ServiceProviderInterface;
|
7 |
+
|
8 |
+
class LicenseServiceProvider implements ServiceProviderInterface
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Registers all licensing related services
|
13 |
+
*
|
14 |
+
* @param Container $container
|
15 |
+
*/
|
16 |
+
public function register(Container $container)
|
17 |
+
{
|
18 |
+
$container['license'] = function ($container) {
|
19 |
+
return new License('boxzilla_license');
|
20 |
+
};
|
21 |
+
|
22 |
+
$container['license_api'] = function ($container) {
|
23 |
+
$api_url = 'https://my.boxzillaplugin.com/api/v2';
|
24 |
+
return new API($api_url, $container['license']);
|
25 |
+
};
|
26 |
+
|
27 |
+
$container['license_manager'] = function ($container) {
|
28 |
+
return new LicenseManager($container['plugins'], $container['license_api'], $container['license']);
|
29 |
+
};
|
30 |
+
|
31 |
+
$container['update_manager'] = function ($container) {
|
32 |
+
return new UpdateManager($container['plugins'], $container['license_api'], $container['license']);
|
33 |
+
};
|
34 |
+
|
35 |
+
$container['license_poller'] = function ($container) {
|
36 |
+
return new Poller($container['license_api'], $container['license']);
|
37 |
+
};
|
38 |
+
}
|
39 |
}
|
src/licensing/class-license.php
CHANGED
@@ -14,105 +14,112 @@ namespace Boxzilla\Licensing;
|
|
14 |
*
|
15 |
* @package Boxzilla\Licensing
|
16 |
*/
|
17 |
-
class License
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
}
|
14 |
*
|
15 |
* @package Boxzilla\Licensing
|
16 |
*/
|
17 |
+
class License
|
18 |
+
{
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var string The name of the option that holds the License data
|
22 |
+
*/
|
23 |
+
protected $option_key = '';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var bool Loaded?
|
27 |
+
*/
|
28 |
+
protected $loaded = false;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var bool Any changes?
|
32 |
+
*/
|
33 |
+
protected $dirty = false;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var array
|
37 |
+
*/
|
38 |
+
protected $data;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @param string $option_key
|
42 |
+
*/
|
43 |
+
public function __construct($option_key)
|
44 |
+
{
|
45 |
+
$this->option_key = $option_key;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param string $name
|
50 |
+
* @param mixed $value
|
51 |
+
*/
|
52 |
+
public function __set($name, $value)
|
53 |
+
{
|
54 |
+
$this->load();
|
55 |
+
$this->data[ $name ] = $value;
|
56 |
+
$this->dirty = true;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param string $name
|
61 |
+
*
|
62 |
+
* @return mixed
|
63 |
+
*/
|
64 |
+
public function __get($name)
|
65 |
+
{
|
66 |
+
$this->load();
|
67 |
+
return $this->data[ $name ];
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param $name
|
72 |
+
*
|
73 |
+
* @return bool
|
74 |
+
*/
|
75 |
+
public function __isset($name)
|
76 |
+
{
|
77 |
+
$this->load();
|
78 |
+
return isset($this->data[ $name ]);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Load the license data from the database
|
83 |
+
*/
|
84 |
+
protected function load()
|
85 |
+
{
|
86 |
+
if ($this->loaded) {
|
87 |
+
return;
|
88 |
+
}
|
89 |
+
|
90 |
+
$defaults = array(
|
91 |
+
'key' => '',
|
92 |
+
'activation_key' => '',
|
93 |
+
'activated' => false,
|
94 |
+
'expires_at' => ''
|
95 |
+
);
|
96 |
+
|
97 |
+
$data = (array) get_option($this->option_key, array());
|
98 |
+
$this->data = array_replace($defaults, $data);
|
99 |
+
$this->loaded = true;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Reload the license data from DB
|
104 |
+
*/
|
105 |
+
public function reload()
|
106 |
+
{
|
107 |
+
$this->loaded = false;
|
108 |
+
$this->load();
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Save the license in the database
|
113 |
+
*
|
114 |
+
* @return License
|
115 |
+
*/
|
116 |
+
public function save()
|
117 |
+
{
|
118 |
+
if (! $this->dirty) {
|
119 |
+
return;
|
120 |
+
}
|
121 |
+
|
122 |
+
update_option($this->option_key, $this->data);
|
123 |
+
$this->dirty = false;
|
124 |
+
}
|
125 |
}
|
src/licensing/class-poller.php
CHANGED
@@ -2,7 +2,8 @@
|
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
-
class Poller
|
|
|
6 |
|
7 |
/**
|
8 |
* @var API
|
@@ -20,7 +21,8 @@ class Poller {
|
|
20 |
* @param API $api
|
21 |
* @param License $license
|
22 |
*/
|
23 |
-
public function __construct(
|
|
|
24 |
$this->api = $api;
|
25 |
$this->license = $license;
|
26 |
}
|
@@ -28,20 +30,22 @@ class Poller {
|
|
28 |
/**
|
29 |
* Add hooks.
|
30 |
*/
|
31 |
-
public function hook()
|
32 |
-
|
33 |
-
|
|
|
34 |
};
|
35 |
|
36 |
-
add_action(
|
37 |
}
|
38 |
|
39 |
/**
|
40 |
* Run!
|
41 |
*/
|
42 |
-
public function run()
|
|
|
43 |
// don't run if license not active
|
44 |
-
if(
|
45 |
return;
|
46 |
}
|
47 |
|
@@ -51,17 +55,16 @@ class Poller {
|
|
51 |
try {
|
52 |
$remote_license = $this->api->get_license();
|
53 |
$license_still_valid = $remote_license->valid;
|
54 |
-
} catch(
|
55 |
// license key wasn't found or expired
|
56 |
-
if(
|
57 |
$license_still_valid = false;
|
58 |
}
|
59 |
}
|
60 |
|
61 |
-
if(
|
62 |
$this->license->activated = false;
|
63 |
$this->license->save();
|
64 |
}
|
65 |
-
|
66 |
}
|
67 |
-
}
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
+
class Poller
|
6 |
+
{
|
7 |
|
8 |
/**
|
9 |
* @var API
|
21 |
* @param API $api
|
22 |
* @param License $license
|
23 |
*/
|
24 |
+
public function __construct(API $api, License $license)
|
25 |
+
{
|
26 |
$this->api = $api;
|
27 |
$this->license = $license;
|
28 |
}
|
30 |
/**
|
31 |
* Add hooks.
|
32 |
*/
|
33 |
+
public function hook()
|
34 |
+
{
|
35 |
+
if (! wp_next_scheduled('boxzilla_check_license_status')) {
|
36 |
+
wp_schedule_event(time(), 'daily', 'boxzilla_check_license_status');
|
37 |
};
|
38 |
|
39 |
+
add_action('boxzilla_check_license_status', array( $this, 'run' ));
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
* Run!
|
44 |
*/
|
45 |
+
public function run()
|
46 |
+
{
|
47 |
// don't run if license not active
|
48 |
+
if (! $this->license->activated) {
|
49 |
return;
|
50 |
}
|
51 |
|
55 |
try {
|
56 |
$remote_license = $this->api->get_license();
|
57 |
$license_still_valid = $remote_license->valid;
|
58 |
+
} catch (API_Exception $e) {
|
59 |
// license key wasn't found or expired
|
60 |
+
if (in_array($e->getApiCode(), array( 'license_invalid', 'license_expired' ))) {
|
61 |
$license_still_valid = false;
|
62 |
}
|
63 |
}
|
64 |
|
65 |
+
if (! $license_still_valid) {
|
66 |
$this->license->activated = false;
|
67 |
$this->license->save();
|
68 |
}
|
|
|
69 |
}
|
70 |
+
}
|
src/licensing/class-update-manager.php
CHANGED
@@ -2,245 +2,253 @@
|
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
-
use Boxzilla\
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
146 |
}
|
147 |
|
148 |
// don't try if we failed a request recently.
|
149 |
-
$failed_at = get_transient(
|
150 |
-
if(
|
151 |
return array();
|
152 |
}
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
// set flag for 5 minutes
|
159 |
-
set_transient(
|
160 |
return array();
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
|
|
|
|
245 |
|
|
|
|
|
246 |
}
|
2 |
|
3 |
namespace Boxzilla\Licensing;
|
4 |
|
5 |
+
use Boxzilla\Plugin;
|
6 |
+
|
7 |
+
class UpdateManager
|
8 |
+
{
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var array
|
12 |
+
*/
|
13 |
+
protected $extensions = array();
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var API
|
17 |
+
*/
|
18 |
+
protected $api;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var License
|
22 |
+
*/
|
23 |
+
protected $license;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var
|
27 |
+
*/
|
28 |
+
protected $available_updates;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param array $extensions
|
32 |
+
* @param API $api
|
33 |
+
* @param License $license
|
34 |
+
*/
|
35 |
+
public function __construct(array $extensions, API $api, License $license)
|
36 |
+
{
|
37 |
+
$this->extensions = $extensions;
|
38 |
+
$this->license = $license;
|
39 |
+
$this->api = $api;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Add hooks
|
44 |
+
*/
|
45 |
+
public function hook()
|
46 |
+
{
|
47 |
+
add_filter('pre_set_site_transient_update_plugins', array( $this, 'add_updates' ));
|
48 |
+
add_filter('plugins_api', array( $this, 'get_plugin_info' ), 20, 3);
|
49 |
+
add_filter('http_request_args', array( $this, 'add_auth_headers' ), 10, 2);
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* This adds the license key header to download package requests.
|
54 |
+
*
|
55 |
+
* @param array $args
|
56 |
+
* @param string $url
|
57 |
+
*
|
58 |
+
* @return mixed
|
59 |
+
*/
|
60 |
+
public function add_auth_headers($args, $url)
|
61 |
+
{
|
62 |
+
// only act on download request's to the Boxzilla update API
|
63 |
+
if (strpos($url, $this->api->url) !== 0 || strpos($url, '/download') === false) {
|
64 |
+
return $args;
|
65 |
+
}
|
66 |
+
|
67 |
+
// only add if activation key not empty
|
68 |
+
if (empty($this->license->activation_key)) {
|
69 |
+
return $args;
|
70 |
+
}
|
71 |
+
|
72 |
+
if (! isset($args['headers'])) {
|
73 |
+
$args['headers'] = array();
|
74 |
+
}
|
75 |
+
|
76 |
+
$args['headers']['Authorization'] = sprintf('Bearer %s', $this->license->activation_key);
|
77 |
+
return $args;
|
78 |
+
}
|
79 |
+
|
80 |
+
private function get_plugin_by_slug($slug)
|
81 |
+
{
|
82 |
+
foreach ($this->extensions as $p) {
|
83 |
+
// find plugin by slug
|
84 |
+
if (dirname($p->slug()) === $slug) {
|
85 |
+
return $p;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
return null;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @param $result
|
94 |
+
* @param string $action
|
95 |
+
* @param null $args
|
96 |
+
*
|
97 |
+
* @return object
|
98 |
+
*/
|
99 |
+
public function get_plugin_info($result, $action = '', $args = null)
|
100 |
+
{
|
101 |
+
// do nothing for unrelated requests
|
102 |
+
if ($action !== 'plugin_information' || ! isset($args->slug)) {
|
103 |
+
return $result;
|
104 |
+
}
|
105 |
+
|
106 |
+
// only act on our own plugins
|
107 |
+
$plugin = $this->get_plugin_by_slug($args->slug);
|
108 |
+
if ($plugin === null) {
|
109 |
+
return $result;
|
110 |
+
}
|
111 |
+
|
112 |
+
return $this->get_update_info($plugin);
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @param object $updates
|
117 |
+
* @return object
|
118 |
+
*/
|
119 |
+
public function add_updates($updates)
|
120 |
+
{
|
121 |
+
|
122 |
+
// do nothing if no plugins registered
|
123 |
+
if (empty($this->extensions)) {
|
124 |
+
return $updates;
|
125 |
+
}
|
126 |
+
|
127 |
+
// failsafe WP bug
|
128 |
+
if (empty($updates) || ! isset($updates->response) || ! is_array($updates->response)) {
|
129 |
+
return $updates;
|
130 |
+
}
|
131 |
+
|
132 |
+
// fetch available updates
|
133 |
+
$available_updates = $this->fetch_updates();
|
134 |
+
|
135 |
+
// merge with other updates
|
136 |
+
$updates->response = array_merge($updates->response, $available_updates);
|
137 |
+
|
138 |
+
return $updates;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Fetch array of available updates from remote server
|
143 |
+
*
|
144 |
+
* @return array
|
145 |
+
*/
|
146 |
+
protected function fetch_updates()
|
147 |
+
{
|
148 |
+
if (is_array($this->available_updates)) {
|
149 |
+
return $this->available_updates;
|
150 |
}
|
151 |
|
152 |
// don't try if we failed a request recently.
|
153 |
+
$failed_at = get_transient('boxzilla_request_failed');
|
154 |
+
if (! empty($failed_at) && ((strtotime('now') - 300) < $failed_at)) {
|
155 |
return array();
|
156 |
}
|
157 |
|
158 |
+
// fetch remote info
|
159 |
+
try {
|
160 |
+
$remote_plugins = $this->api->get_plugins();
|
161 |
+
} catch (API_Exception $e) {
|
162 |
// set flag for 5 minutes
|
163 |
+
set_transient('boxzilla_request_failed', strtotime('now'), 300);
|
164 |
return array();
|
165 |
+
}
|
166 |
+
|
167 |
+
// filter remote plugins, we only want the ones with an update available
|
168 |
+
$this->available_updates = $this->filter_remote_plugins($remote_plugins);
|
169 |
+
|
170 |
+
return $this->available_updates;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* @param $remote_plugins
|
175 |
+
* @return array
|
176 |
+
*/
|
177 |
+
protected function filter_remote_plugins($remote_plugins)
|
178 |
+
{
|
179 |
+
$available_updates = array();
|
180 |
+
|
181 |
+
// find new versions
|
182 |
+
foreach ($remote_plugins as $remote_plugin) {
|
183 |
+
|
184 |
+
// only act on update info of our own plugins
|
185 |
+
if (! isset($this->extensions[ $remote_plugin->sid ])) {
|
186 |
+
continue;
|
187 |
+
}
|
188 |
+
|
189 |
+
// sanity check
|
190 |
+
if (! isset($remote_plugin->new_version)) {
|
191 |
+
continue;
|
192 |
+
}
|
193 |
+
|
194 |
+
// find corresponding local plugin
|
195 |
+
/** @var Plugin $local_plugin */
|
196 |
+
$local_plugin = $this->extensions[ $remote_plugin->sid ];
|
197 |
+
|
198 |
+
// plugin found and local plugin version not same as remote version?
|
199 |
+
if (! $local_plugin || version_compare($local_plugin->version(), $remote_plugin->new_version, '>=')) {
|
200 |
+
continue;
|
201 |
+
}
|
202 |
+
|
203 |
+
// add some dynamic data
|
204 |
+
$available_updates[ $local_plugin->slug() ] = $this->format_response($local_plugin, $remote_plugin);
|
205 |
+
}
|
206 |
+
|
207 |
+
return $available_updates;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* @param Plugin $plugin
|
212 |
+
*
|
213 |
+
* @return null
|
214 |
+
*/
|
215 |
+
public function get_update_info(Plugin $plugin)
|
216 |
+
{
|
217 |
+
$available_updates = $this->fetch_updates();
|
218 |
+
|
219 |
+
if (isset($available_updates[ $plugin->slug() ])) {
|
220 |
+
return $available_updates[ $plugin->slug() ];
|
221 |
+
}
|
222 |
+
|
223 |
+
return null;
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* @param Plugin $plugin
|
228 |
+
* @param $response
|
229 |
+
*
|
230 |
+
* @return mixed
|
231 |
+
*/
|
232 |
+
protected function format_response(Plugin $plugin, $response)
|
233 |
+
{
|
234 |
+
$response->slug = dirname($plugin->slug());
|
235 |
+
$response->plugin = $plugin->slug();
|
236 |
+
|
237 |
+
// add some notices if license is inactive
|
238 |
+
if (! $this->license->activated) {
|
239 |
+
$response->upgrade_notice = sprintf('You will need to <a href="%s">activate your license</a> to install this plugin update.', admin_url('edit.php?post_type=boxzilla-box&page=boxzilla-settings'));
|
240 |
+
$response->sections->changelog = '<p>' . sprintf('You will need to <a href="%s" target="_top">activate your license</a> to install this plugin update.', admin_url('edit.php?post_type=boxzilla-box&page=boxzilla-settings')) . '</p>' . $response->sections->changelog;
|
241 |
+
$response->package = null;
|
242 |
+
}
|
243 |
+
|
244 |
+
// cast subkey objects to array as that is what WP expects
|
245 |
+
$response->sections = get_object_vars($response->sections);
|
246 |
+
$response->banners = get_object_vars($response->banners);
|
247 |
+
$response->contributors = get_object_vars($response->contributors);
|
248 |
+
$response->contributors = array_map(function ($v) {
|
249 |
+
return get_object_vars($v);
|
250 |
+
}, $response->contributors);
|
251 |
|
252 |
+
return $response;
|
253 |
+
}
|
254 |
}
|
src/licensing/views/license-form.php
CHANGED
@@ -1,57 +1,66 @@
|
|
1 |
<?php
|
2 |
// prevent direct file access
|
3 |
-
defined(
|
4 |
|
5 |
/** @var Boxzilla\Licensing\License $license */
|
6 |
?>
|
7 |
|
8 |
-
<h2><?php _e(
|
9 |
|
10 |
-
<?php if(
|
|
|
11 |
<div class="error inline">
|
12 |
<p>
|
13 |
-
<strong><?php _e(
|
14 |
</p>
|
15 |
<ul class="ul-square">
|
16 |
-
<?php
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
?>
|
21 |
</ul>
|
22 |
<p>
|
23 |
To fix this, please activate your license using the form below.
|
24 |
</p>
|
25 |
</div>
|
26 |
-
<?php
|
|
|
27 |
|
28 |
-
<?php foreach(
|
|
|
29 |
<div class="notice notice-<?php echo $notice['type']; ?> inline">
|
30 |
<p><?php echo $notice['message']; ?></p>
|
31 |
</div>
|
32 |
-
<?php
|
|
|
33 |
|
34 |
<form method="post">
|
35 |
<table class="form-table">
|
36 |
<tr valign="top">
|
37 |
-
<th><?php _e(
|
38 |
<td>
|
39 |
-
<input size="40" name="boxzilla_license_key" placeholder="<?php esc_attr_e(
|
40 |
-
|
|
|
|
|
41 |
<p class="help">
|
42 |
-
<?php echo sprintf(
|
43 |
</p>
|
44 |
</td>
|
45 |
</tr>
|
46 |
<tr valign="top">
|
47 |
-
<th><?php _e(
|
48 |
<td>
|
49 |
<?php
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
55 |
</td>
|
56 |
</tr>
|
57 |
</table>
|
@@ -60,7 +69,7 @@ defined( 'ABSPATH' ) or exit;
|
|
60 |
|
61 |
|
62 |
<p>
|
63 |
-
<input type="submit" class="button button-primary" name="action" value="<?php _e(
|
64 |
</p>
|
65 |
|
66 |
<input type="hidden" name="boxzilla_license_form" value="1" />
|
1 |
<?php
|
2 |
// prevent direct file access
|
3 |
+
defined('ABSPATH') or exit;
|
4 |
|
5 |
/** @var Boxzilla\Licensing\License $license */
|
6 |
?>
|
7 |
|
8 |
+
<h2><?php _e('License & Plugin Updates', 'boxzilla'); ?></h2>
|
9 |
|
10 |
+
<?php if (! $license->activated) {
|
11 |
+
?>
|
12 |
<div class="error inline">
|
13 |
<p>
|
14 |
+
<strong><?php _e('Warning! You are <u>not</u> receiving plugin updates for the following plugin(s):', 'boxzilla'); ?></strong>
|
15 |
</p>
|
16 |
<ul class="ul-square">
|
17 |
+
<?php
|
18 |
+
foreach ($this->extensions as $p) {
|
19 |
+
echo '<li>' . esc_html($p->name()) . '</li>';
|
20 |
+
} ?>
|
|
|
21 |
</ul>
|
22 |
<p>
|
23 |
To fix this, please activate your license using the form below.
|
24 |
</p>
|
25 |
</div>
|
26 |
+
<?php
|
27 |
+
} ?>
|
28 |
|
29 |
+
<?php foreach ($this->notices as $notice) {
|
30 |
+
?>
|
31 |
<div class="notice notice-<?php echo $notice['type']; ?> inline">
|
32 |
<p><?php echo $notice['message']; ?></p>
|
33 |
</div>
|
34 |
+
<?php
|
35 |
+
} ?>
|
36 |
|
37 |
<form method="post">
|
38 |
<table class="form-table">
|
39 |
<tr valign="top">
|
40 |
+
<th><?php _e('License Key', 'boxzilla'); ?></th>
|
41 |
<td>
|
42 |
+
<input size="40" name="boxzilla_license_key" placeholder="<?php esc_attr_e('Enter your license key..', 'boxzilla'); ?>" value="<?php echo esc_attr($this->license->key); ?>" <?php if ($this->license->activated) {
|
43 |
+
echo 'readonly';
|
44 |
+
} ?> />
|
45 |
+
<input class="button" type="submit" name="action" value="<?php echo ($this->license->activated) ? 'deactivate' : 'activate'; ?>" />
|
46 |
<p class="help">
|
47 |
+
<?php echo sprintf(__('The license key received when purchasing your premium Boxzilla plan. <a href="%s">You can find it here</a>.', 'boxzilla'), 'https://platform.boxzillaplugin.com/'); ?>
|
48 |
</p>
|
49 |
</td>
|
50 |
</tr>
|
51 |
<tr valign="top">
|
52 |
+
<th><?php _e('License Status', 'boxzilla'); ?></th>
|
53 |
<td>
|
54 |
<?php
|
55 |
+
if ($license->activated) {
|
56 |
+
?>
|
57 |
+
<p><span class="status positive"><?php _e('ACTIVE', 'boxzilla'); ?></span> - <?php _e('you are receiving plugin updates', 'boxzilla'); ?></p>
|
58 |
+
<?php
|
59 |
+
} else {
|
60 |
+
?>
|
61 |
+
<p><span class="status negative"><?php _e('INACTIVE', 'boxzilla'); ?></span> - <?php _e('you are <strong>not</strong> receiving plugin updates', 'boxzilla'); ?></p>
|
62 |
+
<?php
|
63 |
+
} ?>
|
64 |
</td>
|
65 |
</tr>
|
66 |
</table>
|
69 |
|
70 |
|
71 |
<p>
|
72 |
+
<input type="submit" class="button button-primary" name="action" value="<?php _e('Save Changes'); ?>" />
|
73 |
</p>
|
74 |
|
75 |
<input type="hidden" name="boxzilla_license_form" value="1" />
|