Call Now Button - Version 1.1.14

Version Description

  • New buttons active by default (Cloud)
  • Visible on all screens is default (Cloud)
  • Changed folder naming for Upress customers
Download this release

Release Info

Developer jasperroel
Plugin Icon 128x128 Call Now Button
Version 1.1.14
Comparing to
See all releases

Code changes from version 1.1.12 to 1.1.14

call-now-button.php CHANGED
@@ -3,14 +3,14 @@
3
  Plugin Name: Call Now Button
4
  Plugin URI: https://callnowbutton.com
5
  Description: Mobile visitors will see a <strong>Call Now Button</strong> on your website. Easy to use but flexible to meet more demanding requirements. Change placement and color, hide on specific pages, track how many people click them or conversions of your Google Ads campaigns. It's all optional but possible.
6
- Version: 1.1.12
7
- Author: Jerry Rietveld
8
  Author URI: https://www.callnowbutton.com
9
  GitHub Plugin URI: https://github.com/callnowbutton/wp-plugin
10
  License: GPL2
11
  */
12
 
13
- /* Copyright 2013-2020 Jerry Rietveld (email : jerry@jgrietveld.com)
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License, version 2, as
@@ -26,7 +26,7 @@ License: GPL2
26
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
- define('CNB_VERSION', '1.1.12');
30
  define('CNB_NAME', 'Call Now Button');
31
  define('CNB_BASENAME', plugin_basename(__FILE__));
32
  define('CNB_BASEFOLDER', plugin_basename(dirname(__FILE__)));
3
  Plugin Name: Call Now Button
4
  Plugin URI: https://callnowbutton.com
5
  Description: Mobile visitors will see a <strong>Call Now Button</strong> on your website. Easy to use but flexible to meet more demanding requirements. Change placement and color, hide on specific pages, track how many people click them or conversions of your Google Ads campaigns. It's all optional but possible.
6
+ Version: 1.1.14
7
+ Author: Jerry & Jasper
8
  Author URI: https://www.callnowbutton.com
9
  GitHub Plugin URI: https://github.com/callnowbutton/wp-plugin
10
  License: GPL2
11
  */
12
 
13
+ /* Copyright 2013-2020 Jerry Rietveld (email : jerry@studiostacks.com)
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License, version 2, as
26
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
+ define('CNB_VERSION', '1.1.14');
30
  define('CNB_NAME', 'Call Now Button');
31
  define('CNB_BASENAME', plugin_basename(__FILE__));
32
  define('CNB_BASEFOLDER', plugin_basename(dirname(__FILE__)));
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: call button, click to call, convert, call now button, contact button
5
  Requires at least: 3.9
6
  Requires PHP: 5.4
7
  Tested up to: 6.0
8
- Stable tag: 1.1.12
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -111,6 +111,11 @@ Yes, you can upgrade to Premium to enable tons of extra features. Checkout [call
111
 
112
 
113
  == Changelog ==
 
 
 
 
 
114
  = 1.1.12 =
115
  * Small hotfix
116
 
5
  Requires at least: 3.9
6
  Requires PHP: 5.4
7
  Tested up to: 6.0
8
+ Stable tag: 1.1.14
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
111
 
112
 
113
  == Changelog ==
114
+ = 1.1.14 =
115
+ * New buttons active by default (Cloud)
116
+ * Visible on all screens is default (Cloud)
117
+ * Changed folder naming for Upress customers
118
+
119
  = 1.1.12 =
120
  * Small hotfix
121
 
resources/js/action-edit.js CHANGED
@@ -63,7 +63,41 @@ function cnb_add_sortable_to_action_table() {
63
  jQuery('.column-draggable', ele.parentElement).hide()
64
  }
65
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  jQuery(() => {
@@ -73,4 +107,7 @@ jQuery(() => {
73
  // This ensures that the default state matches the state of the page when it is loaded
74
  cnb_set_action_modal_fields()
75
  cnb_add_sortable_to_action_table()
 
 
 
76
  })
63
  jQuery('.column-draggable', ele.parentElement).hide()
64
  }
65
  })
66
+ }
67
+
68
+ function cnb_action_icon_background_image() {
69
+ jQuery('#cnb_action_icon_background_image').on('change input', () => {
70
+ jQuery('#cnb_action_icon_type').val('CUSTOM')
71
+ // Clear the custom icons
72
+ cnb_remove_all_icon_highlights()
73
+ })
74
+ }
75
+
76
+ function cnb_init_image_select() {
77
+ jQuery('#cnb_select_image').on('click', () => {
78
+ const image_frame = wp.media({
79
+ title: 'Select Image',
80
+ multiple : false,
81
+ library : {
82
+ type : 'image',
83
+ }
84
+ });
85
 
86
+ image_frame.on('close',function() {
87
+ const selection = image_frame.state().get('selection')
88
+ if (!selection || selection.length === 0) return
89
+
90
+ const first = selection.first()
91
+ if (!first) return
92
+
93
+ const selected = first.toJSON();
94
+ if (!selected) return
95
+
96
+ jQuery('#cnb_action_icon_background_image').val('url(' + selected.url + ')').trigger('change')
97
+ });
98
+
99
+ image_frame.open();
100
+ })
101
  }
102
 
103
  jQuery(() => {
107
  // This ensures that the default state matches the state of the page when it is loaded
108
  cnb_set_action_modal_fields()
109
  cnb_add_sortable_to_action_table()
110
+ // Set up the custom image property
111
+ cnb_action_icon_background_image()
112
+ cnb_init_image_select()
113
  })
resources/js/action-type-to-icon-text.js CHANGED
@@ -20,6 +20,9 @@ function cnbActiontypeToIcontext(actionType) {
20
  case 'FACEBOOK': return 'facebook_messenger'
21
  case 'SIGNAL': return 'signal'
22
  case 'TELEGRAM': return 'telegram'
 
 
 
23
  default:
24
  return 'call'
25
  }
@@ -120,11 +123,7 @@ function cnb_show_icon_text_advanced(ele) {
120
  return false;
121
  }
122
 
123
- /**
124
- *
125
- * @param {HTMLElement} ele the font icon clicked (can be empty in case of action-edit)
126
- */
127
- function cnb_hightlight_selected_icon_all(ele = null) {
128
  const all = jQuery("[data-icon-text-target]")
129
  all.each(function() {
130
  const findIcontextEle = jQuery(this).data('iconTextTarget')
@@ -140,6 +139,8 @@ function cnb_hightlight_selected_icon_each(iconTextEle, iconTypeEle) {
140
  const iconTextVal = iconTextEle.val()
141
  const iconTypeVal = iconTypeEle.val() === 'DEFAULT' ? 'FONT' : iconTypeEle.val()
142
 
 
 
143
  const selector = '.cnb-font-icon[data-icon-text="' + iconTextVal + '"][data-icon-type="' + iconTypeVal + '"]'
144
  const current = jQuery(selector)
145
 
@@ -148,6 +149,18 @@ function cnb_hightlight_selected_icon_each(iconTextEle, iconTypeEle) {
148
  if (current.length) {
149
  current.parent().addClass('cnb_icon_active')
150
  }
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
  function initUpdateIconText() {
20
  case 'FACEBOOK': return 'facebook_messenger'
21
  case 'SIGNAL': return 'signal'
22
  case 'TELEGRAM': return 'telegram'
23
+ case 'IFRAME': return 'link4'
24
+ case 'TALLY': return 'support'
25
+ case 'INTERCOM': return 'call3'
26
  default:
27
  return 'call'
28
  }
123
  return false;
124
  }
125
 
126
+ function cnb_hightlight_selected_icon_all() {
 
 
 
 
127
  const all = jQuery("[data-icon-text-target]")
128
  all.each(function() {
129
  const findIcontextEle = jQuery(this).data('iconTextTarget')
139
  const iconTextVal = iconTextEle.val()
140
  const iconTypeVal = iconTypeEle.val() === 'DEFAULT' ? 'FONT' : iconTypeEle.val()
141
 
142
+ if (iconTypeVal === 'CUSTOM') return
143
+
144
  const selector = '.cnb-font-icon[data-icon-text="' + iconTextVal + '"][data-icon-type="' + iconTypeVal + '"]'
145
  const current = jQuery(selector)
146
 
149
  if (current.length) {
150
  current.parent().addClass('cnb_icon_active')
151
  }
152
+
153
+ // Clear the custom image
154
+ cnb_remove_icon_background_image()
155
+ }
156
+
157
+ function cnb_remove_all_icon_highlights() {
158
+ jQuery('.cnb_icon_active').removeClass('cnb_icon_active')
159
+ }
160
+
161
+ function cnb_remove_icon_background_image() {
162
+ jQuery('#cnb_action_icon_background_image').val('')
163
+ jQuery('#cnb_action_icon_background_image').attr('value', '')
164
  }
165
 
166
  function initUpdateIconText() {
resources/js/button-edit.js ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function cnb_warn_if_inactive_on_save() {
2
+ const target = jQuery('#cnb-enable')
3
+ const message = jQuery('#cnb-button-save-inactive-message')
4
+ message.hide()
5
+ const result = !target.is(':checked')
6
+ if (result) {
7
+ message.show()
8
+ }
9
+ }
10
+
11
+ function cnb_warn_if_inactive_on_save_watcher() {
12
+ jQuery('#cnb-enable').on('change', cnb_warn_if_inactive_on_save)
13
+ cnb_warn_if_inactive_on_save()
14
+ }
15
+
16
+ function cnb_warn_if_mobile_only_on_save() {
17
+ const target = jQuery('#button_options_displaymode')
18
+ const message = jQuery('#cnb-button-save-mobile-only-message')
19
+ message.hide()
20
+ const result = target.val()
21
+ if (result === 'MOBILE_ONLY') {
22
+ message.show()
23
+ }
24
+ }
25
+
26
+ function cnb_warn_if_mobile_only_on_save_watcher() {
27
+ jQuery('#button_options_displaymode').on('change', cnb_warn_if_mobile_only_on_save)
28
+ cnb_warn_if_mobile_only_on_save()
29
+ }
30
+
31
+ function cnb_switch_to_tab(tabName) {
32
+ jQuery('[data-tab-name="' + tabName + '"').trigger('click')
33
+ }
34
+
35
+ jQuery(() => {
36
+ cnb_warn_if_inactive_on_save_watcher()
37
+ cnb_warn_if_mobile_only_on_save_watcher()
38
+ })
resources/js/call-now-button.js CHANGED
@@ -9,128 +9,128 @@ function cnb_setup_colors() {
9
  change: () => {
10
  jQuery(() => {
11
  if (typeof livePreview !== 'undefined') {
12
- livePreview();
13
  }
14
- });
15
 
16
  }
17
  }
18
 
19
  // Add color picker
20
- jQuery('.cnb-color-field').wpColorPicker(options);
21
- jQuery('.cnb-iconcolor-field').wpColorPicker(options);
22
  }
23
 
24
  function cnb_setup_placements() {
25
  // Reveal additional button placements when clicking "more"
26
  jQuery("#button-more-placements").on('click', function (e) {
27
- e.preventDefault();
28
- jQuery(".cnb-extra-placement").css("display", "block");
29
- jQuery("#button-more-placements").remove();
30
- });
31
  }
32
 
33
  function cnb_setup_sliders() {
34
  jQuery('#cnb_slider').on("input change", function() {
35
- cnb_update_sliders();
36
- });
37
  jQuery('#cnb_order_slider').on("input change", function() {
38
- cnb_update_sliders();
39
- });
40
- cnb_update_sliders();
41
  }
42
 
43
  function cnb_update_sliders() {
44
  // Zoom slider - show percentage
45
- const cnb_slider = document.getElementById("cnb_slider");
46
  if (cnb_slider && cnb_slider.value) {
47
- const cnb_slider_value = document.getElementById("cnb_slider_value");
48
- cnb_slider_value.innerHTML = '(' + Math.round(cnb_slider.value * 100) + '%)';
49
  }
50
 
51
  // Z-index slider - show steps
52
- const cnb_order_slider = document.getElementById("cnb_order_slider");
53
  if (cnb_order_slider && cnb_order_slider.value) {
54
- const cnb_order_value = document.getElementById("cnb_order_value");
55
- cnb_order_value.innerHTML = cnb_order_slider.value;
56
  }
57
  }
58
 
59
  function cnb_hide_on_show_always() {
60
- let show_always_checkbox = document.getElementById('actions_schedule_show_always');
61
  if (show_always_checkbox) {
62
  if (show_always_checkbox.checked) {
63
  // Hide all items specific for Scheduler
64
- jQuery('.cnb_hide_on_show_always').hide();
65
 
66
  // Hide Domain Timezone notice
67
- jQuery('.cnb-notice-domain-timezone-unsupported').parent('.notice').hide();
68
  } else {
69
  // Show all items specific for Scheduler
70
- jQuery('.cnb_hide_on_show_always').show();
71
 
72
  // Show Domain Timezone notice (and move to the correct place)
73
- const domainTimezoneNotice = jQuery('.cnb-notice-domain-timezone-unsupported').parent('.notice');
74
- domainTimezoneNotice.show();
75
- const domainTimezoneNoticePlaceholder = jQuery('#domain-timezone-notice-placeholder');
76
  if (domainTimezoneNoticePlaceholder.length !== 0) {
77
- domainTimezoneNotice.insertAfter(domainTimezoneNoticePlaceholder);
78
  }
79
  }
80
  }
81
- cnb_clean_up_advanced_view();
82
- return false;
83
  }
84
 
85
  function cnb_animate_saving() {
86
  jQuery('.call-now-button-plugin form.cnb-validation #submit').on('click', function (event) {
87
  // if value is saving, skip...
88
  if (jQuery(this).prop('value') === 'Saving...') {
89
- event.preventDefault();
90
- return;
91
  }
92
  // Check if the form will actually subbmit...
93
- const form = jQuery(this).closest('form');
94
- const valid = form[0].checkValidity();
95
  if (valid) {
96
- jQuery(this).addClass('is-busy');
97
- jQuery(this).prop('value', 'Saving...');
98
- jQuery(this).prop('aria-disabled', 'true');
99
  } else {
100
  // Clear old notices
101
- jQuery('.cnb-form-validation-notice').remove();
102
 
103
  const invalidFields = form.find(':invalid')
104
  // Find tab with error and switch to it if found
105
  const tabName = invalidFields.first().closest('[data-tab-name]').data('tabName')
106
  if (tabName) {
107
- cnb_switch_tab(tabName);
108
  }
109
  // Collect all errors and create notification
110
  invalidFields.each( function(index,node) {
111
- const inner = jQuery('<p/>');
112
- const notification = jQuery('<div />', {class: "cnb-form-validation-notice notice notice-warning"}).append(inner);
113
- const label = node.labels.length > 0 ? node.labels[0].innerText + ': ' : '';
114
- inner.text(label + node.validationMessage);
115
- notification.insertBefore(form.find('#submit'));
116
  })
117
  }
118
  })
119
  }
120
  function cnb_setup_toggle_label_clicks() {
121
  jQuery('.cnb_toggle_state').on( "click", function() {
122
- const stateLabel = jQuery(this).data('cnb_toggle_state_label');
123
- jQuery('#' + stateLabel).trigger('click');
124
- });
125
  }
126
 
127
  function cnb_action_appearance() {
128
  jQuery('#cnb_action_type').on('change', function (obj) {
129
- cnb_action_update_appearance(obj.target.value);
130
- });
131
 
132
  // Setup WHATSAPP integration
133
- const input = document.querySelector("#cnb_action_value_input_whatsapp");
134
  if (!input || !window.intlTelInput) {
135
  return
136
  }
@@ -140,7 +140,7 @@ function cnb_action_appearance() {
140
  nationalMode: false,
141
  separateDialCode: true,
142
  hiddenInput: 'actionValueWhatsappHidden'
143
- });
144
 
145
  // here, the index maps to the error code returned from getValidationError - see readme
146
  const errorMap = [
@@ -148,141 +148,169 @@ function cnb_action_appearance() {
148
  'Invalid country code',
149
  'Too short',
150
  'Too long',
151
- 'Invalid number'];
152
 
153
- const errorMsg = jQuery('#cnb-error-msg');
154
- const validMsg = jQuery('#cnb-valid-msg');
155
 
156
  const reset = function() {
157
- input.classList.remove('error');
158
- errorMsg.html('');
159
- errorMsg.hide();
160
- validMsg.hide();
161
- };
162
 
163
  const onBlur = function() {
164
- reset();
165
  if (input.value.trim()) {
166
  if (iti.isValidNumber()) {
167
- validMsg.show();
168
  } else {
169
- const errorCode = iti.getValidationError();
170
  if (errorCode < 0) {
171
  // Unknown error, ignore for now
172
  return
173
  }
174
- input.classList.add('error');
175
- errorMsg.text(errorMap[errorCode]);
176
- errorMsg.show();
177
  }
178
  } else {
179
  // Empty
180
- reset();
181
  }
182
  }
183
 
184
  // on blur: validate
185
- input.addEventListener('blur', onBlur);
186
 
187
  // on keyup / change flag: reset
188
- input.addEventListener('change', onBlur);
189
- input.addEventListener('keyup', onBlur);
190
 
191
  // init
192
- onBlur();
193
  }
194
 
195
  function cnb_action_update_appearance(value) {
196
- const emailEle = jQuery('.cnb-action-properties-email');
197
- const linkEle = jQuery('.cnb-action-properties-link');
198
- const emailExtraEle = jQuery('.cnb-action-properties-email-extra');
199
- const whatsappEle = jQuery('.cnb-action-properties-whatsapp');
200
- const signalEle = jQuery('.cnb-action-properties-signal');
201
- const whatsappExtraEle = jQuery('.cnb-action-properties-whatsapp-extra');
202
- const smsEle = jQuery('.cnb-action-properties-sms');
203
- const smsExtraEle = jQuery('.cnb-action-properties-sms-extra');
204
-
205
- const propertiesEle = jQuery('.cnb-action-properties-map');
206
- const valueEle = jQuery('.cnb-action-value');
207
- const valueTextEle = jQuery('#cnb_action_value_input');
208
- const valuelabelEle = jQuery('#cnb_action_value');
 
 
 
209
  const whatsappValueEle = jQuery('#cnb_action_value_input_whatsapp')
210
  const intlInputLabel = jQuery('#cnb_action_value_input_intl_input')
211
 
212
- emailEle.hide();
213
- emailExtraEle.hide();
214
- whatsappEle.hide();
215
- signalEle.hide();
216
- whatsappExtraEle.hide();
217
- smsEle.hide();
218
- smsExtraEle.hide();
219
- propertiesEle.hide();
220
  linkEle.hide()
 
 
 
221
 
222
- valueEle.show();
223
- valueTextEle.prop( 'disabled', false );
224
- whatsappValueEle.prop( 'disabled', true );
225
 
226
  valueTextEle.removeAttr("required")
227
  whatsappValueEle.removeAttr("required")
228
 
229
  switch (value) {
230
  case 'ANCHOR':
231
- valuelabelEle.text('On-page anchor');
232
- valueTextEle.attr("required", "required");
233
  break
234
  case 'EMAIL':
235
- valuelabelEle.text('E-mail address');
236
- valueTextEle.attr("required", "required");
237
  emailEle.show()
238
  break
239
  case 'LINK':
240
- valuelabelEle.text('Full URL');
241
- valueTextEle.attr("required", "required");
242
  linkEle.show()
243
  break
244
  case 'MAP':
245
- valuelabelEle.text('Address');
246
- valueTextEle.attr("required", "required");
247
- propertiesEle.show();
248
  break
249
  case 'PHONE':
250
- valuelabelEle.text('Phone number');
251
- valueTextEle.attr("required", "required");
252
  break
253
  case 'SMS':
254
- valuelabelEle.text('Phone number');
255
- valueTextEle.attr("required", "required");
256
- smsEle.show();
257
  break
258
  case 'WHATSAPP':
259
- valuelabelEle.text('WhatsApp number');
260
  intlInputLabel.text('WhatsApp number')
261
- valueEle.hide();
262
- valueTextEle.prop( 'disabled', true );
263
- whatsappValueEle.prop( 'disabled', false );
264
- whatsappValueEle.attr("required", "required");
265
- whatsappEle.show();
266
  break
267
  case 'FACEBOOK':
268
  case 'TELEGRAM':
269
- valuelabelEle.text('Username');
270
- valueTextEle.attr("required", "required");
271
  break
272
  case 'SIGNAL':
273
- valuelabelEle.text('Signal number');
274
  intlInputLabel.text('Signal number')
275
- valueEle.hide();
276
- valueTextEle.prop( 'disabled', true );
277
- whatsappValueEle.prop( 'disabled', false );
278
- whatsappValueEle.attr("required", "required");
279
- signalEle.show();
280
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  default:
282
- valuelabelEle.text('Action value');
283
- valueTextEle.attr("required", "required");
284
  }
285
- cnb_clean_up_advanced_view();
286
  }
287
 
288
  function cnb_action_update_map_link(element) {
@@ -290,24 +318,24 @@ function cnb_action_update_map_link(element) {
290
  }
291
 
292
  function cnb_hide_edit_action_if_advanced() {
293
- const element = jQuery('#toplevel_page_call-now-button li.current a');
294
  if (element.text() === 'Edit action') {
295
- element.removeAttr('href');
296
- element.css('cursor', 'default');
297
  }
298
  }
299
 
300
  function cnb_hide_edit_domain_upgrade_if_advanced() {
301
- const element = jQuery('#toplevel_page_call-now-button li.current a');
302
  if (element.text() === 'Upgrade domain') {
303
- element.removeAttr('href');
304
- element.css('cursor', 'default');
305
  }
306
  }
307
 
308
  function cnb_hide_on_modal() {
309
- jQuery('.cnb_hide_on_modal').hide();
310
- jQuery('.cnb_hide_on_modal input').removeAttr('required');
311
  }
312
 
313
  /**
@@ -317,20 +345,20 @@ function cnb_hide_on_modal() {
317
  * @returns {boolean}
318
  */
319
  function cnb_enable_advanced_view(ele) {
320
- window.cnb_show_advanced_view_only_set=1;
321
- cnb_clean_up_advanced_view();
322
- jQuery(ele.parentElement.parentElement).remove();
323
- return false;
324
  }
325
 
326
  function cnb_is_advanced_view() {
327
  return typeof window.cnb_show_advanced_view_only_set !== 'undefined' &&
328
  window.cnb_show_advanced_view_only_set &&
329
- window.cnb_show_advanced_view_only_set === 1;
330
  }
331
 
332
  function show_advanced_view_only() {
333
- jQuery('.cnb_advanced_view').show();
334
  }
335
 
336
  function cnb_clean_up_advanced_view() {
@@ -342,7 +370,7 @@ function cnb_clean_up_advanced_view() {
342
  }
343
 
344
  function cnb_strip_beta_from_referrer() {
345
- const referer = jQuery('input[name="_wp_http_referer"]');
346
  if (referer && referer.val()) {
347
  referer.val(referer.val().replace(/[?&]beta/, ''))
348
  referer.val(referer.val().replace(/[?&]api_key=[0-9a-z-]+/, ''))
@@ -358,14 +386,14 @@ function cnb_delete_action() {
358
  jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list span.delete a[data-ajax="true"]')
359
  .on('click', function(){
360
  // Prep data
361
- const id = jQuery(this).data('id');
362
- const bid = jQuery(this).data('bid');
363
  const data = {
364
  'action': 'cnb_delete_action',
365
  'id': id,
366
  'bid': bid,
367
  '_ajax_nonce': jQuery(this).data('wpnonce'),
368
- };
369
 
370
  // Send remove request
371
  jQuery.post(ajaxurl, data)
@@ -375,35 +403,35 @@ function cnb_delete_action() {
375
  cnb_actions = result.button.actions
376
  // livePreview is also called again below in case the Ajax call comes back before the fadeOut is done.
377
  if (typeof livePreview !== 'undefined') {
378
- livePreview();
379
  }
380
  }
381
- });
382
 
383
  // Remove container
384
- const action_row = jQuery(this).closest('tr');
385
- jQuery(action_row).css("background-color", "#ff726f");
386
  jQuery(action_row).fadeOut(function() {
387
- jQuery(action_row).css("background-color", "");
388
- jQuery(action_row).remove();
389
 
390
  // Special case: if this is the last item, show a "no items" row
391
- const remaining_items = jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list tr').length;
392
  if (!remaining_items) {
393
  // Add row
394
- jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list').html('<tr class="no-items"><td class="colspanchange" colspan="4">This button has no actions yet. Let\'s add one!</td></tr>');
395
  }
396
 
397
  // We call livePreview /again/ (in case the Ajax call comes back before the fadeOut is done).
398
  if (typeof livePreview !== 'undefined') {
399
- livePreview();
400
  }
401
- });
402
 
403
  // Remove ID from Button array
404
- jQuery('input[name^="actions['+id+']"').remove();
405
- return false;
406
- });
407
  }
408
 
409
  /**
@@ -411,64 +439,64 @@ function cnb_delete_action() {
411
  */
412
  function cnb_button_overview_modal() {
413
  jQuery(".cnb_type_selector_item").on('click', function(){
414
- jQuery(".cnb_type_selector_item").removeClass('cnb_type_selector_active');
415
- jQuery(this).addClass("cnb_type_selector_active");
416
- const cnbType = jQuery(this).attr("data-cnb-selection");
417
- jQuery('#button_type').val(cnbType);
418
- });
419
 
420
  jQuery("#cnb-button-overview-modal-add-new").on("click", function() {
421
  setTimeout(function () {
422
- jQuery("input[name='button[name]']").trigger("focus");
423
- });
424
- });
425
  }
426
 
427
  function cnb_button_overview_add_new_click() {
428
- jQuery("#cnb-button-overview-modal-add-new").trigger("click");
429
- return false;
430
  }
431
 
432
  function cnb_init_tabs() {
433
  jQuery('a.nav-tab').on('click', (e) => {
434
- e.preventDefault();
435
  return cnb_switch_tab(jQuery( e.target ).data('tabName'))
436
- });
437
  }
438
 
439
  function cnb_switch_tab(tabName, addToHistory = true) {
440
- const tab = jQuery('a.nav-tab[data-tab-name][data-tab-name="' + tabName + '"]');
441
- const tabContent = jQuery('table[data-tab-name][data-tab-name="' + tabName + '"], div[data-tab-name][data-tab-name="' + tabName + '"]');
442
 
443
  // Does tab name exist (if not, don't do anything)
444
- if (tab.length === 0) return false;
445
 
446
  // Hide all tabs
447
- const otherTabs = jQuery('a.nav-tab[data-tab-name][data-tab-name!="' + tabName + '"]');
448
- const otherTabsContent = jQuery('table[data-tab-name][data-tab-name!="' + tabName + '"], div[data-tab-name][data-tab-name!="' + tabName + '"]');
449
  otherTabs.removeClass('nav-tab-active')
450
- otherTabsContent.hide();
451
 
452
  // Display passed in tab
453
  tab.addClass('nav-tab-active')
454
- tabContent.show();
455
 
456
  // If there is an element keeping track of the tab, update it
457
  jQuery('input[name="tab"]').val(tabName)
458
 
459
  // Push this to URL
460
  if (addToHistory) {
461
- const url = new URL(window.location);
462
  const data = {
463
  cnb_switch_tab_event: true,
464
  tab_name: tabName
465
  }
466
 
467
- url.searchParams.set('tab', tabName);
468
- window.history.pushState(data, '', url);
469
  }
470
 
471
- return false;
472
  }
473
 
474
  function cnb_switch_tab_from_history_listener() {
@@ -477,25 +505,25 @@ function cnb_switch_tab_from_history_listener() {
477
  // Switch back but do NOT add this action to the history again to prevent loops
478
  cnb_switch_tab(event.state.tab_name, false)
479
  }
480
- });
481
  }
482
 
483
  function cnb_hide_add_new_on_error() {
484
  // Find an error box - if that exists, remove the "Add new" macro
485
  if (jQuery('.cnb-remove-add-new').length) {
486
- jQuery("li.toplevel_page_call-now-button li:contains('Add New') a").hide();
487
  }
488
  }
489
 
490
  function cnb_setup_pricing() {
491
  // Find the elements
492
- const elements = jQuery('.eur-per-month, .usd-per-month, .eur-discount, .usd-discount');
493
 
494
  // If there are elements, find the pricing (ajax call)
495
  if (elements.length) {
496
  const data = {
497
  'action': 'cnb_get_plans',
498
- };
499
  jQuery.post(ajaxurl, data)
500
  .done((result) => {
501
  // Fix the elements
@@ -514,35 +542,35 @@ function cnb_setup_pricing() {
514
 
515
  jQuery( function() {
516
  // Generic
517
- cnb_setup_colors();
518
- cnb_setup_placements();
519
- cnb_setup_sliders();
520
- cnb_hide_on_show_always();
521
- cnb_action_appearance();
522
- cnb_action_update_appearance(jQuery('#cnb_action_type').val());
523
- cnb_hide_edit_action_if_advanced();
524
- cnb_hide_edit_domain_upgrade_if_advanced();
525
- cnb_strip_beta_from_referrer();
526
- cnb_animate_saving();
527
- cnb_setup_toggle_label_clicks();
528
- cnb_switch_tab_from_history_listener();
529
 
530
  // Allow for tab switching to be dynamic
531
- cnb_init_tabs();
532
 
533
- cnb_clean_up_advanced_view();
534
 
535
  // This needs to go AFTER the "advanced_view" check so a modal does not get additional (unneeded) "advanced" items
536
  if (typeof cnb_hide_on_modal_set !== 'undefined' && cnb_hide_on_modal_set === 1) {
537
- cnb_hide_on_modal();
538
  }
539
 
540
  // page: button-edit (conditions tabs)
541
 
542
- cnb_delete_action();
543
- cnb_button_overview_modal();
544
 
545
- cnb_hide_add_new_on_error();
546
 
547
- cnb_setup_pricing();
548
- });
9
  change: () => {
10
  jQuery(() => {
11
  if (typeof livePreview !== 'undefined') {
12
+ livePreview()
13
  }
14
+ })
15
 
16
  }
17
  }
18
 
19
  // Add color picker
20
+ jQuery('.cnb-color-field').wpColorPicker(options)
21
+ jQuery('.cnb-iconcolor-field').wpColorPicker(options)
22
  }
23
 
24
  function cnb_setup_placements() {
25
  // Reveal additional button placements when clicking "more"
26
  jQuery("#button-more-placements").on('click', function (e) {
27
+ e.preventDefault()
28
+ jQuery(".cnb-extra-placement").css("display", "block")
29
+ jQuery("#button-more-placements").remove()
30
+ })
31
  }
32
 
33
  function cnb_setup_sliders() {
34
  jQuery('#cnb_slider').on("input change", function() {
35
+ cnb_update_sliders()
36
+ })
37
  jQuery('#cnb_order_slider').on("input change", function() {
38
+ cnb_update_sliders()
39
+ })
40
+ cnb_update_sliders()
41
  }
42
 
43
  function cnb_update_sliders() {
44
  // Zoom slider - show percentage
45
+ const cnb_slider = document.getElementById("cnb_slider")
46
  if (cnb_slider && cnb_slider.value) {
47
+ const cnb_slider_value = document.getElementById("cnb_slider_value")
48
+ cnb_slider_value.innerHTML = '(' + Math.round(cnb_slider.value * 100) + '%)'
49
  }
50
 
51
  // Z-index slider - show steps
52
+ const cnb_order_slider = document.getElementById("cnb_order_slider")
53
  if (cnb_order_slider && cnb_order_slider.value) {
54
+ const cnb_order_value = document.getElementById("cnb_order_value")
55
+ cnb_order_value.innerHTML = cnb_order_slider.value
56
  }
57
  }
58
 
59
  function cnb_hide_on_show_always() {
60
+ let show_always_checkbox = document.getElementById('actions_schedule_show_always')
61
  if (show_always_checkbox) {
62
  if (show_always_checkbox.checked) {
63
  // Hide all items specific for Scheduler
64
+ jQuery('.cnb_hide_on_show_always').hide()
65
 
66
  // Hide Domain Timezone notice
67
+ jQuery('.cnb-notice-domain-timezone-unsupported').parent('.notice').hide()
68
  } else {
69
  // Show all items specific for Scheduler
70
+ jQuery('.cnb_hide_on_show_always').show()
71
 
72
  // Show Domain Timezone notice (and move to the correct place)
73
+ const domainTimezoneNotice = jQuery('.cnb-notice-domain-timezone-unsupported').parent('.notice')
74
+ domainTimezoneNotice.show()
75
+ const domainTimezoneNoticePlaceholder = jQuery('#domain-timezone-notice-placeholder')
76
  if (domainTimezoneNoticePlaceholder.length !== 0) {
77
+ domainTimezoneNotice.insertAfter(domainTimezoneNoticePlaceholder)
78
  }
79
  }
80
  }
81
+ cnb_clean_up_advanced_view()
82
+ return false
83
  }
84
 
85
  function cnb_animate_saving() {
86
  jQuery('.call-now-button-plugin form.cnb-validation #submit').on('click', function (event) {
87
  // if value is saving, skip...
88
  if (jQuery(this).prop('value') === 'Saving...') {
89
+ event.preventDefault()
90
+ return
91
  }
92
  // Check if the form will actually subbmit...
93
+ const form = jQuery(this).closest('form')
94
+ const valid = form[0].checkValidity()
95
  if (valid) {
96
+ jQuery(this).addClass('is-busy')
97
+ jQuery(this).prop('value', 'Saving...')
98
+ jQuery(this).prop('aria-disabled', 'true')
99
  } else {
100
  // Clear old notices
101
+ jQuery('.cnb-form-validation-notice').remove()
102
 
103
  const invalidFields = form.find(':invalid')
104
  // Find tab with error and switch to it if found
105
  const tabName = invalidFields.first().closest('[data-tab-name]').data('tabName')
106
  if (tabName) {
107
+ cnb_switch_tab(tabName)
108
  }
109
  // Collect all errors and create notification
110
  invalidFields.each( function(index,node) {
111
+ const inner = jQuery('<p/>')
112
+ const notification = jQuery('<div />', {class: "cnb-form-validation-notice notice notice-warning"}).append(inner)
113
+ const label = node.labels.length > 0 ? node.labels[0].innerText + ': ' : ''
114
+ inner.text(label + node.validationMessage)
115
+ notification.insertBefore(form.find('#submit'))
116
  })
117
  }
118
  })
119
  }
120
  function cnb_setup_toggle_label_clicks() {
121
  jQuery('.cnb_toggle_state').on( "click", function() {
122
+ const stateLabel = jQuery(this).data('cnb_toggle_state_label')
123
+ jQuery('#' + stateLabel).trigger('click')
124
+ })
125
  }
126
 
127
  function cnb_action_appearance() {
128
  jQuery('#cnb_action_type').on('change', function (obj) {
129
+ cnb_action_update_appearance(obj.target.value)
130
+ })
131
 
132
  // Setup WHATSAPP integration
133
+ const input = document.querySelector("#cnb_action_value_input_whatsapp")
134
  if (!input || !window.intlTelInput) {
135
  return
136
  }
140
  nationalMode: false,
141
  separateDialCode: true,
142
  hiddenInput: 'actionValueWhatsappHidden'
143
+ })
144
 
145
  // here, the index maps to the error code returned from getValidationError - see readme
146
  const errorMap = [
148
  'Invalid country code',
149
  'Too short',
150
  'Too long',
151
+ 'Invalid number']
152
 
153
+ const errorMsg = jQuery('#cnb-error-msg')
154
+ const validMsg = jQuery('#cnb-valid-msg')
155
 
156
  const reset = function() {
157
+ input.classList.remove('error')
158
+ errorMsg.html('')
159
+ errorMsg.hide()
160
+ validMsg.hide()
161
+ }
162
 
163
  const onBlur = function() {
164
+ reset()
165
  if (input.value.trim()) {
166
  if (iti.isValidNumber()) {
167
+ validMsg.show()
168
  } else {
169
+ const errorCode = iti.getValidationError()
170
  if (errorCode < 0) {
171
  // Unknown error, ignore for now
172
  return
173
  }
174
+ input.classList.add('error')
175
+ errorMsg.text(errorMap[errorCode])
176
+ errorMsg.show()
177
  }
178
  } else {
179
  // Empty
180
+ reset()
181
  }
182
  }
183
 
184
  // on blur: validate
185
+ input.addEventListener('blur', onBlur)
186
 
187
  // on keyup / change flag: reset
188
+ input.addEventListener('change', onBlur)
189
+ input.addEventListener('keyup', onBlur)
190
 
191
  // init
192
+ onBlur()
193
  }
194
 
195
  function cnb_action_update_appearance(value) {
196
+ const emailEle = jQuery('.cnb-action-properties-email')
197
+ const linkEle = jQuery('.cnb-action-properties-link')
198
+ const emailExtraEle = jQuery('.cnb-action-properties-email-extra')
199
+ const whatsappEle = jQuery('.cnb-action-properties-whatsapp')
200
+ const signalEle = jQuery('.cnb-action-properties-signal')
201
+ const whatsappExtraEle = jQuery('.cnb-action-properties-whatsapp-extra')
202
+ const smsEle = jQuery('.cnb-action-properties-sms')
203
+ const smsExtraEle = jQuery('.cnb-action-properties-sms-extra')
204
+ const iframeEle = jQuery('.cnb-action-properties-iframe')
205
+ const tallyEle = jQuery('.cnb-action-properties-tally')
206
+ const intercomEle = jQuery('.cnb-action-properties-intercom')
207
+
208
+ const propertiesEle = jQuery('.cnb-action-properties-map')
209
+ const valueEle = jQuery('.cnb-action-value')
210
+ const valueTextEle = jQuery('#cnb_action_value_input')
211
+ const valuelabelEle = jQuery('#cnb_action_value')
212
  const whatsappValueEle = jQuery('#cnb_action_value_input_whatsapp')
213
  const intlInputLabel = jQuery('#cnb_action_value_input_intl_input')
214
 
215
+ emailEle.hide()
216
+ emailExtraEle.hide()
217
+ whatsappEle.hide()
218
+ signalEle.hide()
219
+ whatsappExtraEle.hide()
220
+ smsEle.hide()
221
+ smsExtraEle.hide()
222
+ propertiesEle.hide()
223
  linkEle.hide()
224
+ iframeEle.hide()
225
+ tallyEle.hide()
226
+ intercomEle.hide()
227
 
228
+ valueEle.show()
229
+ valueTextEle.prop( 'disabled', false )
230
+ whatsappValueEle.prop( 'disabled', true )
231
 
232
  valueTextEle.removeAttr("required")
233
  whatsappValueEle.removeAttr("required")
234
 
235
  switch (value) {
236
  case 'ANCHOR':
237
+ valuelabelEle.text('On-page anchor')
238
+ valueTextEle.attr("required", "required")
239
  break
240
  case 'EMAIL':
241
+ valuelabelEle.text('E-mail address')
242
+ valueTextEle.attr("required", "required")
243
  emailEle.show()
244
  break
245
  case 'LINK':
246
+ valuelabelEle.text('Full URL')
247
+ valueTextEle.attr("required", "required")
248
  linkEle.show()
249
  break
250
  case 'MAP':
251
+ valuelabelEle.text('Address')
252
+ valueTextEle.attr("required", "required")
253
+ propertiesEle.show()
254
  break
255
  case 'PHONE':
256
+ valuelabelEle.text('Phone number')
257
+ valueTextEle.attr("required", "required")
258
  break
259
  case 'SMS':
260
+ valuelabelEle.text('Phone number')
261
+ valueTextEle.attr("required", "required")
262
+ smsEle.show()
263
  break
264
  case 'WHATSAPP':
265
+ valuelabelEle.text('WhatsApp number')
266
  intlInputLabel.text('WhatsApp number')
267
+ valueEle.hide()
268
+ valueTextEle.prop( 'disabled', true )
269
+ whatsappValueEle.prop( 'disabled', false )
270
+ whatsappValueEle.attr("required", "required")
271
+ whatsappEle.show()
272
  break
273
  case 'FACEBOOK':
274
  case 'TELEGRAM':
275
+ valuelabelEle.text('Username')
276
+ valueTextEle.attr("required", "required")
277
  break
278
  case 'SIGNAL':
279
+ valuelabelEle.text('Signal number')
280
  intlInputLabel.text('Signal number')
281
+ valueEle.hide()
282
+ valueTextEle.prop( 'disabled', true )
283
+ whatsappValueEle.prop( 'disabled', false )
284
+ whatsappValueEle.attr("required", "required")
285
+ signalEle.show()
286
+ break
287
+ case 'IFRAME':
288
+ valuelabelEle.text('Iframe URL')
289
+ valueTextEle.attr("required", "required")
290
+ iframeEle.show()
291
+ break
292
+ case 'TALLY':
293
+ valuelabelEle.text('Tally')
294
+ valueTextEle.val('tally')
295
+ valueEle.hide()
296
+ valueTextEle.prop( 'disabled', true )
297
+ valueTextEle.attr("required", "required")
298
+ iframeEle.show()
299
+ tallyEle.show()
300
+ break
301
+ case 'INTERCOM':
302
+ valuelabelEle.text('Intercom')
303
+ valueTextEle.val('intercom')
304
+ valueEle.hide()
305
+ valueTextEle.prop( 'disabled', true )
306
+ valueTextEle.attr("required", "required")
307
+ intercomEle.show()
308
+ break
309
  default:
310
+ valuelabelEle.text('Action value')
311
+ valueTextEle.attr("required", "required")
312
  }
313
+ cnb_clean_up_advanced_view()
314
  }
315
 
316
  function cnb_action_update_map_link(element) {
318
  }
319
 
320
  function cnb_hide_edit_action_if_advanced() {
321
+ const element = jQuery('#toplevel_page_call-now-button li.current a')
322
  if (element.text() === 'Edit action') {
323
+ element.removeAttr('href')
324
+ element.css('cursor', 'default')
325
  }
326
  }
327
 
328
  function cnb_hide_edit_domain_upgrade_if_advanced() {
329
+ const element = jQuery('#toplevel_page_call-now-button li.current a')
330
  if (element.text() === 'Upgrade domain') {
331
+ element.removeAttr('href')
332
+ element.css('cursor', 'default')
333
  }
334
  }
335
 
336
  function cnb_hide_on_modal() {
337
+ jQuery('.cnb_hide_on_modal').hide()
338
+ jQuery('.cnb_hide_on_modal input').removeAttr('required')
339
  }
340
 
341
  /**
345
  * @returns {boolean}
346
  */
347
  function cnb_enable_advanced_view(ele) {
348
+ window.cnb_show_advanced_view_only_set=1
349
+ cnb_clean_up_advanced_view()
350
+ jQuery(ele.parentElement.parentElement).remove()
351
+ return false
352
  }
353
 
354
  function cnb_is_advanced_view() {
355
  return typeof window.cnb_show_advanced_view_only_set !== 'undefined' &&
356
  window.cnb_show_advanced_view_only_set &&
357
+ window.cnb_show_advanced_view_only_set === 1
358
  }
359
 
360
  function show_advanced_view_only() {
361
+ jQuery('.cnb_advanced_view').show()
362
  }
363
 
364
  function cnb_clean_up_advanced_view() {
370
  }
371
 
372
  function cnb_strip_beta_from_referrer() {
373
+ const referer = jQuery('input[name="_wp_http_referer"]')
374
  if (referer && referer.val()) {
375
  referer.val(referer.val().replace(/[?&]beta/, ''))
376
  referer.val(referer.val().replace(/[?&]api_key=[0-9a-z-]+/, ''))
386
  jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list span.delete a[data-ajax="true"]')
387
  .on('click', function(){
388
  // Prep data
389
+ const id = jQuery(this).data('id')
390
+ const bid = jQuery(this).data('bid')
391
  const data = {
392
  'action': 'cnb_delete_action',
393
  'id': id,
394
  'bid': bid,
395
  '_ajax_nonce': jQuery(this).data('wpnonce'),
396
+ }
397
 
398
  // Send remove request
399
  jQuery.post(ajaxurl, data)
403
  cnb_actions = result.button.actions
404
  // livePreview is also called again below in case the Ajax call comes back before the fadeOut is done.
405
  if (typeof livePreview !== 'undefined') {
406
+ livePreview()
407
  }
408
  }
409
+ })
410
 
411
  // Remove container
412
+ const action_row = jQuery(this).closest('tr')
413
+ jQuery(action_row).css("background-color", "#ff726f")
414
  jQuery(action_row).fadeOut(function() {
415
+ jQuery(action_row).css("background-color", "")
416
+ jQuery(action_row).remove()
417
 
418
  // Special case: if this is the last item, show a "no items" row
419
+ const remaining_items = jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list tr').length
420
  if (!remaining_items) {
421
  // Add row
422
+ jQuery('.cnb-button-edit-action-table tbody[data-wp-lists="list:cnb_list_action"]#the-list').html('<tr class="no-items"><td class="colspanchange" colspan="4">This button has no actions yet. Let\'s add one!</td></tr>')
423
  }
424
 
425
  // We call livePreview /again/ (in case the Ajax call comes back before the fadeOut is done).
426
  if (typeof livePreview !== 'undefined') {
427
+ livePreview()
428
  }
429
+ })
430
 
431
  // Remove ID from Button array
432
+ jQuery('input[name^="actions['+id+']"').remove()
433
+ return false
434
+ })
435
  }
436
 
437
  /**
439
  */
440
  function cnb_button_overview_modal() {
441
  jQuery(".cnb_type_selector_item").on('click', function(){
442
+ jQuery(".cnb_type_selector_item").removeClass('cnb_type_selector_active')
443
+ jQuery(this).addClass("cnb_type_selector_active")
444
+ const cnbType = jQuery(this).attr("data-cnb-selection")
445
+ jQuery('#button_type').val(cnbType)
446
+ })
447
 
448
  jQuery("#cnb-button-overview-modal-add-new").on("click", function() {
449
  setTimeout(function () {
450
+ jQuery("input[name='button[name]']").trigger("focus")
451
+ })
452
+ })
453
  }
454
 
455
  function cnb_button_overview_add_new_click() {
456
+ jQuery("#cnb-button-overview-modal-add-new").trigger("click")
457
+ return false
458
  }
459
 
460
  function cnb_init_tabs() {
461
  jQuery('a.nav-tab').on('click', (e) => {
462
+ e.preventDefault()
463
  return cnb_switch_tab(jQuery( e.target ).data('tabName'))
464
+ })
465
  }
466
 
467
  function cnb_switch_tab(tabName, addToHistory = true) {
468
+ const tab = jQuery('a.nav-tab[data-tab-name][data-tab-name="' + tabName + '"]')
469
+ const tabContent = jQuery('table[data-tab-name][data-tab-name="' + tabName + '"], div[data-tab-name][data-tab-name="' + tabName + '"]')
470
 
471
  // Does tab name exist (if not, don't do anything)
472
+ if (tab.length === 0) return false
473
 
474
  // Hide all tabs
475
+ const otherTabs = jQuery('a.nav-tab[data-tab-name][data-tab-name!="' + tabName + '"]')
476
+ const otherTabsContent = jQuery('table[data-tab-name][data-tab-name!="' + tabName + '"], div[data-tab-name][data-tab-name!="' + tabName + '"]')
477
  otherTabs.removeClass('nav-tab-active')
478
+ otherTabsContent.hide()
479
 
480
  // Display passed in tab
481
  tab.addClass('nav-tab-active')
482
+ tabContent.show()
483
 
484
  // If there is an element keeping track of the tab, update it
485
  jQuery('input[name="tab"]').val(tabName)
486
 
487
  // Push this to URL
488
  if (addToHistory) {
489
+ const url = new URL(window.location)
490
  const data = {
491
  cnb_switch_tab_event: true,
492
  tab_name: tabName
493
  }
494
 
495
+ url.searchParams.set('tab', tabName)
496
+ window.history.pushState(data, '', url)
497
  }
498
 
499
+ return false
500
  }
501
 
502
  function cnb_switch_tab_from_history_listener() {
505
  // Switch back but do NOT add this action to the history again to prevent loops
506
  cnb_switch_tab(event.state.tab_name, false)
507
  }
508
+ })
509
  }
510
 
511
  function cnb_hide_add_new_on_error() {
512
  // Find an error box - if that exists, remove the "Add new" macro
513
  if (jQuery('.cnb-remove-add-new').length) {
514
+ jQuery("li.toplevel_page_call-now-button li:contains('Add New') a").hide()
515
  }
516
  }
517
 
518
  function cnb_setup_pricing() {
519
  // Find the elements
520
+ const elements = jQuery('.eur-per-month, .usd-per-month, .eur-discount, .usd-discount')
521
 
522
  // If there are elements, find the pricing (ajax call)
523
  if (elements.length) {
524
  const data = {
525
  'action': 'cnb_get_plans',
526
+ }
527
  jQuery.post(ajaxurl, data)
528
  .done((result) => {
529
  // Fix the elements
542
 
543
  jQuery( function() {
544
  // Generic
545
+ cnb_setup_colors()
546
+ cnb_setup_placements()
547
+ cnb_setup_sliders()
548
+ cnb_hide_on_show_always()
549
+ cnb_action_appearance()
550
+ cnb_action_update_appearance(jQuery('#cnb_action_type').val())
551
+ cnb_hide_edit_action_if_advanced()
552
+ cnb_hide_edit_domain_upgrade_if_advanced()
553
+ cnb_strip_beta_from_referrer()
554
+ cnb_animate_saving()
555
+ cnb_setup_toggle_label_clicks()
556
+ cnb_switch_tab_from_history_listener()
557
 
558
  // Allow for tab switching to be dynamic
559
+ cnb_init_tabs()
560
 
561
+ cnb_clean_up_advanced_view()
562
 
563
  // This needs to go AFTER the "advanced_view" check so a modal does not get additional (unneeded) "advanced" items
564
  if (typeof cnb_hide_on_modal_set !== 'undefined' && cnb_hide_on_modal_set === 1) {
565
+ cnb_hide_on_modal()
566
  }
567
 
568
  // page: button-edit (conditions tabs)
569
 
570
+ cnb_delete_action()
571
+ cnb_button_overview_modal()
572
 
573
+ cnb_hide_add_new_on_error()
574
 
575
+ cnb_setup_pricing()
576
+ })
resources/js/domain-upgrade.js CHANGED
@@ -6,7 +6,7 @@ function cnb_domain_upgrade_hide_notice() {
6
  }
7
  }
8
 
9
- function showMessage(type='success', message='') {
10
  const cnb_notice = jQuery('.cnb-message');
11
 
12
  cnb_notice.hide();
@@ -37,7 +37,7 @@ function cnb_domain_upgrade_currency() {
37
  * @param planId
38
  */
39
  function cnb_get_checkout(planId) {
40
- showMessage('warning', 'Processing your request, please wait...')
41
 
42
  const data = {
43
  'action': 'cnb_get_checkout',
@@ -56,84 +56,16 @@ function cnb_get_checkout(planId) {
56
  */
57
  function cnb_goto_checkout(response) {
58
  if (typeof stripe === 'undefined') {
59
- showMessage('warning', 'Using alternate provider...');
60
  location.href = 'https://www.callnowbutton.com/stripe.html?s=' + response.message;
61
  }else if (response.status === 'success') {
62
- showMessage('success', 'Redirecting you...')
63
  stripe.redirectToCheckout({sessionId: response.message});
64
  }else if (response.status === 'error') {
65
- showMessage('warning', response.message)
66
  }
67
  }
68
-
69
- function cnb_domain_upgrade_notice_profile_saved() {
70
- showMessage('success', 'Your profile has been saved, click Upgrade to finish your order.')
71
-
72
- // Also go straight to checkout
73
- if (cnb_btn) {
74
- const className = '.' + cnb_btn;
75
- const ele = jQuery(className)
76
- ele.trigger('click');
77
- }
78
- }
79
-
80
- function do_cnb_ajax_submit_profile() {
81
- const form = jQuery('.cnb-settings-profile');
82
-
83
- // Prep data
84
- const formData = form.serialize();
85
- const data = {
86
- action: 'cnb_settings_profile_save',
87
- data: formData
88
- };
89
-
90
- const valid = form[0].checkValidity();
91
- if (valid) {
92
- try {
93
- jQuery.post({
94
- url: ajaxurl,
95
- data: data,
96
- success: function () {
97
- // Hide "Next", show "Upgrade"
98
- jQuery('.open-profile-details-modal').hide();
99
- jQuery('.button-upgrade').show();
100
-
101
- // Close box
102
- cnb_domain_upgrade_notice_profile_saved();
103
- jQuery('#TB_closeWindowButton').trigger('click');
104
- }
105
- });
106
- } catch (e) {
107
- showMessage('error', e.message);
108
- }
109
- } else {
110
- // Noop, show errors in the form itself
111
- form[0].reportValidity()
112
- }
113
- return false;
114
- }
115
-
116
- /**
117
- * This calls the admin-ajax action called 'cnb_settings_profile_save'
118
- *
119
- * This is used on the modal on domain-upgrade
120
- */
121
- function cnb_ajax_submit_profile() {
122
- jQuery('.cnb-settings-profile')
123
- .on('submit', function(e) {
124
- e.preventDefault();
125
- return do_cnb_ajax_submit_profile();
126
- });
127
- jQuery('.cnb-settings-profile #submit')
128
- .on('click', function(e){
129
- e.preventDefault();
130
- return do_cnb_ajax_submit_profile();
131
-
132
- });
133
- }
134
-
135
  jQuery(function () {
136
  cnb_domain_upgrade_hide_notice();
137
  cnb_domain_upgrade_currency();
138
- cnb_ajax_submit_profile();
139
  });
6
  }
7
  }
8
 
9
+ function cnb_stripe_show_message(type='success', message='') {
10
  const cnb_notice = jQuery('.cnb-message');
11
 
12
  cnb_notice.hide();
37
  * @param planId
38
  */
39
  function cnb_get_checkout(planId) {
40
+ cnb_stripe_show_message('warning', 'Processing your request, please wait...')
41
 
42
  const data = {
43
  'action': 'cnb_get_checkout',
56
  */
57
  function cnb_goto_checkout(response) {
58
  if (typeof stripe === 'undefined') {
59
+ cnb_stripe_show_message('warning', 'Using alternate provider...');
60
  location.href = 'https://www.callnowbutton.com/stripe.html?s=' + response.message;
61
  }else if (response.status === 'success') {
62
+ cnb_stripe_show_message('success', 'Redirecting you...')
63
  stripe.redirectToCheckout({sessionId: response.message});
64
  }else if (response.status === 'error') {
65
+ cnb_stripe_show_message('warning', response.message)
66
  }
67
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  jQuery(function () {
69
  cnb_domain_upgrade_hide_notice();
70
  cnb_domain_upgrade_currency();
 
71
  });
src/CallNowButton.php CHANGED
@@ -336,6 +336,12 @@ class CallNowButton {
336
  array( CNB_SLUG . '-call-now-button' ),
337
  CNB_VERSION,
338
  true );
 
 
 
 
 
 
339
  wp_register_script(
340
  CNB_SLUG . '-action-edit',
341
  plugins_url( '../resources/js/action-edit.js', __FILE__ ),
@@ -496,6 +502,13 @@ class CallNowButton {
496
 
497
  $profile_controller = new CnbProfileController();
498
  add_action( 'admin_post_cnb_profile_edit', array( $profile_controller, 'update' ) );
 
 
 
 
 
 
 
499
  }
500
 
501
  public function register_ajax_actions() {
336
  array( CNB_SLUG . '-call-now-button' ),
337
  CNB_VERSION,
338
  true );
339
+ wp_register_script(
340
+ CNB_SLUG . '-button-edit',
341
+ plugins_url( '../resources/js/button-edit.js', __FILE__ ),
342
+ array( CNB_SLUG . '-call-now-button' ),
343
+ CNB_VERSION,
344
+ true );
345
  wp_register_script(
346
  CNB_SLUG . '-action-edit',
347
  plugins_url( '../resources/js/action-edit.js', __FILE__ ),
502
 
503
  $profile_controller = new CnbProfileController();
504
  add_action( 'admin_post_cnb_profile_edit', array( $profile_controller, 'update' ) );
505
+
506
+ if (getenv('WORDPRESS_CALL_NOW_BUTTON_TESTS') == 1) {
507
+ $settings_controller = new CnbSettingsController();
508
+ add_action( 'admin_post_cnb_delete_all_settings', array( $settings_controller, 'delete_all_settings' ) );
509
+ add_action( 'admin_post_cnb_set_default_settings', array( $settings_controller, 'set_default_settings' ) );
510
+ add_action( 'admin_post_cnb_set_changelog_version', array( $settings_controller, 'override_changelog_version' ) );
511
+ }
512
  }
513
 
514
  public function register_ajax_actions() {
src/admin/action/CnbAction.php CHANGED
@@ -52,6 +52,8 @@ class CnbAction implements JsonSerializable {
52
 
53
  public $iconType = 'DEFAULT';
54
 
 
 
55
  public $labelBackgroundColor;
56
 
57
  public $labelText;
@@ -116,6 +118,7 @@ class CnbAction implements JsonSerializable {
116
  $action->iconColor = CnbUtils::getPropertyOrNull( $object, 'iconColor' );
117
  $action->iconText = CnbUtils::getPropertyOrNull( $object, 'iconText' );
118
  $action->iconType = CnbUtils::getPropertyOrNull( $object, 'iconType' );
 
119
  $action->labelBackgroundColor = CnbUtils::getPropertyOrNull( $object, 'labelBackgroundColor' );
120
  $action->labelText = CnbUtils::getPropertyOrNull( $object, 'labelText' );
121
 
@@ -172,6 +175,7 @@ class CnbAction implements JsonSerializable {
172
  'iconColor' => $this->iconColor,
173
  'iconText' => $this->iconText,
174
  'iconType' => $this->iconType,
 
175
  'labelBackgroundColor' => $this->labelBackgroundColor,
176
  'labelText' => $this->labelText,
177
  'schedule' => $this->schedule,
52
 
53
  public $iconType = 'DEFAULT';
54
 
55
+ public $iconBackgroundImage;
56
+
57
  public $labelBackgroundColor;
58
 
59
  public $labelText;
118
  $action->iconColor = CnbUtils::getPropertyOrNull( $object, 'iconColor' );
119
  $action->iconText = CnbUtils::getPropertyOrNull( $object, 'iconText' );
120
  $action->iconType = CnbUtils::getPropertyOrNull( $object, 'iconType' );
121
+ $action->iconBackgroundImage = CnbUtils::getPropertyOrNull( $object, 'iconBackgroundImage' );
122
  $action->labelBackgroundColor = CnbUtils::getPropertyOrNull( $object, 'labelBackgroundColor' );
123
  $action->labelText = CnbUtils::getPropertyOrNull( $object, 'labelText' );
124
 
175
  'iconColor' => $this->iconColor,
176
  'iconText' => $this->iconText,
177
  'iconType' => $this->iconType,
178
+ 'iconBackgroundImage' => $this->iconBackgroundImage,
179
  'labelBackgroundColor' => $this->labelBackgroundColor,
180
  'labelText' => $this->labelText,
181
  'schedule' => $this->schedule,
src/admin/action/CnbActionViewEdit.php CHANGED
@@ -146,12 +146,17 @@ class CnbActionViewEdit {
146
  wp_enqueue_script( 'jquery-ui-slider' );
147
  wp_enqueue_script( CNB_SLUG . '-action-edit-scheduler' );
148
 
 
 
 
149
  // Uses domain timezone if no timezone can be found
150
  $timezone = ( isset( $action->schedule ) && ! empty( $action->schedule->timezone ) ) ? $action->schedule->timezone : ( isset( $domain ) ? $domain->timezone : null );
151
  $action_tz_different_from_domain = isset( $domain ) && ! empty( $domain->timezone ) && $domain->timezone !== $timezone;
152
 
153
  $timezone_set_correctly = ( new CnbHeaderNotices() )->is_timezone_valid( $domain );
154
 
 
 
155
  ?>
156
  <input type="hidden" name="actions[<?php echo esc_attr( $action->id ) ?>][id]"
157
  value="<?php if ( $action->id !== null && $action->id !== 'new' ) {
@@ -341,6 +346,21 @@ class CnbActionViewEdit {
341
  <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="signal">signal</i>
342
  </div>
343
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
  <a
346
  href="#"
@@ -370,6 +390,45 @@ class CnbActionViewEdit {
370
  The Call Now Button uses the <code>filled</code> version of icons.</p>
371
  </td>
372
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
 
374
  <?php if ( $button && $button->type === 'SINGLE' ) { ?>
375
  <tr class="cnb_hide_on_modal cnb_advanced_view">
@@ -618,6 +677,158 @@ class CnbActionViewEdit {
618
  </td>
619
  </tr>
620
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  </table>
622
  <table data-tab-name="scheduler"
623
  class="form-table <?php echo esc_attr( $adminFunctions->is_active_tab( 'scheduler' ) ) ?>">
146
  wp_enqueue_script( 'jquery-ui-slider' );
147
  wp_enqueue_script( CNB_SLUG . '-action-edit-scheduler' );
148
 
149
+ // For the image selector
150
+ wp_enqueue_media();
151
+
152
  // Uses domain timezone if no timezone can be found
153
  $timezone = ( isset( $action->schedule ) && ! empty( $action->schedule->timezone ) ) ? $action->schedule->timezone : ( isset( $domain ) ? $domain->timezone : null );
154
  $action_tz_different_from_domain = isset( $domain ) && ! empty( $domain->timezone ) && $domain->timezone !== $timezone;
155
 
156
  $timezone_set_correctly = ( new CnbHeaderNotices() )->is_timezone_valid( $domain );
157
 
158
+ $isPro = $domain != null && !is_wp_error($domain) && $domain->type === 'PRO';
159
+
160
  ?>
161
  <input type="hidden" name="actions[<?php echo esc_attr( $action->id ) ?>][id]"
162
  value="<?php if ( $action->id !== null && $action->id !== 'new' ) {
346
  <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="signal">signal</i>
347
  </div>
348
  </div>
349
+ <div class="icon-text-options" id="icon-text-IFRAME">
350
+ <div class="cnb-button-icon">
351
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link4">link4</i>
352
+ </div>
353
+ </div>
354
+ <div class="icon-text-options" id="icon-text-TALLY">
355
+ <div class="cnb-button-icon">
356
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="support">support</i>
357
+ </div>
358
+ </div>
359
+ <div class="icon-text-options" id="icon-text-INTERCOM">
360
+ <div class="cnb-button-icon">
361
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="call3">call3</i>
362
+ </div>
363
+ </div>
364
 
365
  <a
366
  href="#"
390
  The Call Now Button uses the <code>filled</code> version of icons.</p>
391
  </td>
392
  </tr>
393
+ <tr class="cnb_advanced_view">
394
+ <th scope="row">
395
+ <label for="cnb_select_image">
396
+ <span>Image</span>
397
+ </label>
398
+
399
+ </th>
400
+ <td>
401
+ <input
402
+ type="hidden"
403
+ name="actions[<?php echo esc_attr( $action->id ) ?>][iconBackgroundImage]"
404
+ value="<?php echo esc_attr( $action->iconBackgroundImage ) ?>"
405
+ id="cnb_action_icon_background_image"/>
406
+ <input
407
+ type='button'
408
+ class="button-primary" value="<?php esc_attr_e( 'Select image' ); ?>"
409
+ id="cnb_select_image"
410
+ <?php if (!$isPro) { ?>disabled="disabled"<?php } ?>
411
+ />
412
+ <?php if (!empty($action->iconBackgroundImage) && stripos($action->iconBackgroundImage, 'url(') !== false) {
413
+ $clean = str_replace(')', '', str_replace('url(', '', $action->iconBackgroundImage)) ?>
414
+ <br />Currently set via your media gallery:<br /><img id="cnb_selected_image" src="<?php echo esc_attr($clean) ?>" alt="Action background image" style="max-height: 100px;max-width: 100px;"/>
415
+ <?php } ?>
416
+ <p class="description">Instead of an icon, you can choose to use an image from your Media Library.</p>
417
+ <?php if (!$isPro && $domain) {
418
+ $upgrade_link =
419
+ add_query_arg( array(
420
+ 'page' => 'call-now-button-domains',
421
+ 'action' => 'upgrade',
422
+ 'id' => $domain->id
423
+ ),
424
+ admin_url( 'admin.php' ) );
425
+ ?>
426
+ <p class="description">
427
+ <a href="<?php echo esc_url( $upgrade_link ) ?>">Upgrade</a> to unlock this <span class="cnb-pro-badge">Pro</span> feature.
428
+ </p>
429
+ <?php } ?>
430
+ </td>
431
+ </tr>
432
 
433
  <?php if ( $button && $button->type === 'SINGLE' ) { ?>
434
  <tr class="cnb_hide_on_modal cnb_advanced_view">
677
  </td>
678
  </tr>
679
 
680
+ <tr class="cnb-action-properties-iframe">
681
+ <th colspan="2">
682
+ <hr/>
683
+ </th>
684
+ </tr>
685
+ <tr class="cnb-action-properties-iframe">
686
+ <th scope="row"><label for="cnb-action-properties-iframe-title">Iframe Title</label></th>
687
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-title"
688
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-title]" type="text"
689
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-title'} ) ) {
690
+ echo esc_attr( $action->properties->{'iframe-title'} );
691
+ } ?>"/>
692
+ <p class="description">This will display a header, including the icon selected above and a "close" icon</p>
693
+ </td>
694
+ </tr>
695
+ <tr class="cnb-action-properties-iframe">
696
+ <th scope="row"><label for="cnb-action-properties-iframe-width">Iframe Width</label></th>
697
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-width"
698
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-width]" type="text"
699
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-width'} ) ) {
700
+ echo esc_attr( $action->properties->{'iframe-width'} );
701
+ } ?>"/>
702
+ <p class="description">Width of the iframe (max 400px).</p>
703
+ </td>
704
+ </tr>
705
+ <tr class="cnb-action-properties-iframe">
706
+ <th scope="row"><label for="cnb-action-properties-iframe-height">Iframe Height</label></th>
707
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-height"
708
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-height]" type="text"
709
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-height'} ) ) {
710
+ echo esc_attr( $action->properties->{'iframe-height'} );
711
+ } ?>"/>
712
+ <p class="description">Height of the iframe (min 100px).</p>
713
+ </td>
714
+ </tr>
715
+ <tr class="cnb-action-properties-iframe">
716
+ <th scope="row"><label for="cnb-action-properties-iframe-frameborder">Iframe Frameborder</label></th>
717
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-frameborder"
718
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-frameborder]" type="text"
719
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-frameborder'} ) ) {
720
+ echo esc_attr( $action->properties->{'iframe-frameborder'} );
721
+ } ?>"/>
722
+ <p class="description">1 or 0</p>
723
+ </td>
724
+ </tr>
725
+ <tr class="cnb-action-properties-iframe">
726
+ <th scope="row"><label for="cnb-action-properties-iframe-marginheight">Iframe Marginheight</label></th>
727
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-marginheight"
728
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-marginheight]" type="text"
729
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-marginheight'} ) ) {
730
+ echo esc_attr( $action->properties->{'iframe-marginheight'} );
731
+ } ?>"/>
732
+ <p class="description">obsolete? Sets <code>marginheight</code> on the iframe</p>
733
+ </td>
734
+ </tr>
735
+ <tr class="cnb-action-properties-iframe">
736
+ <th scope="row"><label for="cnb-action-properties-iframe-marginwidth">Iframe Marginwidth</label></th>
737
+ <td><input placeholder="Optional" id="cnb-action-properties-iframe-marginwidth"
738
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][iframe-marginwidth]" type="text"
739
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'iframe-marginwidth'} ) ) {
740
+ echo esc_attr( $action->properties->{'iframe-marginwidth'} );
741
+ } ?>"/>
742
+ <p class="description">obsolete? Sets <code>marginwidth</code> on the iframe</p>
743
+ </td>
744
+ </tr>
745
+ <tr class="cnb-action-properties-tally">
746
+ <th scope="row"><label for="cnb-action-properties-tally-id">Tally form ID</label></th>
747
+ <td><input placeholder="Optional" id="cnb-action-properties-tally-id"
748
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][tally-id]" type="text"
749
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'tally-id'} ) ) {
750
+ echo esc_attr( $action->properties->{'tally-id'} );
751
+ } ?>"/>
752
+ <p class="description">Tally form ID (last of the Share Link, e.g. <code>wA74do</code> for <code>https://tally.so/r/wA74do</code>.</p>
753
+ </td>
754
+ </tr>
755
+ <tr class="cnb-action-properties-tally">
756
+ <th scope="row"><label for="cnb-action-properties-tally-hide-title">Hide Title</label></th>
757
+ <td><input placeholder="Optional" id="cnb-action-properties-tally-hide-title"
758
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][tally-hide-title]" type="text"
759
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'tally-hide-title'} ) ) {
760
+ echo esc_attr( $action->properties->{'tally-hide-title'} );
761
+ } ?>"/>
762
+ <p class="description">Hide the title from the Tally form.</p>
763
+ </td>
764
+ </tr>
765
+ <tr class="cnb-action-properties-tally">
766
+ <th scope="row"><label for="cnb-action-properties-tally-transparent-background">Transparent Background</label></th>
767
+ <td><input placeholder="Optional" id="cnb-action-properties-tally-transparent-background"
768
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][tally-transparent-background]" type="text"
769
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'tally-transparent-background'} ) ) {
770
+ echo esc_attr( $action->properties->{'tally-transparent-background'} );
771
+ } ?>"/>
772
+ <p class="description">1 for transparant, 0 for white</p>
773
+ </td>
774
+ </tr>
775
+ <tr class="cnb-action-properties-tally">
776
+ <th scope="row"><label for="cnb-action-properties-tally-align-left">Align Left</label></th>
777
+ <td><input placeholder="Optional" id="cnb-action-properties-tally-align-left"
778
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][tally-align-left]" type="text"
779
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'tally-align-left'} ) ) {
780
+ echo esc_attr( $action->properties->{'tally-align-left'} );
781
+ } ?>"/>
782
+ <p class="description">1 for alight left, 0 for default</p>
783
+ </td>
784
+ </tr>
785
+
786
+ <tr class="cnb-action-properties-intercom">
787
+ <th colspan="2">
788
+ <hr/>
789
+ </th>
790
+ </tr>
791
+ <tr class="cnb-action-properties-intercom">
792
+ <th scope="row"><label for="cnb-action-properties-intercom-app-id">App ID</label></th>
793
+ <td><input placeholder="Optional" id="cnb-action-properties-intercom-app-id"
794
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][intercom-app-id]" type="text"
795
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'intercom-app-id'} ) ) {
796
+ echo esc_attr( $action->properties->{'intercom-app-id'} );
797
+ } ?>"/>
798
+ <p class="description">Your intercom app ID, something like <code>p7okjh23</code>.</p>
799
+ </td>
800
+ </tr>
801
+ <tr class="cnb-action-properties-intercom">
802
+ <th scope="row"><label for="cnb-action-properties-intercom-alignment">Alignment</label></th>
803
+ <td><input placeholder="Optional" id="cnb-action-properties-intercom-alignment"
804
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][intercom-alignment]" type="text"
805
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'intercom-alignment'} ) ) {
806
+ echo esc_attr( $action->properties->{'intercom-alignment'} );
807
+ } ?>"/>
808
+ <p class="description"><code>left</code> or <code>right</code> (default).</p>
809
+ </td>
810
+ </tr>
811
+ <tr class="cnb-action-properties-intercom">
812
+ <th scope="row"><label for="cnb-action-properties-intercom-horizontal-padding">Horizontal padding</label></th>
813
+ <td><input placeholder="Optional" id="cnb-action-properties-intercom-horizontal-padding"
814
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][intercom-horizontal-padding]" type="text"
815
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'intercom-horizontal-padding'} ) ) {
816
+ echo esc_attr( $action->properties->{'intercom-horizontal-padding'} );
817
+ } ?>"/>
818
+ <p class="description">Horizontal padding (in whole numbers), defaults to <code>0</code>.</p>
819
+ </td>
820
+ </tr>
821
+ <tr class="cnb-action-properties-intercom">
822
+ <th scope="row"><label for="cnb-action-properties-intercom-vertical-padding">Vertical padding</label></th>
823
+ <td><input placeholder="Optional" id="cnb-action-properties-intercom-vertical-padding"
824
+ name="actions[<?php echo esc_attr( $action->id ) ?>][properties][intercom-vertical-padding]" type="text"
825
+ value="<?php if ( isset( $action->properties ) && isset( $action->properties->{'intercom-vertical-padding'} ) ) {
826
+ echo esc_attr( $action->properties->{'intercom-vertical-padding'} );
827
+ } ?>"/>
828
+ <p class="description">Vertical padding (in whole numbers), defaults to <code>0</code>.</p>
829
+ </td>
830
+ </tr>
831
+
832
  </table>
833
  <table data-tab-name="scheduler"
834
  class="form-table <?php echo esc_attr( $adminFunctions->is_active_tab( 'scheduler' ) ) ?>">
src/admin/{apikey → api-key}/CnbApiKey.php RENAMED
File without changes
src/admin/{apikey → api-key}/CnbApiKeyController.php RENAMED
File without changes
src/admin/{apikey → api-key}/CnbApiKeyRouter.php RENAMED
File without changes
src/admin/{apikey → api-key}/CnbApiKeyView.php RENAMED
File without changes
src/admin/{apikey → api-key}/Cnb_Apikey_List_Table.php RENAMED
File without changes
src/admin/api-key/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php // Silence is golden
2
+ // Folder name is api-key instead of apikey so uPress doesn't keep deleting this folder (issue #738)
src/admin/api/CnbAppRemote.php CHANGED
@@ -764,9 +764,20 @@ class CnbAppRemote {
764
  * @return StripeBillingPortal
765
  */
766
  public static function cnb_remote_create_billing_portal() {
 
 
 
 
 
 
 
 
 
 
 
767
  $rest_endpoint = '/v1/stripe/createBillingPortal';
768
 
769
- return StripeBillingPortal::fromObject(self::cnb_remote_post( $rest_endpoint ));
770
  }
771
 
772
  /**
764
  * @return StripeBillingPortal
765
  */
766
  public static function cnb_remote_create_billing_portal() {
767
+ $return_link =
768
+ add_query_arg(
769
+ array(
770
+ 'page' => 'call-now-button-settings',
771
+ 'tab' => 'account_options',
772
+ ),
773
+ admin_url( 'admin.php' ) );
774
+
775
+ $body = array(
776
+ 'returnUrl' => $return_link
777
+ );
778
  $rest_endpoint = '/v1/stripe/createBillingPortal';
779
 
780
+ return StripeBillingPortal::fromObject(self::cnb_remote_post( $rest_endpoint, $body ));
781
  }
782
 
783
  /**
src/admin/api/CnbAppRemotePayment.php CHANGED
@@ -36,7 +36,7 @@ class CnbAppRemotePayment {
36
  'callbackUri' => $callbackUri
37
  );
38
 
39
- $rest_endpoint = '/v1/subscription';
40
 
41
  return CnbAppRemote::cnb_remote_post( $rest_endpoint, $body );
42
  }
36
  'callbackUri' => $callbackUri
37
  );
38
 
39
+ $rest_endpoint = '/v1/subscription/v2';
40
 
41
  return CnbAppRemote::cnb_remote_post( $rest_endpoint, $body );
42
  }
src/admin/apikey/index.php DELETED
@@ -1 +0,0 @@
1
- <?php // Silence is golden
 
src/admin/button/CnbButton.php CHANGED
@@ -72,16 +72,17 @@ class CnbButton implements JsonSerializable {
72
  * @return CnbButton
73
  */
74
  public static function createDummyButton( $domain = null ) {
75
- $button = new CnbButton();
76
- $button->id = '';
77
- $button->active = false;
78
- $button->name = '';
79
- $button->type = 'SINGLE';
80
- $button->domain = $domain;
81
- $button->actions = array();
82
- $button->conditions = array();
83
- $button->options = new CnbButtonOptions();
84
- $button->options->placement = 'BOTTOM_RIGHT';
 
85
 
86
  return $button;
87
  }
72
  * @return CnbButton
73
  */
74
  public static function createDummyButton( $domain = null ) {
75
+ $button = new CnbButton();
76
+ $button->id = '';
77
+ $button->active = true;
78
+ $button->name = '';
79
+ $button->type = 'SINGLE';
80
+ $button->domain = $domain;
81
+ $button->actions = array();
82
+ $button->conditions = array();
83
+ $button->options = new CnbButtonOptions();
84
+ $button->options->placement = 'BOTTOM_RIGHT';
85
+ $button->options->displayMode = 'ALWAYS';
86
 
87
  return $button;
88
  }
src/admin/button/CnbButtonViewEdit.php CHANGED
@@ -117,6 +117,7 @@ class CnbButtonViewEdit {
117
  wp_enqueue_script( CNB_SLUG . '-form-to-json' );
118
  wp_enqueue_script( CNB_SLUG . '-preview' );
119
  wp_enqueue_script( CNB_SLUG . '-client' );
 
120
  wp_enqueue_script( CNB_SLUG . '-action-edit' );
121
  wp_enqueue_script( CNB_SLUG . '-condition-edit' );
122
  wp_enqueue_style( CNB_SLUG . '-client' );
@@ -608,6 +609,10 @@ class CnbButtonViewEdit {
608
  </div>
609
 
610
  <?php submit_button( $submit_button_text ); ?>
 
 
 
 
611
  </form>
612
  <?php
613
  }
117
  wp_enqueue_script( CNB_SLUG . '-form-to-json' );
118
  wp_enqueue_script( CNB_SLUG . '-preview' );
119
  wp_enqueue_script( CNB_SLUG . '-client' );
120
+ wp_enqueue_script( CNB_SLUG . '-button-edit' );
121
  wp_enqueue_script( CNB_SLUG . '-action-edit' );
122
  wp_enqueue_script( CNB_SLUG . '-condition-edit' );
123
  wp_enqueue_style( CNB_SLUG . '-client' );
609
  </div>
610
 
611
  <?php submit_button( $submit_button_text ); ?>
612
+ <div class="cnb_advanced_view">
613
+ <p class="description" id="cnb-button-save-inactive-message"><span class="dashicons dashicons-warning"></span> Your button is <code>Inactive</code>, so it will not be visible until set the Button status to <code><strong>Active</strong></code></p>
614
+ <p class="description" id="cnb-button-save-mobile-only-message"><span class="dashicons dashicons-info"></span> Your button is <code>Mobile only</code>, so it will not be visible on desktop. Change this on the <a onclick="cnb_switch_to_tab('visibility')">Visibility</a> tab.</p>
615
+ </div>
616
  </form>
617
  <?php
618
  }
src/admin/deactivation/Activation.php CHANGED
@@ -29,12 +29,14 @@ class Activation {
29
  *
30
  * @return void
31
  */
32
- public static function onActivation() {
33
  $activation = new Activation();
34
 
35
  $activation->init_activation();
36
  $activation->capture_activation_time();
37
- $activation->ensure_redirect();
 
 
38
  }
39
 
40
  /**
29
  *
30
  * @return void
31
  */
32
+ public static function onActivation($set_redirect = true) {
33
  $activation = new Activation();
34
 
35
  $activation->init_activation();
36
  $activation->capture_activation_time();
37
+ if ($set_redirect) {
38
+ $activation->ensure_redirect();
39
+ }
40
  }
41
 
42
  /**
src/admin/domain/partials/CnbDomainViewUpgradeOverview.php CHANGED
@@ -7,10 +7,15 @@ defined( 'ABSPATH' ) || die( '-1' );
7
 
8
  use cnb\admin\api\CnbAppRemotePayment;
9
  use cnb\admin\models\CnbPlan;
10
- use cnb\admin\profile\CnbProfileEdit;
11
 
12
  class CnbDomainViewUpgradeOverview {
13
 
 
 
 
 
 
14
  private function getActiveCurrency( $user ) {
15
  $active_currency = null;
16
  if ( $user && ! is_wp_error( $user ) && isset( $user->stripeDetails ) && ! empty( $user->stripeDetails->currency ) ) {
@@ -20,16 +25,6 @@ class CnbDomainViewUpgradeOverview {
20
  return $active_currency;
21
  }
22
 
23
- private function render_hidden_profile() {
24
- add_thickbox();
25
- echo '<div id="cnb_admin_page_domain_upgrade_profile" style="display: none;"><div>';
26
- $view = new CnbProfileEdit();
27
- $user = $view->render_form( true );
28
- echo '</div></div>';
29
-
30
- return $user;
31
- }
32
-
33
  /**
34
  * Render upgrade form
35
  *
@@ -49,35 +44,14 @@ class CnbDomainViewUpgradeOverview {
49
  $this->renderBenefits();
50
  }
51
 
52
- private function renderJsForUpgradeForm( $user ) {
53
  $active_currency = $this->getActiveCurrency( $user );
54
- $profile_set = false;
55
- if ( $user && ! is_wp_error( $user ) && isset( $user->address ) && ! empty( $user->address->country ) ) {
56
- $profile_set = true;
57
- }
58
- echo '<script>';
59
- if ( ! $profile_set ) {
60
- // Unless a profile hasn't been set yet, in which case, ensure we ask customers for that first
61
- echo "
62
- jQuery(() => {
63
- jQuery('.button-upgrade').hide();
64
- })";
65
- } else {
66
- // Hide the "Next" buttons, we already have a profile
67
- echo "
68
- jQuery(() => {
69
- jQuery('.open-profile-details-modal').hide();
70
- })";
71
- }
72
-
73
  if ( $active_currency ) {
74
  // We already know the currency, so a "select currency" tab menu makes no sense
75
- echo "
76
- jQuery(() => {
77
- jQuery('.nav-tab-wrapper').hide();
78
- })";
79
  }
80
- echo '</script>';
81
  }
82
 
83
  private function renderStripeJs() {
@@ -94,7 +68,7 @@ class CnbDomainViewUpgradeOverview {
94
  return;
95
  }
96
 
97
- showMessage("error", e);
98
  }
99
  });
100
  </script>';
@@ -106,11 +80,11 @@ class CnbDomainViewUpgradeOverview {
106
  * @return void
107
  */
108
  public function renderUpgradeForm( $domain ) {
109
- $user = $this->render_hidden_profile();
110
  $this->renderStripeJs();
111
- $this->renderJsForUpgradeForm( $user );
112
  $plans = CnbAppRemotePayment::cnb_remote_get_plans();
113
- $active_currency = $this->getActiveCurrency( $user );
114
  $domain_controller = new CnbDomainController();
115
  ?>
116
  <form id="wp_domain_upgrade" method="post">
@@ -158,11 +132,6 @@ class CnbDomainViewUpgradeOverview {
158
  <div class="billingprice">
159
  Billed annually
160
  </div>
161
- <?php $this->get_profile_edit_modal_link(
162
- 'button button-primary',
163
- 'Upgrade',
164
- 'Enter or verify your information',
165
- 'powered-by-eur-yearly' ); ?>
166
  <a class="button button-primary button-upgrade powered-by-eur-yearly" href="#"
167
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
168
  </div>
@@ -185,11 +154,6 @@ class CnbDomainViewUpgradeOverview {
185
  <div class="billingprice">
186
  Billed monthly
187
  </div>
188
- <?php $this->get_profile_edit_modal_link(
189
- 'button button-secondary',
190
- 'Upgrade',
191
- 'Enter or verify your information',
192
- 'powered-by-eur-monthly' ); ?>
193
  <a class="button button-secondary button-upgrade powered-by-eur-monthly" href="#"
194
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
195
  </div>
@@ -219,11 +183,6 @@ class CnbDomainViewUpgradeOverview {
219
  <div class="billingprice">
220
  Billed annually
221
  </div>
222
- <?php $this->get_profile_edit_modal_link(
223
- 'button button-primary',
224
- 'Upgrade',
225
- 'Enter or verify your information',
226
- 'powered-by-usd-yearly' ); ?>
227
  <a class="button button-primary button-upgrade powered-by-usd-yearly" href="#"
228
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
229
  </div>
@@ -245,11 +204,6 @@ class CnbDomainViewUpgradeOverview {
245
  <div class="billingprice">
246
  Billed monthly
247
  </div>
248
- <?php $this->get_profile_edit_modal_link(
249
- 'button button-secondary',
250
- 'Upgrade',
251
- 'Enter or verify your information',
252
- 'powered-by-usd-monthly' ); ?>
253
  <a class="button button-secondary button-upgrade powered-by-usd-monthly" href="#"
254
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
255
  </div>
@@ -313,40 +267,4 @@ class CnbDomainViewUpgradeOverview {
313
  return null;
314
  }
315
 
316
- /**
317
- * Echo the link required for the profile modal
318
- *
319
- * @param $additional_classes
320
- * @param $link_text
321
- * @param $modal_header
322
- * @param $data_title
323
- *
324
- * @return void
325
- */
326
- private function get_profile_edit_modal_link(
327
- $additional_classes = null,
328
- $link_text = 'Enter or verify your information',
329
- $modal_header = null,
330
- $data_title = ''
331
- ) {
332
- if ( ! $modal_header ) {
333
- $modal_header = $link_text;
334
- }
335
- $url = admin_url( 'admin.php' );
336
- $full_url = add_query_arg(
337
- array(
338
- 'TB_inline' => 'true',
339
- 'inlineId' => 'cnb_admin_page_domain_upgrade_profile',
340
- 'height' => '725'
341
- ),
342
- $url );
343
- printf(
344
- '<a href="%1$s" title="%2$s" class="thickbox open-profile-details-modal %4$s" onclick="cnb_btn=\'%5$s\'">%3$s</a>',
345
- esc_url( $full_url ),
346
- esc_html( $modal_header ),
347
- esc_html( $link_text ),
348
- esc_attr( $additional_classes ),
349
- esc_attr( $data_title )
350
- );
351
- }
352
  }
7
 
8
  use cnb\admin\api\CnbAppRemotePayment;
9
  use cnb\admin\models\CnbPlan;
10
+ use cnb\admin\models\CnbUser;
11
 
12
  class CnbDomainViewUpgradeOverview {
13
 
14
+ /**
15
+ * @param $user CnbUser
16
+ *
17
+ * @return string|null
18
+ */
19
  private function getActiveCurrency( $user ) {
20
  $active_currency = null;
21
  if ( $user && ! is_wp_error( $user ) && isset( $user->stripeDetails ) && ! empty( $user->stripeDetails->currency ) ) {
25
  return $active_currency;
26
  }
27
 
 
 
 
 
 
 
 
 
 
 
28
  /**
29
  * Render upgrade form
30
  *
44
  $this->renderBenefits();
45
  }
46
 
47
+ private function renderJsToHideCurrency( $user ) {
48
  $active_currency = $this->getActiveCurrency( $user );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  if ( $active_currency ) {
50
  // We already know the currency, so a "select currency" tab menu makes no sense
51
+ echo '<script>';
52
+ echo "jQuery(() => { jQuery('.nav-tab-wrapper').hide(); })";
53
+ echo '</script>';
 
54
  }
 
55
  }
56
 
57
  private function renderStripeJs() {
68
  return;
69
  }
70
 
71
+ cnb_stripe_show_message("error", e);
72
  }
73
  });
74
  </script>';
80
  * @return void
81
  */
82
  public function renderUpgradeForm( $domain ) {
83
+ global $cnb_user;
84
  $this->renderStripeJs();
85
+ $this->renderJsToHideCurrency( $cnb_user );
86
  $plans = CnbAppRemotePayment::cnb_remote_get_plans();
87
+ $active_currency = $this->getActiveCurrency( $cnb_user );
88
  $domain_controller = new CnbDomainController();
89
  ?>
90
  <form id="wp_domain_upgrade" method="post">
132
  <div class="billingprice">
133
  Billed annually
134
  </div>
 
 
 
 
 
135
  <a class="button button-primary button-upgrade powered-by-eur-yearly" href="#"
136
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
137
  </div>
154
  <div class="billingprice">
155
  Billed monthly
156
  </div>
 
 
 
 
 
157
  <a class="button button-secondary button-upgrade powered-by-eur-monthly" href="#"
158
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
159
  </div>
183
  <div class="billingprice">
184
  Billed annually
185
  </div>
 
 
 
 
 
186
  <a class="button button-primary button-upgrade powered-by-usd-yearly" href="#"
187
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
188
  </div>
204
  <div class="billingprice">
205
  Billed monthly
206
  </div>
 
 
 
 
 
207
  <a class="button button-secondary button-upgrade powered-by-usd-monthly" href="#"
208
  onclick="cnb_get_checkout('<?php echo esc_js( $plan->id ) ?>')">Upgrade</a>
209
  </div>
267
  return null;
268
  }
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
src/admin/settings/CnbSettingsController.php CHANGED
@@ -8,6 +8,7 @@ defined( 'ABSPATH' ) || die( '-1' );
8
  use cnb\admin\api\CnbAdminCloud;
9
  use cnb\admin\api\CnbAppRemote;
10
  use cnb\admin\api\CnbMigration;
 
11
  use cnb\admin\domain\CnbDomainController;
12
  use cnb\admin\models\CnbActivation;
13
  use cnb\notices\CnbAdminNotices;
@@ -252,9 +253,11 @@ class CnbSettingsController {
252
  * @return WP_Error
253
  */
254
  private function disallow_active_without_phone_number( $input ) {
 
255
  $number = trim( $input['number'] );
256
  $cloud_enabled = array_key_exists( 'cloud_enabled', $input ) ? $input['cloud_enabled'] : 0;
257
- if ( $input['active'] == 1 && $cloud_enabled == 0 && empty( $number ) ) {
 
258
  return new WP_Error( 'CNB_PHONE_NUMBER_MISSING', 'Please enter a phone number before enabling your button.' );
259
  }
260
 
@@ -383,4 +386,94 @@ class CnbSettingsController {
383
 
384
  return $api_key_obj->key;
385
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  }
8
  use cnb\admin\api\CnbAdminCloud;
9
  use cnb\admin\api\CnbAppRemote;
10
  use cnb\admin\api\CnbMigration;
11
+ use cnb\admin\deactivation\Activation;
12
  use cnb\admin\domain\CnbDomainController;
13
  use cnb\admin\models\CnbActivation;
14
  use cnb\notices\CnbAdminNotices;
253
  * @return WP_Error
254
  */
255
  private function disallow_active_without_phone_number( $input ) {
256
+ $active = trim( $input['active'] );
257
  $number = trim( $input['number'] );
258
  $cloud_enabled = array_key_exists( 'cloud_enabled', $input ) ? $input['cloud_enabled'] : 0;
259
+
260
+ if ( $active == 1 && $cloud_enabled == 0 && empty( $number ) ) {
261
  return new WP_Error( 'CNB_PHONE_NUMBER_MISSING', 'Please enter a phone number before enabling your button.' );
262
  }
263
 
386
 
387
  return $api_key_obj->key;
388
  }
389
+
390
+ /**
391
+ * is called via admin_post
392
+ *
393
+ * @return void
394
+ */
395
+ public function delete_all_settings() {
396
+ $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
397
+ $success = 0;
398
+ if ( $nonce && wp_verify_nonce( $nonce, 'cnb_delete_all_settings' ) ) {
399
+
400
+ // Delete known options
401
+ $option_names = array( 'cnb', 'cnb_cloud_migration_done' );
402
+
403
+ foreach ( $option_names as $option_name ) {
404
+ // Delete the standard options
405
+ delete_option( $option_name );
406
+
407
+ // Delete site options in Multisite
408
+ delete_site_option( $option_name );
409
+ }
410
+ $this->set_default_settings();
411
+
412
+ // Delete notice dismissals
413
+ $options_slug = 'call-now-button';
414
+
415
+ global $wpdb;
416
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery
417
+ $wpdb->query(
418
+ $wpdb->prepare(
419
+ "DELETE FROM $wpdb->options
420
+ WHERE option_name
421
+ LIKE %s",
422
+ $options_slug . '_dismissed_%' )
423
+ );
424
+ $success = 1;
425
+ }
426
+ // Always redirect back, even when not succesful
427
+ $this->redirect_to_delete_all_settings($success);
428
+ }
429
+
430
+ /**
431
+ * is called via admin_post
432
+ *
433
+ * @return void
434
+ */
435
+ public function set_default_settings() {
436
+ $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
437
+ $success = 0;
438
+ if ( $nonce && wp_verify_nonce( $nonce, 'cnb_set_default_settings' ) ) {
439
+ Activation::onActivation( false );
440
+ $success = 2;
441
+ }
442
+ // Always redirect back, even when not succesful
443
+ $this->redirect_to_delete_all_settings($success);
444
+ }
445
+
446
+ /**
447
+ * is called via admin_post
448
+ *
449
+ * @return void
450
+ */
451
+ public function override_changelog_version() {
452
+ $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
453
+ $success = 0;
454
+ if ( $nonce && wp_verify_nonce( $nonce, 'cnb_set_default_settings' ) ) {
455
+ $changelog_version = filter_input( INPUT_POST, 'changelog_version', FILTER_SANITIZE_STRING );
456
+ $options = ['changelog_version' => $changelog_version];
457
+ update_option('cnb', $options);
458
+ $success = 3;
459
+ }
460
+ // Always redirect back, even when not succesful
461
+ $this->redirect_to_delete_all_settings($success);
462
+ }
463
+
464
+ private function redirect_to_delete_all_settings($success = 0) {
465
+ $url = admin_url( 'admin.php' );
466
+ $redirect_link =
467
+ add_query_arg(
468
+ array(
469
+ 'page' => CNB_SLUG . '-settings',
470
+ 'action' => 'delete_all_settings',
471
+ 'success' => $success,
472
+ ),
473
+ $url );
474
+ $redirect_url = esc_url_raw( $redirect_link );
475
+ do_action( 'cnb_finish' );
476
+ wp_safe_redirect( $redirect_url );
477
+
478
+ }
479
  }
src/admin/settings/CnbSettingsRouter.php CHANGED
@@ -3,6 +3,8 @@
3
  namespace cnb\admin\settings;
4
 
5
  // don't load directly
 
 
6
  defined( 'ABSPATH' ) || die( '-1' );
7
 
8
  class CnbSettingsRouter {
@@ -25,9 +27,20 @@ class CnbSettingsRouter {
25
 
26
  return;
27
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- $view = new CnbSettingsViewEdit();
30
- $view->render();
31
  do_action( 'cnb_finish' );
32
  }
33
  }
3
  namespace cnb\admin\settings;
4
 
5
  // don't load directly
6
+ use cnb\utils\CnbUtils;
7
+
8
  defined( 'ABSPATH' ) || die( '-1' );
9
 
10
  class CnbSettingsRouter {
27
 
28
  return;
29
  }
30
+ $action = ( new CnbUtils() )->get_query_val( 'action', null );
31
+ switch ( $action ) {
32
+ case 'delete_all_settings':
33
+ if (getenv('WORDPRESS_CALL_NOW_BUTTON_TESTS') == 1) {
34
+ $view = new Settings_Reset_view();
35
+ $view->render();
36
+ }
37
+ break;
38
+ default:
39
+ $view = new CnbSettingsViewEdit();
40
+ $view->render();
41
+ break;
42
+ }
43
 
 
 
44
  do_action( 'cnb_finish' );
45
  }
46
  }
src/admin/settings/class-settings-reset-view.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace cnb\admin\settings;
4
+
5
+ // don't load directly
6
+ defined( 'ABSPATH' ) || die( '-1' );
7
+
8
+ use cnb\notices\CnbAdminNotices;
9
+
10
+ class Settings_Reset_view {
11
+ private function render_success() {
12
+ $success = filter_input( INPUT_GET, 'success', FILTER_SANITIZE_STRING );
13
+ $noticeHandler = CnbAdminNotices::get_instance();
14
+ if ($success === '1') {
15
+ $noticeHandler->renderSuccess('<p>Settings deleted.</p>');
16
+ }
17
+ if ($success === '2') {
18
+ $noticeHandler->renderSuccess('<p>Settings set to their defaults.</p>');
19
+ }
20
+ }
21
+ function render() {
22
+ $options = get_option('cnb');
23
+ $this->render_success();
24
+ ?>
25
+ <h1>Reset options</h1>
26
+ <form action="<?php echo esc_attr(admin_url('admin-post.php')); ?>" method="post">
27
+ <?php wp_nonce_field('cnb_delete_all_settings') ?>
28
+ <input type="hidden" name="action" value="cnb_delete_all_settings">
29
+ <?php submit_button('Reset', 'primary', 'submit', true, ['data-cy-reset' => true]) ?>
30
+ </form>
31
+
32
+ <h1>Set default options</h1>
33
+ <form action="<?php echo esc_attr(admin_url('admin-post.php')); ?>" method="post">
34
+ <?php wp_nonce_field('cnb_set_default_settings') ?>
35
+ <input type="hidden" name="action" value="cnb_set_default_settings">
36
+ <?php submit_button('Reset', 'primary', 'submit', true, ['data-cy-set-default-values' => true]) ?>
37
+ </form>
38
+
39
+ <h1>Set changelog version</h1>
40
+ <form action="<?php echo esc_attr(admin_url('admin-post.php')); ?>" method="post">
41
+ <?php wp_nonce_field('cnb_set_default_settings') ?>
42
+ <input type="hidden" name="action" value="cnb_set_changelog_version">
43
+ <label>New version:
44
+ <input type="text" data-cy-changelog-version="1" name="changelog_version" value="<?php echo esc_attr($options['changelog_version']) ?>">
45
+ </label>
46
+ <?php submit_button('Reset', 'primary', 'submit', true, ['data-cy-set-changelog-version' => true]) ?>
47
+ </form>
48
+
49
+ <?php
50
+ }
51
+ }
src/autoload.php CHANGED
@@ -23,11 +23,11 @@ spl_autoload_register(
23
  'cnb\\admin\\api\\cnbmigration' => '/admin/api/CnbMigration.php',
24
  'cnb\\admin\\api\\remotetrace' => '/admin/api/RemoteTrace.php',
25
  'cnb\\admin\\api\\remotetracer' => '/admin/api/RemoteTracer.php',
26
- 'cnb\\admin\\apikey\\cnb_apikey_list_table' => '/admin/apikey/Cnb_Apikey_List_Table.php',
27
- 'cnb\\admin\\apikey\\cnbapikey' => '/admin/apikey/CnbApiKey.php',
28
- 'cnb\\admin\\apikey\\cnbapikeycontroller' => '/admin/apikey/CnbApiKeyController.php',
29
- 'cnb\\admin\\apikey\\cnbapikeyrouter' => '/admin/apikey/CnbApiKeyRouter.php',
30
- 'cnb\\admin\\apikey\\cnbapikeyview' => '/admin/apikey/CnbApiKeyView.php',
31
  'cnb\\admin\\button\\cnb_button_list_table' => '/admin/button/Cnb_Button_List_Table.php',
32
  'cnb\\admin\\button\\cnbbutton' => '/admin/button/CnbButton.php',
33
  'cnb\\admin\\button\\cnbbuttoncontroller' => '/admin/button/CnbButtonController.php',
@@ -78,6 +78,7 @@ spl_autoload_register(
78
  'cnb\\admin\\settings\\cnbsettingscontroller' => '/admin/settings/CnbSettingsController.php',
79
  'cnb\\admin\\settings\\cnbsettingsrouter' => '/admin/settings/CnbSettingsRouter.php',
80
  'cnb\\admin\\settings\\cnbsettingsviewedit' => '/admin/settings/CnbSettingsViewEdit.php',
 
81
  'cnb\\admin\\settings\\stripebillingportal' => '/admin/settings/StripeBillingPortal.php',
82
  'cnb\\cache\\cachehandler' => '/utils/class-cachehandler.php',
83
  'cnb\\callnowbutton' => '/CallNowButton.php',
@@ -98,9 +99,7 @@ spl_autoload_register(
98
  'cnb\\renderer\\rendererfactory' => '/renderers/class-rendererfactory.php',
99
  'cnb\\utils\\cnb_sentry' => '/utils/class-cnb-sentry.php',
100
  'cnb\\utils\\cnbadminfunctions' => '/utils/CnbAdminFunctions.php',
101
- 'cnb\\utils\\cnbutils' => '/utils/CnbUtils.php',
102
- 'wp_cli' => '/cli/mocks/WP_CLI.class.php',
103
- 'wp_cli_command' => '/cli/mocks/WP_CLI.class.php'
104
  );
105
  }
106
  $cn = strtolower($class);
23
  'cnb\\admin\\api\\cnbmigration' => '/admin/api/CnbMigration.php',
24
  'cnb\\admin\\api\\remotetrace' => '/admin/api/RemoteTrace.php',
25
  'cnb\\admin\\api\\remotetracer' => '/admin/api/RemoteTracer.php',
26
+ 'cnb\\admin\\apikey\\cnb_apikey_list_table' => '/admin/api-key/Cnb_Apikey_List_Table.php',
27
+ 'cnb\\admin\\apikey\\cnbapikey' => '/admin/api-key/CnbApiKey.php',
28
+ 'cnb\\admin\\apikey\\cnbapikeycontroller' => '/admin/api-key/CnbApiKeyController.php',
29
+ 'cnb\\admin\\apikey\\cnbapikeyrouter' => '/admin/api-key/CnbApiKeyRouter.php',
30
+ 'cnb\\admin\\apikey\\cnbapikeyview' => '/admin/api-key/CnbApiKeyView.php',
31
  'cnb\\admin\\button\\cnb_button_list_table' => '/admin/button/Cnb_Button_List_Table.php',
32
  'cnb\\admin\\button\\cnbbutton' => '/admin/button/CnbButton.php',
33
  'cnb\\admin\\button\\cnbbuttoncontroller' => '/admin/button/CnbButtonController.php',
78
  'cnb\\admin\\settings\\cnbsettingscontroller' => '/admin/settings/CnbSettingsController.php',
79
  'cnb\\admin\\settings\\cnbsettingsrouter' => '/admin/settings/CnbSettingsRouter.php',
80
  'cnb\\admin\\settings\\cnbsettingsviewedit' => '/admin/settings/CnbSettingsViewEdit.php',
81
+ 'cnb\\admin\\settings\\settings_reset_view' => '/admin/settings/class-settings-reset-view.php',
82
  'cnb\\admin\\settings\\stripebillingportal' => '/admin/settings/StripeBillingPortal.php',
83
  'cnb\\cache\\cachehandler' => '/utils/class-cachehandler.php',
84
  'cnb\\callnowbutton' => '/CallNowButton.php',
99
  'cnb\\renderer\\rendererfactory' => '/renderers/class-rendererfactory.php',
100
  'cnb\\utils\\cnb_sentry' => '/utils/class-cnb-sentry.php',
101
  'cnb\\utils\\cnbadminfunctions' => '/utils/CnbAdminFunctions.php',
102
+ 'cnb\\utils\\cnbutils' => '/utils/CnbUtils.php'
 
 
103
  );
104
  }
105
  $cn = strtolower($class);
src/utils/CnbAdminFunctions.php CHANGED
@@ -65,6 +65,9 @@ class CnbAdminFunctions {
65
  'FACEBOOK' => 'Facebook Messenger',
66
  'SIGNAL' => 'Signal',
67
  'TELEGRAM' => 'Telegram',
 
 
 
68
  );
69
  }
70
 
65
  'FACEBOOK' => 'Facebook Messenger',
66
  'SIGNAL' => 'Signal',
67
  'TELEGRAM' => 'Telegram',
68
+ // 'IFRAME' => 'Iframe',
69
+ // 'TALLY' => 'Tally (integration)',
70
+ // 'INTERCOM' => 'Intercom (integration)'
71
  );
72
  }
73
 
src/utils/CnbUtils.php CHANGED
@@ -100,6 +100,12 @@ class CnbUtils {
100
  return 'signal';
101
  case 'TELEGRAM':
102
  return 'telegram';
 
 
 
 
 
 
103
  case 'PHONE':
104
  default:
105
  return 'call';
100
  return 'signal';
101
  case 'TELEGRAM':
102
  return 'telegram';
103
+ case 'IFRAME':
104
+ return 'link4';
105
+ case 'TALLY':
106
+ return 'support';
107
+ case 'INTERCOM':
108
+ return 'call3';
109
  case 'PHONE':
110
  default:
111
  return 'call';
src/vendor/composer/installed.json CHANGED
@@ -1264,17 +1264,17 @@
1264
  },
1265
  {
1266
  "name": "symfony/options-resolver",
1267
- "version": "v5.4.3",
1268
- "version_normalized": "5.4.3.0",
1269
  "source": {
1270
  "type": "git",
1271
  "url": "https://github.com/symfony/options-resolver.git",
1272
- "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8"
1273
  },
1274
  "dist": {
1275
  "type": "zip",
1276
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8",
1277
- "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8",
1278
  "shasum": ""
1279
  },
1280
  "require": {
@@ -1283,7 +1283,7 @@
1283
  "symfony/polyfill-php73": "~1.0",
1284
  "symfony/polyfill-php80": "^1.16"
1285
  },
1286
- "time": "2022-01-02T09:53:40+00:00",
1287
  "type": "library",
1288
  "installation-source": "dist",
1289
  "autoload": {
@@ -1316,7 +1316,7 @@
1316
  "options"
1317
  ],
1318
  "support": {
1319
- "source": "https://github.com/symfony/options-resolver/tree/v5.4.3"
1320
  },
1321
  "funding": [
1322
  {
1264
  },
1265
  {
1266
  "name": "symfony/options-resolver",
1267
+ "version": "v5.4.11",
1268
+ "version_normalized": "5.4.11.0",
1269
  "source": {
1270
  "type": "git",
1271
  "url": "https://github.com/symfony/options-resolver.git",
1272
+ "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690"
1273
  },
1274
  "dist": {
1275
  "type": "zip",
1276
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/54f14e36aa73cb8f7261d7686691fd4d75ea2690",
1277
+ "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690",
1278
  "shasum": ""
1279
  },
1280
  "require": {
1283
  "symfony/polyfill-php73": "~1.0",
1284
  "symfony/polyfill-php80": "^1.16"
1285
  },
1286
+ "time": "2022-07-20T13:00:38+00:00",
1287
  "type": "library",
1288
  "installation-source": "dist",
1289
  "autoload": {
1316
  "options"
1317
  ],
1318
  "support": {
1319
+ "source": "https://github.com/symfony/options-resolver/tree/v5.4.11"
1320
  },
1321
  "funding": [
1322
  {
src/vendor/composer/installed.php CHANGED
@@ -3,7 +3,7 @@
3
  'name' => '__root__',
4
  'pretty_version' => 'dev-master',
5
  'version' => 'dev-master',
6
- 'reference' => 'd2c6b667fba2a45bba8a3ce6ced006dfa882dfbd',
7
  'type' => 'library',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
@@ -13,7 +13,7 @@
13
  '__root__' => array(
14
  'pretty_version' => 'dev-master',
15
  'version' => 'dev-master',
16
- 'reference' => 'd2c6b667fba2a45bba8a3ce6ced006dfa882dfbd',
17
  'type' => 'library',
18
  'install_path' => __DIR__ . '/../../',
19
  'aliases' => array(),
@@ -218,9 +218,9 @@
218
  'dev_requirement' => false,
219
  ),
220
  'symfony/options-resolver' => array(
221
- 'pretty_version' => 'v5.4.3',
222
- 'version' => '5.4.3.0',
223
- 'reference' => 'cc1147cb11af1b43f503ac18f31aa3bec213aba8',
224
  'type' => 'library',
225
  'install_path' => __DIR__ . '/../symfony/options-resolver',
226
  'aliases' => array(),
3
  'name' => '__root__',
4
  'pretty_version' => 'dev-master',
5
  'version' => 'dev-master',
6
+ 'reference' => 'd96515b240c9b787a8c2da93a282aae583d6af7d',
7
  'type' => 'library',
8
  'install_path' => __DIR__ . '/../../',
9
  'aliases' => array(),
13
  '__root__' => array(
14
  'pretty_version' => 'dev-master',
15
  'version' => 'dev-master',
16
+ 'reference' => 'd96515b240c9b787a8c2da93a282aae583d6af7d',
17
  'type' => 'library',
18
  'install_path' => __DIR__ . '/../../',
19
  'aliases' => array(),
218
  'dev_requirement' => false,
219
  ),
220
  'symfony/options-resolver' => array(
221
+ 'pretty_version' => 'v5.4.11',
222
+ 'version' => '5.4.11.0',
223
+ 'reference' => '54f14e36aa73cb8f7261d7686691fd4d75ea2690',
224
  'type' => 'library',
225
  'install_path' => __DIR__ . '/../symfony/options-resolver',
226
  'aliases' => array(),
src/vendor/symfony/options-resolver/OptionsResolver.php CHANGED
@@ -437,7 +437,7 @@ class OptionsResolver implements Options
437
  *
438
  * @return $this
439
  */
440
- public function setDeprecated(string $option/*, string $package, string $version, $message = 'The option "%name%" is deprecated.' */): self
441
  {
442
  if ($this->locked) {
443
  throw new AccessException('Options cannot be deprecated from a lazy option or normalizer.');
437
  *
438
  * @return $this
439
  */
440
+ public function setDeprecated(string $option/* , string $package, string $version, $message = 'The option "%name%" is deprecated.' */): self
441
  {
442
  if ($this->locked) {
443
  throw new AccessException('Options cannot be deprecated from a lazy option or normalizer.');