PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / admin / assets / js / wpfnl-admin.js

wpfnl-admin.js in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.13.3, at admin/assets/js/wpfnl-admin.js

3,374 lines 125.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ;(function ($) {
2 'use strict'
3
4 var product_option = window.WPFunnelVars.products
5 var selectedIds = []
6 /**
7 * All of the code for your admin-facing JavaScript source
8 * should reside in this file.
9 *
10 * Note: It has been assumed you will write jQuery code here, so the
11 * $ function reference has been prepared for usage within the scope
12 * of this function.
13 *
14 * This enables you to define handlers, for when the DOM is ready:
15 *
16 * $(function() {
17 *
18 * });
19 *
20 * When the window is loaded:
21 *
22 * $( window ).load(function() {
23 *
24 * });
25 *
26 * ...and/or other possibilities.
27 *
28 * Ideally, it is not considered best practise to attach more than a
29 * single DOM-ready or window-load handler for a particular page.
30 * Although scripts in the WordPress core, Plugins and Themes may be
31 * practising this, we should strive to set a better example in our own work.
32 */
33
34 jQuery(document).ready(function ($) {
35
36 // ---delete import funnel notice permanently ------
37 $(document).on("click", ".wpfnl-import-notice .notice-dismiss", function(event) {
38 event.preventDefault();
39 var nonce = $('#wpfnl-import-nonce').val();
40
41 // Use standard WP ajaxurl if available or WPFunnelVars
42 var reqUrl = (typeof ajaxurl !== 'undefined') ? ajaxurl : (window.WPFunnelVars && window.WPFunnelVars.ajaxurl ? window.WPFunnelVars.ajaxurl : '');
43 if (reqUrl) {
44 $.ajax({
45 url: reqUrl,
46 type: 'POST',
47 data: {
48 action: 'wpfnl_hide_import_funnel_notice',
49 security: nonce
50 }
51 });
52 }
53 });
54
55 //date format
56 function PresentDateForm(date) {
57 var date = new Date(date),
58 day = date.getDate(),
59 month = date.getMonth() + 1, //Months are zero based
60 year = date.getFullYear(),
61 date = new Date(year + '-' + month + '-' + day).toDateString()
62 return date
63 }
64
65 function CompareDateForm(date) {
66 var date = new Date(date),
67 day = date.getDate(),
68 month = date.getMonth() + 1, //Months are zero based
69 year = date.getFullYear() - 1,
70 date = new Date(year + '-' + month + '-' + day).toDateString()
71 return date
72 }
73
74 // -------analytics line chart filter-------
75 function wpfnlDatePicker() {
76 $('.wpfunnel-datepicker').datepicker({
77 maxDate: 0,
78 changeMonth: true,
79 changeYear: true,
80 showOtherMonths: true,
81 selectOtherMonths: true,
82 beforeShowDay: function (date) {
83 let date1 = $.datepicker.parseDate(
84 $.datepicker._defaults.dateFormat,
85 $('#date_from_value').val(),
86 )
87 let date2 = $.datepicker.parseDate(
88 $.datepicker._defaults.dateFormat,
89 $('#date_to_value').val(),
90 )
91
92 let isStartDate = date1 && date.getTime() === date1.getTime()
93 let isEndDate = date2 && date.getTime() === date2.getTime()
94
95 return [
96 true,
97 isStartDate || (date2 && date >= date1 && date <= date2) ? 'in-range' : '',
98 isStartDate ? 'Start' : isEndDate ? 'End' : '',
99 ]
100 },
101 onSelect: function (dateText, inst) {
102 let date1 = $.datepicker.parseDate(
103 $.datepicker._defaults.dateFormat,
104 $('#date_from_value').val(),
105 )
106 let date2 = $.datepicker.parseDate(
107 $.datepicker._defaults.dateFormat,
108 $('#date_to_value').val(),
109 )
110 let selectedDate = $.datepicker.parseDate(
111 $.datepicker._defaults.dateFormat,
112 dateText,
113 )
114 const months = [
115 'Jan',
116 'Feb',
117 'Mar',
118 'Apr',
119 'May',
120 'Jun',
121 'Jul',
122 'Aug',
123 'Sep',
124 'Oct',
125 'Nov',
126 'Dec',
127 ]
128 const formattedDate =
129 months[selectedDate.getMonth()] +
130 ' ' +
131 selectedDate.getDate() +
132 ', ' +
133 selectedDate.getFullYear()
134
135 if (!date1 || date2) {
136 $('#date-from').val(formattedDate)
137 $('#date_from_value').val(dateText)
138 $('li.select-from-date').text(dateText).css('color', '#2D3149')
139
140 $('#date-to').val('')
141 $('#date_to_value').val('')
142 $(this).datepicker()
143 $('.analytics-header .custom-date-range').show()
144 } else if (selectedDate < date1) {
145 $('#date-to').val($('#date-from').val())
146 $('#date_to_value').val($('#date_from_value').val())
147 $('#date-from').val(formattedDate)
148 $('#date_from_value').val(dateText)
149
150 $('li.select-to-date')
151 .text($('li.select-from-date').text())
152 .css('color', '#2D3149')
153 $('li.select-from-date').text(dateText).css('color', '#2D3149')
154
155 $(this).datepicker()
156 } else {
157 $('#date-to').val(formattedDate)
158 $('#date_to_value').val(dateText)
159 $('li.select-to-date').text(dateText).css('color', '#2D3149')
160 $(this).datepicker()
161 $('.analytics-header .custom-date-range').show()
162 }
163 },
164 })
165 }
166
167 $('.wpfnl_muliple_select').select2()
168 // edit field error handle
169 $('.wpfnl-section-type-error').hide()
170 $('.wpfnl-field-type-error').hide()
171 $('.wpfnl-name-type-error').hide()
172 $('.wpfnl-label-type-error').hide()
173
174 //--------show calendar when select as custom filter----------
175 $(document).on('change', '#analytics-filter', function () {
176 let selectedValue = $(this).find(':selected').val()
177
178 if ('custom' === selectedValue) {
179 var selectedDate = $('#date-from').val()
180 $('.wpfnl-analytics .overlay-click').show()
181 $('.analytics-header .custom-date-range').show()
182 $('.analytics-header .header-right').addClass('show-calendar')
183 } else {
184 $('.wpfnl-analytics .overlay-click').hide()
185
186 $('.analytics-header .header-right').removeClass('show-calendar')
187 $('.analytics-header .custom-date-range').hide()
188 }
189 })
190
191 //--------hide calendar when click on calender filter button----------
192 $(document).on('click', '.do-filter', function (e) {
193 $('.analytics-header .header-right').removeClass('show-calendar')
194 $('.wpfnl-analytics .overlay-click').hide()
195 })
196
197 //--------analytics calendar filter dropdown----------
198 $(document).on('click', '.filter-selectbox', function (e) {
199 e.stopPropagation()
200 $(this).parents('.header-right').toggleClass('show-calendar')
201 $('.wpfnl-analytics .overlay-click').show()
202 })
203 $(document).on('click', '.calendar-dorpdown', function (e) {
204 e.stopPropagation()
205 })
206 $(document).on('click', '.wpfnl-analytics .overlay-click', function () {
207 $(this).hide()
208 $('.analytics-header .header-right').removeClass('show-calendar')
209 })
210
211 //--------analytics filter header dropdown----------
212 $(document).on('click', '.funnel-steps > li', function (e) {
213 e.preventDefault()
214 e.stopPropagation()
215 $(this).addClass('active')
216 $(this).siblings('li').removeClass('active')
217 $(this).children('.wpfnl-dropdown').toggleClass('show-dropdown')
218 $(this).siblings('li').children('.wpfnl-dropdown').removeClass('show-dropdown')
219 })
220 $(document).on('click', 'body', function () {
221 $('.chart-header .funnel-steps .wpfnl-dropdown').removeClass('show-dropdown')
222 })
223
224 // -------show/hide step stats info-------
225 $(document).on('change', '#stats', function (e) {
226 if ($(this).is(':checked')) {
227 $('.node-wrapper .node-stats').show()
228 } else {
229 $('.node-wrapper .node-stats').hide()
230 }
231 })
232
233 var FunnelHandler = function () {
234 this.initStepSortable()
235 this.initProductSortable()
236 $(document.body).on('submit', '#wpfnl-change-funnel-name', this.changeFunnelName)
237
238 $('.wpfnl-duplicate-funnel').on('click', this.cloneFunnel)
239 $('.wpfnl-delete-funnel').on('click', this.deleteFunnel)
240 $('.wpfnl-permanent-delete-funnel').on('click', this.permanentDeleteFunnel)
241 $('.wpfnl-restore-funnel').on('click', this.restoreFunnel)
242 $('.wpfnl-update-funnel-status').on('click', this.UpdateFunnelStatus)
243 $('.wpfnl-export-funnel').on('click', this.ExportFunnel)
244 $('.wpfnl-export-all-funnels').on('click', this.ExportAllFunnel)
245 $('#wpfnl-import-funnels').on('submit', this.ImportFunnels)
246 $('#wpfnl-import-funnels').on('change', this.UploadFile)
247 $('.wpfnl-import-funnels').on('click', this.ShowImportFunnelModal)
248 $(
249 '.import-funnel-modal .close-modal, .import-funnel-modal .import-funnel-modal-inner',
250 ).on('click', this.CloseImportFunnelModal)
251 $('.import-funnel-modal .import-funnel-modal-wrapper').on(
252 'click',
253 this.PreventImportFunnelModal,
254 )
255
256 $(document.body).on('click', '.wpfnl-bulk-trash', this.bulkTrashFunnel)
257 $(document.body).on('click', '.wpfnl-bulk-delete', this.bulkDeleteFunnel)
258 $(document.body).on('click', '.wpfnl-bulk-restore', this.bulkRestoreFunnel)
259 $(document.body).on('click', '.wpfnl-bulk-export', this.bulkExportFunnel)
260 // Bound directly, NOT delegated through document.body: the modal wrapper has its
261 // own click handler calling stopPropagation() to keep backdrop clicks from closing
262 // the modal, so events from inside it never reach body.
263 $('.wpfnl-import-cancel').on('click', this.CancelImport)
264 $('.wpfnl-import-view-funnels').on('click', function (e) {
265 e.preventDefault()
266 window.location.reload()
267 })
268
269 // An import started in an earlier page view keeps running in the background, so
270 // pick it back up rather than leaving the user with no sign of it.
271 resumeImportIfRunning()
272 }
273
274 /**
275 * Select quantity
276 *
277 * @since 1.0.0
278 */
279 $('input[name=quantity]').change(function () {
280 var val = parseInt(this.value)
281 var product = $(this).attr('data-product')
282
283 for (var i in product_option) {
284 if (product_option[i].id == product) {
285 product_option[i].quantity = val
286 break //Stop this loop, we found it!
287 }
288 }
289 })
290
291 /**
292 * Subtext Setup
293 *
294 * @since 1.0.0
295 */
296 $('input[name=subtext]').change(function () {
297 var val = $(this).val()
298 var product = $(this).attr('data-product')
299
300 for (var i in product_option) {
301 if (product_option[i].id == product) {
302 product_option[i].subtext = val
303 break //Stop this loop, we found it!
304 }
305 }
306 })
307
308 /**
309 * Highlight Text Setup
310 *
311 * @since 1.0.0
312 */
313 $('input[name=text-highlight]').change(function () {
314 var val = $(this).val()
315 var product = $(this).attr('data-product')
316
317 for (var i in product_option) {
318 if (product_option[i].id == product) {
319 product_option[i].text_highlight = val
320 break //Stop this loop, we found it!
321 }
322 }
323 })
324
325 /**
326 * Enable Highlight setup
327 *
328 * @since 1.0.0
329 */
330 $('input[name=hide-img-mobile]').change(function () {
331 if (this.checked) {
332 var val = 'on'
333 } else {
334 var val = 'off'
335 }
336
337 var product = $(this).attr('data-product')
338
339 for (var i in product_option) {
340 if (product_option[i].id == product) {
341 product_option[i].enable_highlight = val
342 break //Stop this loop, we found it!
343 }
344 }
345 })
346
347 /**
348 * Sort step order
349 *
350 * @since 1.0.0
351 */
352 FunnelHandler.prototype.initStepSortable = function () {
353 $('#wpfnl-funnel-step-lists').sortable({
354 axis: 'y',
355 start: function (event, ui) {},
356 update: function (event, ui) {
357 var order = $('#wpfnl-funnel-step-lists').sortable('toArray')
358
359 var funnel_id = getUrlParameter('id')
360
361 var payload = {
362 funnel_id: funnel_id,
363 order: order,
364 }
365 wpAjaxHelperRequest('funnel-drag-order', payload)
366 .success(function (response) {})
367 .error(function (response) {
368 // console.log('error');
369 })
370 },
371 })
372 $('#wpfnl-funnel-step-lists').disableSelection()
373 }
374
375 /**
376 * Sort product accordion order
377 *
378 * @since 1.0.0
379 */
380 FunnelHandler.prototype.initProductSortable = function () {
381 $('.product-single-accordion__sortable-wrapper').sortable({
382 axis: 'y',
383 start: function (event, ui) {},
384 update: function (event, ui) {
385 var product_order = $('.product-single-accordion__sortable-wrapper').sortable(
386 'toArray',
387 )
388
389 product_option = []
390 var funnel_id = getUrlParameter('id')
391
392 for (var i in product_order) {
393 var dragger_id = product_order[i]
394 var prod_id = dragger_id.replace('product__single-accordion-', '')
395 var quantity = $('#product-quantity-' + prod_id).val()
396 product_option.push({
397 id: prod_id,
398 quantity: quantity,
399 })
400 }
401 },
402 })
403 $('.product-single-accordion__sortable-wrapper').disableSelection()
404 }
405
406 /**
407 *
408 * Ajax handler for duplicate
409 * funnel action
410 *
411 * @param event
412 * @since 1.0.0
413 */
414 FunnelHandler.prototype.cloneFunnel = function (event) {
415 event.preventDefault()
416
417 const $this = $(this)
418 const funnel_id = $this.attr('data-id')
419 const loader = $this.find('.wpfnl-loader')
420
421 $this.css('pointer-events', 'none')
422 loader.show()
423
424 wpAjaxHelperRequest('clone-funnel', { funnel_id })
425 .success(response => {
426 localStorage.setItem('wpfnl_show_toast', 'clone_success')
427 window.location.href = response.redirectUrl
428 })
429 .error(handleAjaxError('Clone failed'))
430 .always(() => loader.hide())
431 }
432
433 /**
434 * delete funnel and all the related
435 * data
436 *
437 * @param event
438 * @since 1.0.0
439 */
440
441 FunnelHandler.prototype.deleteFunnel = function (event) {
442 event.preventDefault()
443
444 const funnel_id = $(this).attr('data-id')
445 if (!confirm('Are you sure?')) return
446
447 wpAjaxHelperRequest('trash-funnel', { funnel_id })
448 .success(response => {
449 localStorage.setItem('wpfnl_show_toast', 'trash_success')
450 window.location.href = response.redirectUrl
451 })
452 .error(handleAjaxError('Trash failed'))
453 }
454
455 // Toast logic on page load
456 function showToast(type, message) {
457 const icons = {
458 success: '<svg width="26" height="26" fill="none" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path fill="#4BAE4F" fill-rule="evenodd" d="M13 0C5.83 0 0 5.83 0 13s5.83 13 13 13 13-5.83 13-13S20.17 0 13 0z" clip-rule="evenodd"/><path fill="#fff" fill-rule="evenodd" d="M19.287 8.618a.815.815 0 010 1.148l-7.617 7.617a.812.812 0 01-1.148 0l-3.808-3.809a.815.815 0 010-1.147.815.815 0 011.147 0l3.235 3.234 7.044-7.043a.806.806 0 011.147 0z" clip-rule="evenodd"/></svg>',
459 error: '<svg width="26" height="26" fill="none" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path fill="#EC5956" fill-rule="evenodd" d="M26 13c0 7.18-5.82 13-13 13S0 20.18 0 13 5.82 0 13 0s13 5.82 13 13zm-11.375 6.5a1.625 1.625 0 11-3.25 0 1.625 1.625 0 013.25 0zM13 4.875c-.898 0-1.625.728-1.625 1.625V13a1.625 1.625 0 103.25 0V6.5c0-.897-.727-1.625-1.625-1.625z" clip-rule="evenodd"/></svg>'
460 }
461
462 const toastClass = type === 'success'
463 ? 'quick-toastify-successful-notification'
464 : 'quick-toastify-warn-notification'
465
466 $('#wpfnl-toaster-wrapper')
467 .removeClass()
468 .addClass(toastClass)
469 .show()
470
471 $('#wpfnl-toaster-icon').html(icons[type])
472 $('#wpfnl-toaster-message').html(message)
473
474 setTimeout(() => {
475 $('#wpfnl-toaster-wrapper').removeClass(toastClass).hide()
476 }, 3000)
477 }
478 function handleAjaxError(message = 'Something went wrong') {
479 return function () {
480 console.error(message)
481 showToast('error', message)
482 }
483 }
484 function showToastFromStorage() {
485 const toastMap = {
486 trash_success: 'The funnel has been moved to Trash.',
487 clone_success: 'The funnel has been duplicated successfully.',
488 status_updated: 'Funnel status has been updated successfully.',
489 bulk_trash_success: 'The selected funnels have been moved to Trash.',
490 bulk_delete_success: 'The selected funnels have been deleted permanently.',
491 bulk_restore_success: 'The selected funnels have been restored successfully.',
492 import_success: 'The funnels have been imported successfully.',
493 }
494
495 const toastKey = localStorage.getItem('wpfnl_show_toast')
496 if (!toastKey || !toastMap[toastKey]) return
497
498 localStorage.removeItem('wpfnl_show_toast')
499 showToast('success', toastMap[toastKey])
500 }
501
502 $(showToastFromStorage)
503
504
505
506
507
508 /**
509 * delete funnel and all the related
510 * data
511 *
512 * @param event
513 * @since 1.0.0
514 */
515 FunnelHandler.prototype.permanentDeleteFunnel = function (event) {
516 event.preventDefault()
517 var funnel_id = $(this).attr('data-id')
518 var payload = {
519 funnel_id: funnel_id,
520 }
521 if (confirm('Are you sure?')) {
522 wpAjaxHelperRequest('delete-funnel', payload)
523 .success(function (response) {
524 window.location.href = response.redirectUrl
525 })
526 .error(function (response) {})
527 }
528 }
529
530 /**
531 * delete funnel and all the related
532 * data
533 *
534 * @param event
535 * @since 1.0.0
536 */
537 FunnelHandler.prototype.restoreFunnel = function (event) {
538 event.preventDefault()
539 var funnel_id = $(this).attr('data-id')
540 var payload = {
541 funnel_id: funnel_id,
542 }
543 if (confirm('Are you sure?')) {
544 wpAjaxHelperRequest('restore-funnel', payload)
545 .success(function (response) {
546 window.location.href = response.redirectUrl
547 })
548 .error(function (response) {})
549 }
550 }
551
552 /**
553 * bulk delete funnel and all the related
554 * data
555 *
556 * @param event
557 * @since 1.0.0
558 */
559 FunnelHandler.prototype.bulkDeleteFunnel = function (event) {
560 event.preventDefault()
561 let funnel_ids = selectedIds
562
563 let payload = {
564 ids: funnel_ids,
565 }
566
567 if (confirm('Are you sure?')) {
568 fetch(
569 `${window.template_library_object.rest_api_url}wpfunnels/v1/funnel-control/bulk-delete-funnel`,
570 {
571 method: 'POST',
572 headers: {
573 'Content-Type': 'application/json',
574 'X-WP-Nonce': wpApiSettings.nonce,
575 },
576 body: JSON.stringify(payload),
577 },
578 )
579 .then((response) => response.json())
580 .then((data) => {
581 if (data.success) {
582 localStorage.setItem('wpfnl_show_toast', 'bulk_delete_success'),
583 window.location.href = data.redirectUrl
584 }
585 })
586 .catch((error) => {
587 console.error('Error:', error)
588 })
589 }
590 selectedIds = []
591 }
592
593 /**
594 * bulk trash funnel and all the related
595 * data
596 *
597 * @param event
598 * @since 1.0.0
599 */
600 FunnelHandler.prototype.bulkTrashFunnel = function (event) {
601 event.preventDefault()
602 let funnel_ids = selectedIds
603
604 let payload = {
605 ids: funnel_ids,
606 }
607
608 if (confirm('Are you sure?')) {
609 fetch(
610 `${window.template_library_object.rest_api_url}wpfunnels/v1/funnel-control/bulk-trash-funnel`,
611 {
612 method: 'POST',
613 headers: {
614 'Content-Type': 'application/json',
615 'X-WP-Nonce': wpApiSettings.nonce,
616 },
617 body: JSON.stringify(payload),
618 },
619 )
620 .then((response) => response.json())
621 .then((data) => {
622 if (data.success) {
623 localStorage.setItem('wpfnl_show_toast', 'bulk_trash_success')
624 window.location.href = data.redirectUrl
625 }
626 })
627 .catch((error) => {
628 handleAjaxError('Trash failed')
629 })
630 }
631 selectedIds = []
632 }
633
634 /**
635 * bulk delete funnel and all the related
636 * data
637 *
638 * @param event
639 * @since 1.0.0
640 */
641 FunnelHandler.prototype.bulkRestoreFunnel = function (event) {
642 event.preventDefault()
643 let funnel_ids = selectedIds
644
645 let payload = {
646 ids: funnel_ids,
647 }
648
649 if (confirm('Are you sure?')) {
650 fetch(
651 `${window.template_library_object.rest_api_url}wpfunnels/v1/funnel-control/bulk-restore-funnel`,
652 {
653 method: 'POST',
654 headers: {
655 'Content-Type': 'application/json',
656 'X-WP-Nonce': wpApiSettings.nonce,
657 },
658 body: JSON.stringify(payload),
659 },
660 )
661 .then((response) => response.json())
662 .then((data) => {
663 if (data.success) {
664 localStorage.setItem('wpfnl_show_toast', 'bulk_restore_success')
665 window.location.href = data.redirectUrl
666 }
667 })
668 .catch((error) => {
669 console.error('Error:', error)
670 })
671 }
672 selectedIds = []
673 }
674
675 /**
676 * Update funnel status
677 * data
678 *
679 * @param event
680 * @since 1.0.0
681 */
682 FunnelHandler.prototype.UpdateFunnelStatus = function (event) {
683 event.preventDefault()
684
685 const funnel_id = $(this).attr('data-id')
686 const new_status = $(this).attr('data-status')
687 if (!confirm('Are you sure?')) return
688
689 wpAjaxHelperRequest('update-funnel-status', { funnel_id, status: new_status })
690 .success(response => {
691 localStorage.setItem('wpfnl_show_toast', 'status_updated')
692 window.location.href = response.redirect_url
693 })
694 .error(handleAjaxError('Status update failed'))
695 }
696
697 /**
698 *
699 * Ajax handler for export a single funnel
700 * funnel action
701 *
702 * @param event
703 * @since 2.6.3
704 */
705 FunnelHandler.prototype.ExportFunnel = function (event) {
706 event.preventDefault()
707
708 var funnel_id = $(this).attr('data-id'),
709 loader = $(this).find('.wpfnl-loader')
710 var payload = {
711 funnel_id: funnel_id,
712 }
713
714 $(this).css('pointer-events', 'none')
715 loader.show()
716
717 wpAjaxHelperRequest('wpfnl-export-funnel', payload)
718 .success(function (response) {
719 if (response.success) {
720 const jsonData = response.steps
721 const filename = response.title + '.json'
722 download(JSON.stringify(jsonData), filename, 'text/plain')
723 }
724 loader.hide()
725 })
726 .error(function (response) {
727 loader.hide()
728 })
729 }
730
731 /**
732 *
733 * Ajax handler for export a single funnel
734 * funnel action
735 *
736 * @param event
737 * @since 2.6.3
738 */
739 FunnelHandler.prototype.ExportAllFunnel = function (event) {
740 event.preventDefault()
741
742 var status = 'all',
743 loader = $(this).find('.wpfnl-loader')
744 var payload = {
745 status: status,
746 }
747
748 $(this).css('pointer-events', 'none')
749 loader.show()
750
751 wpAjaxHelperRequest('wpfnl-export-all-funnels', payload)
752 .success(function (response) {
753 if (response.success) {
754 const jsonData = response.data
755
756 var today = new Date()
757 var dd = String(today.getDate()).padStart(2, '0')
758 var mm = String(today.getMonth() + 1).padStart(2, '0') //January is 0!
759 var yyyy = today.getFullYear()
760 today = mm + '-' + dd + '-' + yyyy
761 const filename = 'wpfunnels-export-' + today + '-.json'
762
763 download(JSON.stringify(jsonData), filename, 'text/plain')
764 }
765 loader.hide()
766 })
767 .error(function (response) {
768 loader.hide()
769 })
770 }
771
772 /**
773 *
774 * Ajax handler for export bulk funnels
775 * funnel action
776 *
777 * @param event
778 * @since 2.7.19
779 */
780 FunnelHandler.prototype.bulkExportFunnel = function (event) {
781 event.preventDefault()
782
783 let funnel_ids = selectedIds
784
785 let status = 'all',
786 loader = $(this).find('.wpfnl-loader')
787 let payload = {
788 status: status,
789 ids: funnel_ids,
790 }
791
792 $(this).css('pointer-events', 'none')
793 loader.show()
794
795 fetch(
796 `${window.template_library_object.rest_api_url}wpfunnels/v1/import-export/bulk-export-funnel`,
797 {
798 method: 'POST',
799 headers: {
800 'Content-Type': 'application/json',
801 'X-WP-Nonce': wpApiSettings.nonce,
802 },
803 body: JSON.stringify(payload),
804 },
805 )
806 .then((response) => response.json())
807 .then((data) => {
808 if (data.success) {
809 const jsonData = data.data
810
811 let today = new Date()
812 let dd = String(today.getDate()).padStart(2, '0')
813 let mm = String(today.getMonth() + 1).padStart(2, '0') // January is 0!
814 let yyyy = today.getFullYear()
815 today = mm + '-' + dd + '-' + yyyy
816 const filename = 'wpfunnels-export-' + today + '-.json'
817
818 download(JSON.stringify(jsonData), filename, 'text/plain')
819 }
820 loader.hide()
821 window.location.href = data.redirectUrl
822 })
823 .catch((error) => {
824 console.error('Error:', error)
825 loader.hide()
826 })
827 selectedIds = []
828 }
829
830 /**
831 * Show import funnels Modal
832 *
833 * @param event
834 * @since 2.6.3
835 */
836 FunnelHandler.prototype.ShowImportFunnelModal = function (e) {
837 e.stopPropagation()
838 e.preventDefault()
839 // Reset back to the upload form: a previous run may have left the modal showing
840 // progress or a result card.
841 $('.wpfnl-import-progress').hide().removeClass('is-stalled')
842 $('.wpfnl-import-result').hide()
843 $('#wpfnl-import-funnels').show()
844 $('#wpfnl-export-import-warning').css('display', 'none')
845 $('.import-funnel-modal').addClass('show-modal')
846 }
847
848 /**
849 * Stop Propagation for .import-funnel-modal-wrapper
850 *
851 */
852 FunnelHandler.prototype.PreventImportFunnelModal = function (e) {
853 e.stopPropagation()
854 }
855
856 /**
857 * Close import funnels Modal
858 *
859 * @param event
860 * @since 2.6.3
861 */
862 FunnelHandler.prototype.CloseImportFunnelModal = function (e) {
863 e.preventDefault()
864 $('.import-funnel-modal').removeClass('show-modal')
865 $('#wpfnl-export-import-warning').css('display', 'none')
866 }
867
868 /**
869 * Show import funnels Modal
870 *
871 * @param event
872 * @since 2.6.3
873 */
874 FunnelHandler.prototype.ShowImportFunnelModal = function (e) {
875 e.stopPropagation()
876 e.preventDefault()
877 // Reset back to the upload form: a previous run may have left the modal showing
878 // progress or a result card.
879 $('.wpfnl-import-progress').hide().removeClass('is-stalled')
880 $('.wpfnl-import-result').hide()
881 $('#wpfnl-import-funnels').show()
882 $('#wpfnl-export-import-warning').css('display', 'none')
883 $('.import-funnel-modal').addClass('show-modal')
884 }
885
886 /**
887 * Stop Propagation for .import-funnel-modal-wrapper
888 *
889 */
890 FunnelHandler.prototype.PreventImportFunnelModal = function (e) {
891 e.stopPropagation()
892 }
893
894 /**
895 * Close import funnels Modal
896 *
897 * @param event
898 * @since 2.6.3
899 */
900 FunnelHandler.prototype.CloseImportFunnelModal = function (e) {
901 e.preventDefault()
902 $('.import-funnel-modal').removeClass('show-modal')
903 $('#wpfnl-export-import-warning').css('display', 'none')
904 }
905
906 /**
907 * Show a validation/error message inside the import funnel modal.
908 *
909 * The message element carries a default text, so it is always set
910 * explicitly here to avoid leaking a previous message.
911 *
912 * @param message
913 * @since 2.6.3
914 */
915 FunnelHandler.prototype.ShowImportWarning = function (message) {
916 $('#wpfnl-export-import-warning')
917 .text(message || 'Please select a valid file.')
918 .css('display', 'inline-block')
919 $('#wpfnl-import-funnel .wpfnl-loader').css('display', 'none')
920 }
921
922 /**
923 * Pull the error message out of an ajax response.
924 *
925 * wp_send_json_error() responses arrive either as a parsed body
926 * (HTTP 200) or on the jqXHR when a status code was passed.
927 *
928 * @param response
929 * @since 2.6.3
930 */
931 FunnelHandler.prototype.GetImportErrorMessage = function (response) {
932 const body = response && response.responseJSON ? response.responseJSON : response
933
934 if (body && body.data && body.data.message) {
935 return body.data.message
936 }
937
938 if (body && typeof body.data === 'string') {
939 return body.data
940 }
941
942 return ''
943 }
944
945 /**
946 *
947 * Ajax handler for import funnels
948 * funnel action
949 *
950 * @param event
951 * @since 2.6.3
952 */
953 FunnelHandler.prototype.ImportFunnels = function (event) {
954 event.preventDefault()
955 // `this` is the submitted form here, so reach the helpers via the prototype.
956 const handler = FunnelHandler.prototype
957 $('#wpfnl-import-funnel .wpfnl-loader').css('display', 'inline-block')
958 $('#wpfnl-export-import-warning').css('display', 'none')
959 let formData = new FormData(this)
960 let importFile = $('#wpfnl-file-import')[0].files[0]
961 if (importFile) {
962 const fileName = importFile?.name
963 const fileExtension = fileName.split('.').pop()
964 if ('json' === fileExtension) {
965 formData.append('action', 'wpfnl_import_funnels')
966 formData.append('is_ajax', 'yes')
967 formData.append('nonce', WPFunnelVars.import_nonce)
968 formData.append('uploaded_file', importFile)
969
970 $.ajax({
971 url: WPFunnelVars.ajaxurl,
972 type: 'post',
973 contentType: false,
974 dataType: 'json',
975 processData: false,
976 data: formData,
977 success: function (response) {
978 // wp_send_json_error() without a status code still returns HTTP 200.
979 if (response && false === response.success) {
980 handler.ShowImportWarning(handler.GetImportErrorMessage(response))
981 return
982 }
983 $('#wpfnl-import-funnel .wpfnl-loader').css('display', 'none')
984 // Deliberately no page reload here. The job has only been *queued*
985 // at this point, so reloading used to land the user on an unchanged
986 // funnel list and force them to keep refreshing to find out what
987 // happened. Stay open and follow the job instead.
988 showImportProgress()
989 pollImportStatus(response?.data?.run_id || '')
990 },
991 error: function (jqXHR) {
992 // Validation failures are sent with a 4xx status code.
993 const body =
994 jqXHR && jqXHR.responseJSON ? jqXHR.responseJSON : null
995 // 409: a run really is still going. Offer to clear it rather than
996 // leaving the user stuck behind "Import already scheduled".
997 if (body && body.data && body.data.can_reset) {
998 showImportProgress()
999 pollImportStatus(body.data.run_id || '')
1000 return
1001 }
1002 handler.ShowImportWarning(handler.GetImportErrorMessage(jqXHR))
1003 },
1004 })
1005 } else {
1006 handler.ShowImportWarning('Please select a valid file.')
1007 }
1008 } else {
1009 handler.ShowImportWarning('Please select a valid file.')
1010 }
1011 }
1012
1013 /**
1014 *
1015 * Ajax handler for import funnels
1016 * funnel action
1017 *
1018 * @param event
1019 * @since 2.6.3
1020 */
1021 FunnelHandler.prototype.UploadFile = function (event) {
1022 event.preventDefault()
1023 $('#wpfnl-export-import-warning').css('display', 'none')
1024 let importFile = $('#wpfnl-file-import')[0].files[0]
1025
1026 if (importFile) {
1027 const fileName = importFile?.name
1028 const fileExtension = fileName.split('.').pop()
1029
1030 if ('json' === fileExtension) {
1031 $('#wpfnl-export-import-warning').css('display', 'none')
1032 $('.import-funnel-modal .import-label').addClass('file-added')
1033 $('.import-funnel-modal .import-label > h4').text('Json file ready for import.')
1034 $('.import-funnel-modal .import-label > p').text(fileName)
1035 } else {
1036 $('.import-funnel-modal .import-label').removeClass('file-added')
1037 FunnelHandler.prototype.ShowImportWarning('Please select a valid file.')
1038
1039 $('.import-funnel-modal .import-label > h4').html(
1040 'Drag & Drop or <span class="primary-color">Choose file</span> to upload.',
1041 )
1042 $('.import-funnel-modal .import-label > p').text(
1043 'Supported formats: JSON file.',
1044 )
1045 }
1046 } else {
1047 $('.import-funnel-modal .import-label').removeClass('file-added')
1048 FunnelHandler.prototype.ShowImportWarning('Please select a valid file.')
1049
1050 $('.import-funnel-modal .import-label > h4').html(
1051 'Drag & Drop or <span class="primary-color">Choose file</span> to upload.',
1052 )
1053 $('.import-funnel-modal .import-label > p').text('Supported formats: JSON file.')
1054 }
1055 }
1056
1057 /**
1058 * Translated string with an English fallback.
1059 *
1060 * Strings in this file are historically hardcoded; new ones go through
1061 * WPFunnelVars.getText so they are actually translatable.
1062 *
1063 * @param key
1064 * @param fallback
1065 *
1066 * @since 2.5.16
1067 */
1068 function importText(key, fallback) {
1069 const bag = window.WPFunnelVars && WPFunnelVars.getText ? WPFunnelVars.getText : {}
1070 return bag[key] || fallback
1071 }
1072
1073 /**
1074 * Swap the import modal into its progress state.
1075 *
1076 * @since 2.5.16
1077 */
1078 function showImportProgress() {
1079 $('.import-funnel-modal').addClass('show-modal')
1080 $('#wpfnl-import-funnels').hide()
1081 $('.wpfnl-import-result').hide()
1082 $('.wpfnl-import-progress').show()
1083 $('.wpfnl-import-progress').removeClass('is-stalled')
1084 $('.wpfnl-import-progress__label').text(
1085 importText('import_preparing', 'Preparing import…'),
1086 )
1087 $('.wpfnl-import-progress__bar').css('width', '0%')
1088 $('.wpfnl-import-progress__meta').text('')
1089 }
1090
1091 /**
1092 * Read the current import status.
1093 *
1094 * @param runId
1095 *
1096 * @since 2.5.16
1097 */
1098 function fetchImportStatus(runId) {
1099 const base = window.WPFunnelVars ? WPFunnelVars.rest_api_url : ''
1100 const url =
1101 base +
1102 'wpfunnels/v1/import-export/import-status' +
1103 (runId ? '?run_id=' + encodeURIComponent(runId) : '')
1104
1105 return fetch(url, {
1106 method: 'GET',
1107 headers: { 'X-WP-Nonce': WPFunnelVars.nonce },
1108 }).then(function (response) {
1109 if (!response.ok) {
1110 throw new Error('status_request_failed')
1111 }
1112 return response.json()
1113 })
1114 }
1115
1116 /**
1117 * Paint one status tick into the progress UI.
1118 *
1119 * @param status
1120 *
1121 * @since 2.5.16
1122 */
1123 function renderImportProgress(status) {
1124 const pct = Math.max(0, Math.min(100, parseInt(status.pct, 10) || 0))
1125
1126 $('.wpfnl-import-progress__label').text(
1127 status.label || importText('import_in_progress', 'Importing funnels…'),
1128 )
1129 $('.wpfnl-import-progress__bar').css('width', pct + '%')
1130
1131 let meta = ''
1132 if (status.total_funnels) {
1133 meta =
1134 status.done_funnels +
1135 ' / ' +
1136 status.total_funnels +
1137 ' ' +
1138 importText('import_funnels_word', 'funnels')
1139 if (status.total_steps) {
1140 meta +=
1141 ' · ' +
1142 status.done_steps +
1143 ' / ' +
1144 status.total_steps +
1145 ' ' +
1146 importText('import_steps_word', 'steps')
1147 }
1148 }
1149 $('.wpfnl-import-progress__meta').text(meta)
1150 }
1151
1152 /**
1153 * Render the terminal state: what landed, what did not.
1154 *
1155 * @param status
1156 *
1157 * @since 2.5.16
1158 */
1159 function renderImportResult(status) {
1160 const imported = Array.isArray(status.imported) ? status.imported : []
1161 const failed = Array.isArray(status.failed) ? status.failed : []
1162
1163 $('.wpfnl-import-progress').hide()
1164 $('.wpfnl-import-result').show()
1165
1166 let summary = status.message || ''
1167 if (!summary) {
1168 summary =
1169 'failed' === status.state
1170 ? importText('import_failed', 'The import could not be completed.')
1171 : importText('import_completed', 'Import complete.')
1172 }
1173 $('.wpfnl-import-result__summary').text(summary)
1174
1175 const $list = $('.wpfnl-import-result__list').empty()
1176
1177 imported.forEach(function (item) {
1178 const stepsWord = importText('import_steps_word', 'steps')
1179 let note = item.steps + ' ' + stepsWord
1180
1181 // A partially imported funnel is the case worth being precise about: say how
1182 // many steps are missing rather than just flagging it as odd.
1183 if ('partial' === item.status) {
1184 const total = (item.steps || 0) + (item.failed_steps || 0)
1185 note =
1186 item.steps +
1187 ' / ' +
1188 total +
1189 ' ' +
1190 stepsWord +
1191 ' · ' +
1192 importText('import_partial', 'some steps failed')
1193 }
1194
1195 $list.append(
1196 $('<li/>')
1197 .addClass('partial' === item.status ? 'is-failed' : '')
1198 .append($('<span/>').text(item.name || ''))
1199 .append($('<span/>').addClass('wpfnl-import-result__note').text(note)),
1200 )
1201 })
1202
1203 failed.forEach(function (item) {
1204 $list.append(
1205 $('<li/>')
1206 .addClass('is-failed')
1207 .append($('<span/>').text(item.name || ''))
1208 .append(
1209 $('<span/>')
1210 .addClass('wpfnl-import-result__note')
1211 .text(item.message || importText('import_failed_item', 'failed')),
1212 ),
1213 )
1214 })
1215
1216 // Only claim success when nothing failed. A partial run has already been spelled
1217 // out in the list above, and a cheerful toast on top of it would misrepresent it.
1218 if (imported.length && !failed.length) {
1219 try {
1220 localStorage.setItem('wpfnl_show_toast', 'import_success')
1221 } catch (e) {
1222 // Private mode / blocked storage: the result card already says what happened.
1223 }
1224 }
1225 }
1226
1227 /**
1228 * Follow a background import to completion.
1229 *
1230 * Bounded polling with backoff rather than setInterval: the job can legitimately run
1231 * for minutes, and a fixed short interval would hammer the REST route for the whole
1232 * duration. Stall detection happens server-side — the process that died cannot report
1233 * on itself — so this only has to react to the state it is handed.
1234 *
1235 * @param runId
1236 *
1237 * @since 2.5.16
1238 */
1239 async function pollImportStatus(runId) {
1240 const started = Date.now()
1241 const maxMs = 15 * 60 * 1000
1242 let attempt = 0
1243 let consecutiveErrors = 0
1244
1245 while (Date.now() - started < maxMs) {
1246 const delay = attempt < 5 ? 1000 : attempt < 20 ? 2000 : 5000
1247 await new Promise(function (resolve) {
1248 setTimeout(resolve, delay)
1249 })
1250 attempt++
1251
1252 let status
1253 try {
1254 status = await fetchImportStatus(runId)
1255 consecutiveErrors = 0
1256 } catch (e) {
1257 // A blip should not kill a long-running import view; three in a row means
1258 // something is actually wrong.
1259 consecutiveErrors++
1260 if (consecutiveErrors >= 3) {
1261 renderImportResult({
1262 state: 'failed',
1263 message: importText(
1264 'import_status_unavailable',
1265 'Lost contact with the import. Refresh the page to check on it.',
1266 ),
1267 })
1268 return
1269 }
1270 continue
1271 }
1272
1273 if (!runId && status.run_id) {
1274 runId = status.run_id
1275 }
1276
1277 // Somebody else started an import; this view is no longer authoritative.
1278 if ('superseded' === status.state || 'idle' === status.state) {
1279 return
1280 }
1281
1282 if ('stalled' === status.state) {
1283 $('.wpfnl-import-progress').addClass('is-stalled')
1284 $('.wpfnl-import-progress__label').text(
1285 importText(
1286 'import_stalled',
1287 'The import seems to have stopped responding. Cancel it to try again.',
1288 ),
1289 )
1290 return
1291 }
1292
1293 renderImportProgress(status)
1294
1295 if ('completed' === status.state || 'failed' === status.state) {
1296 renderImportResult(status)
1297 return
1298 }
1299 }
1300
1301 $('.wpfnl-import-progress__label').text(
1302 importText(
1303 'import_taking_long',
1304 'This import is taking longer than expected. Refresh the page to check on it.',
1305 ),
1306 )
1307 }
1308
1309 /**
1310 * Resume the progress view for an import still running from an earlier page view.
1311 *
1312 * @since 2.5.16
1313 */
1314 function resumeImportIfRunning() {
1315 if (!$('.import-funnel-modal').length || !window.WPFunnelVars) {
1316 return
1317 }
1318
1319 fetchImportStatus('')
1320 .then(function (status) {
1321 if ('running' === status.state || 'queued' === status.state) {
1322 showImportProgress()
1323 renderImportProgress(status)
1324 pollImportStatus(status.run_id || '')
1325 }
1326 })
1327 .catch(function () {
1328 // No import to resume, or the route is unreachable — stay quiet.
1329 })
1330 }
1331
1332 /**
1333 * Clear a stuck import so a new one can be started.
1334 *
1335 * @param event
1336 *
1337 * @since 2.5.16
1338 */
1339 FunnelHandler.prototype.CancelImport = function (event) {
1340 event.preventDefault()
1341
1342 const $button = $(this)
1343 $button.find('.wpfnl-loader').css('display', 'inline-block')
1344
1345 fetch(WPFunnelVars.rest_api_url + 'wpfunnels/v1/import-export/import-reset', {
1346 method: 'POST',
1347 headers: {
1348 'Content-Type': 'application/json',
1349 'X-WP-Nonce': WPFunnelVars.nonce,
1350 },
1351 })
1352 .then(function () {
1353 $button.find('.wpfnl-loader').css('display', 'none')
1354 $('.wpfnl-import-progress').hide().removeClass('is-stalled')
1355 $('.import-funnel-modal').removeClass('show-modal')
1356 $('#wpfnl-import-funnels').show()
1357 showToast(
1358 'success',
1359 importText('import_cancelled', 'The import has been cancelled.'),
1360 )
1361 })
1362 .catch(function () {
1363 $button.find('.wpfnl-loader').css('display', 'none')
1364 showToast(
1365 'error',
1366 importText('import_cancel_failed', 'Could not cancel the import.'),
1367 )
1368 })
1369 }
1370
1371 /**
1372 * Download json file
1373 *
1374 * @param content
1375 * @param fileName
1376 * @param contentType
1377 *
1378 * @since 2.6.3
1379 */
1380 function download(content, fileName, contentType) {
1381 const a = document.createElement('a')
1382 const file = new Blob([content], { type: contentType })
1383 a.href = URL.createObjectURL(file)
1384 a.download = fileName
1385 a.click()
1386 }
1387
1388 /**
1389 * Realtime funnel name change on header
1390 *
1391 * @param event
1392 * @since 1.0.0
1393 */
1394 var fnl_name = ''
1395 var fnl_name2 = ''
1396 var funnelNameWidth = ''
1397 $('.funnel-name-edit').on('click', function (e) {
1398 e.stopPropagation();
1399 fnl_name = $(this).parents('.steps-page__fnl-name').find('.funnel-name').text()
1400 $(this).hide()
1401 funnelNameWidth = $(this).parents('.steps-page__fnl-name').find('.funnel-name').width()
1402
1403 $(this)
1404 .parents('.steps-page__fnl-name')
1405 .find('.funnel-name-input')
1406 .css('width', funnelNameWidth + 'px')
1407 $(this)
1408 .parents('.steps-page__fnl-name')
1409 .find('.funnel-name-input')
1410 .val(fnl_name)
1411 .show()
1412 .focus()
1413 $(this).parents('.steps-page__fnl-name').find('.funnel-name').hide()
1414 })
1415
1416 $('.funnel-name-input').keyup(function (e) {
1417 e.stopPropagation();
1418 $(this).parents('.steps-page__fnl-name').find('.funnel-name').text($(this).val())
1419 funnelNameWidth = $(this).parents('.steps-page__fnl-name').find('.funnel-name').width()
1420
1421 let input = $(this);
1422 let valueLength = input.val().length;
1423 input.css('width', funnelNameWidth + 'px');
1424
1425 // When Enter is pressed, save and hide input, show funnel name
1426 if (e.keyCode === 13 || e.key === 'Enter') {
1427 fnl_name2 = $(this).val();
1428
1429 if(fnl_name2.length === 0){
1430 fnl_name2 = fnl_name;
1431 }
1432
1433 $(this).val(fnl_name2).hide();
1434 $(this).parents('.steps-page__fnl-name').find('.funnel-name').text(fnl_name2).show();
1435 $(this).blur(); // Remove focus from input
1436 }
1437 })
1438
1439 $('.funnel-name-input').on('click', function (e) {
1440 e.stopPropagation();
1441 })
1442
1443 if($('.funnel-name-input').length > 0){
1444 $('body').on('click', function (e) {
1445 fnl_name2 = $('.steps-page__fnl-name .funnel-name-input').val() || '';
1446
1447 if(fnl_name2.length === 0){
1448 fnl_name2 = fnl_name;
1449 }
1450
1451 $('.steps-page__fnl-name .funnel-name-input').val(fnl_name2).hide()
1452 $('.steps-page__fnl-name .funnel-name').text(fnl_name2).show()
1453 })
1454 }
1455
1456 /**
1457 * Realtime automation name change on automation drawer
1458 *
1459 * @param event
1460 * @since 1.0.0
1461 */
1462 var automation_name = ''
1463 var automation_name2 = ''
1464 $(document).on('click', '.automation-name-edit', function (e) {
1465 e.preventDefault()
1466
1467 automation_name = $(this)
1468 .parents('.automation-name-wrapper')
1469 .find('.automation-name-preview')
1470 .text()
1471 $(this).hide()
1472 $('.automation-name-cancel').css('display', 'flex')
1473 $(this)
1474 .parents('.automation-name-wrapper')
1475 .find('.automation-name-input')
1476 .val(automation_name)
1477 .css('display', 'flex')
1478 $(this).parents('.automation-name-wrapper').find('.automation-name-preview').hide()
1479 $(this)
1480 .parents('.automation-name-wrapper')
1481 .find('.automation-name-submit')
1482 .css('display', 'flex')
1483 })
1484
1485 // $(document).on("click", ".automation-name-edit", function(e) {
1486 $('.automation-name-input').keyup(function () {
1487 $(this)
1488 .parents('.automation-name-wrapper')
1489 .find('.automation-name-preview')
1490 .text($(this).val())
1491 })
1492
1493 $(document).on('click', '.automation-name-submit', function (e) {
1494 e.preventDefault()
1495 automation_name2 = $(this)
1496 .parents('.automation-name-wrapper')
1497 .find('.automation-name-input')
1498 .val()
1499 $(this).hide()
1500 $('.automation-name-cancel').hide()
1501 $(this)
1502 .parents('.automation-name-wrapper')
1503 .find('.automation-name-input')
1504 .val(automation_name2)
1505 .hide()
1506 $(this)
1507 .parents('.automation-name-wrapper')
1508 .find('.automation-name-preview')
1509 .text(automation_name2)
1510 .css('display', 'flex')
1511 $(this)
1512 .parents('.automation-name-wrapper')
1513 .find('.automation-name-edit')
1514 .css('display', 'flex')
1515 })
1516
1517 $(document).on('click', '.automation-name-cancel', function (e) {
1518 e.preventDefault()
1519 $(this).hide()
1520 $('.automation-name-cancel').hide()
1521 $(this)
1522 .parents('.automation-name-wrapper')
1523 .find('.automation-name-input')
1524 .val(automation_name)
1525 .hide()
1526 $(this)
1527 .parents('.automation-name-wrapper')
1528 .find('.automation-name-preview')
1529 .text(automation_name)
1530 .css('display', 'flex')
1531 $(this).parents('.automation-name-wrapper').find('.automation-name-submit').hide()
1532 $(this)
1533 .parents('.automation-name-wrapper')
1534 .find('.automation-name-edit')
1535 .css('display', 'flex')
1536 })
1537
1538 $(document).on('click', '#save_automation', function (e) {
1539 e.preventDefault()
1540 $('.event-trigger').each(function () {
1541 if ($(this).children('option:selected').val() == '') {
1542 $(this).parents('.wpfnl-form-group').addClass('field-required')
1543 } else {
1544 $(this).parents('.wpfnl-form-group').removeClass('field-required')
1545 }
1546 })
1547 $('.list-trigger').each(function () {
1548 if ($(this).children('option:selected').val() == '') {
1549 $(this).parents('.wpfnl-form-group').addClass('field-required')
1550 } else {
1551 $(this).parents('.wpfnl-form-group').removeClass('field-required')
1552 }
1553 })
1554 $('.tag-trigger').each(function () {
1555 if ($(this).children('option:selected').val() == '') {
1556 $(this).parents('.wpfnl-form-group').addClass('field-required')
1557 } else {
1558 $(this).parents('.wpfnl-form-group').removeClass('field-required')
1559 }
1560 })
1561 })
1562
1563 //-----remove "field-required" class when data selected-------
1564 $(document).on('change', '.single-trigger .selectbox-wrapper select', function (e) {
1565 if ($(this).children('option:selected').val() != '') {
1566 $(this).parents('.wpfnl-form-group').removeClass('field-required')
1567 }
1568 })
1569
1570 /**
1571 * change funnel name
1572 *
1573 * @param event
1574 * @since 1.0.0
1575 */
1576 FunnelHandler.prototype.changeFunnelName = function (event) {
1577 event.preventDefault()
1578 var payload = {
1579 data: $(this).serialize(),
1580 },
1581 button = $(this).find('.funnel-name-submit')
1582 button.hide()
1583 button.parents('.steps-page__fnl-name').find('.funnel-name-input').hide()
1584 button.parents('.steps-page__fnl-name').find('.funnel-name').show()
1585 button.parents('.steps-page__fnl-name').find('.funnel-name-edit').show()
1586 wpAjaxHelperRequest('funnel-name-change', payload)
1587 .success(function (response) {
1588 location.reload()
1589 })
1590 .error(function (response) {})
1591 }
1592
1593 var StepHandler = function () {
1594 $(document.body)
1595 .on('click', '#wpfnl-delete-step', this.deleteStep)
1596 .on('click', '#wpfnl-update-checkout-product-tab', this.updateCheckoutProduct)
1597 .on('click', '#wpfnl-update-thank-you-settings', this.updateThankYouSettings)
1598 .on('click', '#wpfnl-update-upsell-settings', this.updateUpsellSettings)
1599 .on('click', '#wpfnl-update-downsell-settings', this.updateDownsellSettings)
1600 .on('change', '#wpfnl-choose-step-type', this.stepTypeChange)
1601 // .on('click', '#wpfnl-add-product', this.addProduct)
1602 }
1603
1604 /**
1605 * add product
1606 * @param event
1607 */
1608 StepHandler.prototype.addProduct = function (event) {
1609 event.preventDefault()
1610 var _prObj = $('#wpfnl-checkout-products').select2('data')[0],
1611 step_id = $(this).attr('data-id')
1612 if (_prObj) {
1613 product_option.push({
1614 id: _prObj.id,
1615 quantity: 1,
1616 })
1617 var payload = {
1618 id: _prObj.id,
1619 step_id: step_id,
1620 products: JSON.stringify(product_option),
1621 index: parseInt($('.product__single-accordion').length),
1622 },
1623 that = $(this)
1624
1625 wpAjaxHelperRequest('wpfnl-add-product', payload)
1626 .success(function (response) {
1627 if (response.success) {
1628 $('.no-product-notice').hide()
1629 $('.accordion-head').show()
1630 // $('.product-accordion__wrapper').append(response.html);
1631 $('.product-single-accordion__sortable-wrapper').append(response.html)
1632 $('#wpfnl-checkout-products').val(null).trigger('change')
1633 if (product_option.length) that.html('Add product')
1634 // $('.product__single-accordion:nth-child(2)').addClass('active');
1635 }
1636 console.log('Woohoo!')
1637 console.log(response)
1638 $('#setp-list-' + step_id + ' span').css('color', 'black')
1639
1640 $('.product-single-accordion__sortable-wrapper').sortable({
1641 axis: 'y',
1642 start: function (event, ui) {},
1643 update: function (event, ui) {
1644 var product_order = $(
1645 '.product-single-accordion__sortable-wrapper',
1646 ).sortable('toArray')
1647
1648 product_option = []
1649 var funnel_id = getUrlParameter('id')
1650
1651 for (var i in product_order) {
1652 var dragger_id = product_order[i]
1653 var prod_id = dragger_id.replace(
1654 'product__single-accordion-',
1655 '',
1656 )
1657 var quantity = $('#product-quantity-' + prod_id).val()
1658 product_option.push({
1659 id: prod_id,
1660 quantity: quantity,
1661 })
1662 }
1663 },
1664 })
1665 $('.product-single-accordion__sortable-wrapper').disableSelection()
1666 })
1667 .error(function (response) {})
1668 }
1669 }
1670
1671 /**
1672 * delete product from checkout
1673 *
1674 * @param event
1675 */
1676 StepHandler.prototype.deleteproduct = function (event) {
1677 event.preventDefault()
1678 var index = $(this).attr('data-index')
1679 product_option.splice(index, 1)
1680 var payload = {
1681 step_id: $(this).attr('data-id'),
1682 products: JSON.stringify(product_option),
1683 }
1684 wpAjaxHelperRequest('wpfnl-update-checkout-product-tab', payload)
1685 .success(function (response) {
1686 if (response.success) {
1687 location.reload()
1688 return false
1689 }
1690 console.log('Woohoo!')
1691 console.log(response)
1692 })
1693 .error(function (response) {})
1694 }
1695
1696 /**
1697 * save function for checkout steps
1698 * product tab
1699 *
1700 * @param event
1701 * @since 1.0.0
1702 */
1703 StepHandler.prototype.updateCheckoutProduct = function (event) {
1704 event.preventDefault()
1705 var thisLoader = $(this).find('.wpfnl-loader')
1706 var thisAlert = $(this).siblings('.wpfnl-alert')
1707
1708 //=== Enable additional checkout fields===//
1709 var coupon = 'no'
1710 if ($('#enable-checkout-coupon').prop('checked') == true) {
1711 coupon = 'yes'
1712 } else if ($('#enable-checkout-coupon').prop('checked') == false) {
1713 coupon = 'no'
1714 }
1715
1716 //=== Enable additional checkout fields===//
1717
1718 thisLoader.fadeIn()
1719 var payload = {
1720 step_id: $(this).attr('data-iddata-id'),
1721 coupon: coupon,
1722 products: JSON.stringify(product_option),
1723 // discount: $(".wpfnl-checkout-discount").val(),
1724 }
1725 wpAjaxHelperRequest('wpfnl-update-checkout-product-tab', payload)
1726 .success(function (response) {
1727 thisLoader.fadeOut()
1728 thisAlert.text('Saved Successfully').addClass('box wpfnl-success').fadeIn()
1729
1730 setTimeout(function () {
1731 thisAlert.fadeOut().text('').removeClass('box wpfnl-success')
1732 }, 2000)
1733
1734 console.log('Woohoo!')
1735 console.log(response)
1736 })
1737 .error(function (response) {
1738 console.log('Uh, oh!')
1739 console.log(response.statusText)
1740
1741 thisLoader.fadeOut()
1742 thisAlert.text('Erorr occurred').addClass('box wpfnl-error').fadeIn()
1743 setTimeout(function () {
1744 thisAlert.fadeOut().text('').removeClass('box wpfnl-error')
1745 }, 2000)
1746 })
1747 }
1748
1749 /**
1750 * Set minimum time for custom redirection in thankyou page
1751 *
1752 * @param event
1753 *
1754 */
1755 $(document).on('keyup', '#set-time', function () {
1756 if ($('#set-time').val() && $('#set-time').val() < 1) {
1757 $('#set-time').val(1)
1758 }
1759 })
1760
1761 /**
1762 * save thankyou settings
1763 * options
1764 *
1765 * @param event
1766 * @since 1.0.0
1767 */
1768 StepHandler.prototype.updateThankYouSettings = function (event) {
1769 event.preventDefault()
1770 var thisLoader = $(this).find('.wpfnl-loader')
1771 var thisAlert = $(this).siblings('.wpfnl-alert')
1772 thisLoader.fadeIn()
1773 var payload = {
1774 step_id: $(this).attr('data-id'),
1775 text: $('.thankyou-page-text').val(),
1776 redirect_link: $('.thankyou-redirect-link').val(),
1777 order_overview: $('#enable-order-overview').is(':checked') ? 'on' : 'off',
1778 order_details: $('#enable-order-details').is(':checked') ? 'on' : 'off',
1779 billing_details: $('#enable-billing-details').is(':checked') ? 'on' : 'off',
1780 shipping_details: $('#enable-shipping-details').is(':checked') ? 'on' : 'off',
1781 is_custom_redirect: $('#enable-custom-redirect').is(':checked') ? 'on' : 'off',
1782
1783 is_direct_redirect: $('#direct-custom-redirect').is(':checked') ? 'on' : 'off',
1784 set_time: $('#set-time').val(),
1785 custom_redirect_url: $('#custom-redirect-url').val(),
1786 }
1787
1788 wpAjaxHelperRequest('update-thankyou-settings', payload)
1789 .success(function (response) {
1790 thisLoader.fadeOut()
1791 $('#wpfnl-toaster-wrapper').addClass('quick-toastify-successful-notification')
1792
1793 $('#wpfnl-toaster-icon').html(
1794 '<svg width="26" height="26" fill="none" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path fill="#4BAE4F" fill-rule="evenodd" d="M13 0C5.83 0 0 5.83 0 13s5.83 13 13 13 13-5.83 13-13S20.17 0 13 0z" clip-rule="evenodd"/><path fill="#fff" fill-rule="evenodd" d="M19.287 8.618a.815.815 0 010 1.148l-7.617 7.617a.812.812 0 01-1.148 0l-3.808-3.809a.815.815 0 010-1.147.815.815 0 011.147 0l3.235 3.234 7.044-7.043a.806.806 0 011.147 0z" clip-rule="evenodd"/></svg>',
1795 )
1796
1797 $('#wpfnl-toaster-message').html('Saved Successfully')
1798 $('#wpfnl-toaster-wrapper').show()
1799 setTimeout(function () {
1800 $('#wpfnl-toaster-wrapper').removeClass(
1801 'quick-toastify-successful-notification',
1802 )
1803 $('#wpfnl-toaster-wrapper').hide()
1804 }, 3000)
1805 })
1806 .error(function (response) {
1807 console.log('Uh, oh!')
1808 console.log(response.statusText)
1809 thisLoader.fadeOut()
1810 $('#wpfnl-toaster-wrapper').addClass('quick-toastify-warn-notification')
1811
1812 $('#wpfnl-toaster-icon').html(
1813 '<svg width="26" height="26" fill="none" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path fill="#EC5956" fill-rule="evenodd" d="M26 13c0 7.18-5.82 13-13 13S0 20.18 0 13 5.82 0 13 0s13 5.82 13 13zm-11.375 6.5a1.625 1.625 0 11-3.25 0 1.625 1.625 0 013.25 0zM13 4.875c-.898 0-1.625.728-1.625 1.625V13a1.625 1.625 0 103.25 0V6.5c0-.897-.727-1.625-1.625-1.625z" clip-rule="evenodd"/></svg>',
1814 )
1815
1816 $('#wpfnl-toaster-message').html('Erorr occurred')
1817 $('#wpfnl-toaster-wrapper').show()
1818 setTimeout(function () {
1819 $('#wpfnl-toaster-wrapper').removeClass('quick-toastify-warn-notification')
1820 $('#wpfnl-toaster-wrapper').hide()
1821 }, 3000)
1822 })
1823 }
1824
1825 /**
1826 * save upsell settings
1827 * options
1828 *
1829 * @param event
1830 * @since 1.0.0
1831 */
1832 StepHandler.prototype.updateUpsellSettings = function (event) {
1833 event.preventDefault()
1834 var thisLoader = $(this).find('.wpfnl-loader')
1835 var thisAlert = $(this).siblings('.wpfnl-alert')
1836 thisLoader.fadeIn()
1837 var payload = {
1838 step_id: $(this).attr('data-id'),
1839 product: $('.wpfnl-product-search').val(),
1840 quantity: $('#upsell-product-quantity').val(),
1841 product_price: $('#upsell-original-price').val(),
1842 product_sale_price: $('#upsell-sale-price').val(),
1843 discount_type: $('#upsell-discount-type').val(),
1844 discount_value: $('#upsell-discount-value').val(),
1845 hide_image: $('#img-hide-mobile').prop('checked') ? 'on' : 'off',
1846 next_step_yes: $('#next-step-yes').val(),
1847 next_step_no: $('#next-step-no').val(),
1848 }
1849 wpAjaxHelperRequest('update-upsell-settings', payload)
1850 .success(function (response) {
1851 thisLoader.fadeOut()
1852 thisAlert.text('Saved Successfully').addClass('box wpfnl-success').fadeIn()
1853 setTimeout(function () {
1854 thisAlert.fadeOut().text('').removeClass('box wpfnl-success')
1855 }, 2000)
1856 console.log('Woohoo!')
1857 console.log(response)
1858 })
1859 .error(function (response) {
1860 console.log('Uh, oh!')
1861 console.log(response.statusText)
1862 thisLoader.fadeOut()
1863 thisAlert.text('Erorr occurred').addClass('box wpfnl-error').fadeIn()
1864 setTimeout(function () {
1865 thisAlert.fadeOut().text('').removeClass('box wpfnl-error')
1866 }, 2000)
1867 })
1868 }
1869
1870 /**
1871 * save downsell settings
1872 * options
1873 *
1874 * @param event
1875 * @since 1.0.0
1876 */
1877 StepHandler.prototype.updateDownsellSettings = function (event) {
1878 event.preventDefault()
1879 var thisLoader = $(this).find('.wpfnl-loader')
1880 var thisAlert = $(this).siblings('.wpfnl-alert')
1881 thisLoader.fadeIn()
1882 var payload = {
1883 step_id: $(this).attr('data-id'),
1884 product: $('.wpfnl-product-search').val(),
1885 quantity: $('#downsell-product-quantity').val(),
1886 product_price: $('#downsell-original-price').val(),
1887 product_sale_price: $('#downsell-sale-price').val(),
1888 discount_type: $('#downsell-discount-type').val(),
1889 discount_value: $('#downsell-discount-value').val(),
1890 hide_image: $('#img-hide-mobile').prop('checked') ? 'on' : 'off',
1891 next_step_yes: $('#next-step-yes').val(),
1892 next_step_no: $('#next-step-no').val(),
1893 }
1894 wpAjaxHelperRequest('update-downsell-settings', payload)
1895 .success(function (response) {
1896 thisLoader.fadeOut()
1897 thisAlert.text('Saved Successfully').addClass('box wpfnl-success').fadeIn()
1898 setTimeout(function () {
1899 thisAlert.fadeOut().text('').removeClass('box wpfnl-success')
1900 }, 2000)
1901 console.log('Woohoo!')
1902 console.log(response)
1903 })
1904 .error(function (response) {
1905 console.log('Uh, oh!')
1906 console.log(response.statusText)
1907 thisLoader.fadeOut()
1908 thisAlert.text('Erorr occurred').addClass('box wpfnl-error').fadeIn()
1909 setTimeout(function () {
1910 thisAlert.fadeOut().text('').removeClass('box wpfnl-error')
1911 }, 2000)
1912 })
1913 }
1914
1915 /**
1916 * Ajax handler for step
1917 * deletion action
1918 *
1919 * @param event
1920 */
1921 StepHandler.prototype.deleteStep = function (event) {
1922 event.preventDefault()
1923 var step_id = $(this).attr('data-id')
1924 var payload = {
1925 step_id: step_id,
1926 }
1927 if (confirm('Are you sure?')) {
1928 wpAjaxHelperRequest('delete-step', payload)
1929 .success(function (response) {
1930 console.log('Woohoo!')
1931 console.log(response)
1932 window.location.href = response.redirectUrl
1933 })
1934 .error(function (response) {
1935 console.log('Uh, oh!')
1936 console.log(response.statusText)
1937 })
1938 }
1939 }
1940
1941 /**
1942 * Ajax handler for step
1943 * creation
1944 *
1945 * @param e
1946 * @since 1.0.0
1947 */
1948 StepHandler.prototype.createStep = function (e) {
1949 e.preventDefault()
1950 var thisLoader = $(this).find('.wpfnl-loader')
1951 var thisAlert = $(this).siblings('.wpfnl-alert')
1952
1953 thisLoader.fadeIn()
1954
1955 var wrapper = $('#create-step-form'),
1956 type = $(this).attr('data-step-type'),
1957 funnelId = $(this).attr('data-funnel-id'),
1958 stepListWrapper = $('#wpfnl-funnel-step-lists')
1959
1960 var payload = {
1961 funnel_id: funnelId,
1962 step_type: type,
1963 }
1964 wpAjaxHelperRequest('create-step', payload)
1965 .success(function (response) {
1966 console.log('success')
1967 thisLoader.fadeOut()
1968 thisAlert
1969 .text('Successfully Step Created')
1970 .addClass('box wpfnl-success')
1971 .fadeIn()
1972
1973 setTimeout(function () {
1974 thisAlert.fadeOut().text('').removeClass('box wpfnl-success')
1975 }, 2000)
1976
1977 if (response.success) {
1978 window.location.href = response.redirectUrl
1979 } else {
1980 console.log(response)
1981 }
1982 })
1983 .error(function (response) {
1984 thisLoader.fadeOut()
1985 thisAlert.text('Erorr Occurred').addClass('box wpfnl-error').fadeIn()
1986
1987 setTimeout(function () {
1988 thisAlert.fadeOut().text('').removeClass('box wpfnl-error')
1989 }, 2000)
1990 })
1991 }
1992
1993 StepHandler.prototype.stepTypeChange = function (event) {
1994 event.preventDefault()
1995 var wrapper = $('.choose-step-type'),
1996 step_type = $(this).find(':selected').val(),
1997 saveBtn = $('#wpfnl-create-step')
1998 if (
1999 WPFunnelVars.is_wc_installed === 'no' &&
2000 (step_type === 'checkout' || step_type === 'upsell' || step_type === 'downsell')
2001 ) {
2002 $('.wpfnl-modal__body').find('p').remove()
2003 wrapper.after(
2004 "<p style='text-align: center; color: red'>You need install and active WooCommerce to use this step type. </p>",
2005 )
2006 saveBtn.addClass('disabled').css('pointer-events', 'none')
2007 return
2008 } else {
2009 $('.wpfnl-modal__body').find('p').remove()
2010 saveBtn.removeClass('disabled').css('pointer-events', 'inherit')
2011 }
2012 }
2013
2014 var DataSerachHandler = function () {
2015 this.initProductSearch()
2016 this.initCouponSearch()
2017 }
2018
2019 /**
2020 * initialize product search
2021 * for checkout
2022 *
2023 * @param event
2024 * @since 1.0.0
2025 */
2026 DataSerachHandler.prototype.initProductSearch = function (event) {
2027 var select2Args = {
2028 minimumInputLength: 3,
2029 allowClear: true,
2030 maximumSelectionLength: 1,
2031 ajax: {
2032 url: WPFunnelVars.ajaxurl,
2033 dataType: 'json',
2034 delay: 250,
2035 data: function (params) {
2036 return {
2037 term: params.term,
2038 action: 'wpfnl_product_search',
2039 security: WPFunnelVars.security,
2040 }
2041 },
2042 processResults: function (data) {
2043 var terms = []
2044 if (data) {
2045 $.each(data, function (id, value) {
2046 terms.push({
2047 id: id,
2048 text: value.name,
2049 price: value.price,
2050 sale_price: value.sale_price,
2051 })
2052 })
2053 }
2054 return {
2055 results: terms,
2056 }
2057 },
2058 cache: true,
2059 },
2060 }
2061
2062 $('.wpfnl-product-search').on('select2:select', function (e) {
2063 var data = e.params.data
2064 $('#upsell-original-price').val(data.price)
2065 $('#upsell-sale-price').val(data.sale_price)
2066
2067 $('#downsell-original-price').val(data.price)
2068 $('#downsell-sale-price').val(data.sale_price)
2069 })
2070 $('.wpfnl-product-search').select2(select2Args)
2071 }
2072
2073 /**
2074 * initialize coupon search
2075 * for checkout
2076 *
2077 * @param event
2078 * @since 1.0.0
2079 */
2080 DataSerachHandler.prototype.initCouponSearch = function (event) {
2081 var select2Args = {
2082 minimumInputLength: 3,
2083 allowClear: true,
2084 ajax: {
2085 url: WPFunnelVars.ajaxurl,
2086 dataType: 'json',
2087 delay: 250,
2088 data: function (params) {
2089 return {
2090 term: params.term,
2091 action: 'wpfnl_coupon_search',
2092 security: WPFunnelVars.security,
2093 }
2094 },
2095 processResults: function (data) {
2096 var terms = []
2097 if (data) {
2098 $.each(data, function (id, text) {
2099 terms.push({
2100 id: id,
2101 text: text,
2102 })
2103 })
2104 }
2105 return {
2106 results: terms,
2107 }
2108 },
2109 cache: true,
2110 },
2111 }
2112 $('.wpfnl-discount-search').select2(select2Args)
2113 }
2114
2115 var AdminNotices = function () {
2116 $(document.body)
2117 .on('click', '#wpfnl-install-plugin', this.installPlugin)
2118 .on('wp-plugin-install-success', this.installSuccess)
2119 $(document).on('wp-plugin-install-success', self._installSuccess)
2120 }
2121 AdminNotices.prototype.installPlugin = function (e) {
2122 e.preventDefault()
2123 let slug = $(this).attr('data-slug')
2124 wp.updates.queue.push({
2125 action: 'install-plugin', // Required action.
2126 data: {
2127 slug: slug,
2128 },
2129 })
2130 wp.updates.queueChecker()
2131 }
2132 AdminNotices.prototype.installSuccess = function (event, response) {
2133 event.preventDefault()
2134 console.log(response)
2135 }
2136
2137 new FunnelHandler()
2138 new StepHandler()
2139 new DataSerachHandler()
2140 new AdminNotices()
2141
2142 /**
2143 * funnel list show more action on click
2144 *
2145 * @since 1.0.0
2146 */
2147 $('body').on('click', function () {
2148 $('.funnel-list__more-action').removeClass('show-actions')
2149 })
2150
2151 $('.funnel-list__more-action').on('click', function (e) {
2152 e.stopPropagation()
2153 $(this).toggleClass('show-actions')
2154 $(this)
2155 .parents('.funnel__single-list')
2156 .siblings()
2157 .find('.funnel-list__more-action')
2158 .removeClass('show-actions')
2159 })
2160
2161 $('.funnel-list__more-action .wpfnl-dropdown').on('click', function (e) {
2162 e.stopPropagation()
2163 })
2164
2165 /**
2166 * copy to clipboard
2167 *
2168 * @since 1.0.0
2169 */
2170 $('.wpfnl-copy-clipboard').on('click', function () {
2171 var getID = $(this).attr('data-id')
2172 var getText = $('#' + getID).val()
2173 CopyToClipboard(getText)
2174
2175 $(this).siblings('.copied-msg').text('Copied').fadeIn(500)
2176
2177 setTimeout(function () {
2178 $('.copied-msg').fadeOut('slow')
2179 }, 2500)
2180 })
2181
2182 /**
2183 * copy to clipboard helper function
2184 *
2185 * @since 1.0.0
2186 */
2187 function CopyToClipboard(text) {
2188 if (window.clipboardData && window.clipboardData.setData) {
2189 return clipboardData.setData('Text', text)
2190 } else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
2191 var textarea = document.createElement('textarea')
2192 textarea.textContent = text
2193 textarea.style.position = 'fixed'
2194 document.body.appendChild(textarea)
2195 textarea.select()
2196
2197 try {
2198 return document.execCommand('copy')
2199 } catch (ex) {
2200 console.warn('Copy to clipboard failed.', ex)
2201 return false
2202 } finally {
2203 document.body.removeChild(textarea)
2204 }
2205 }
2206 }
2207
2208 /**
2209 * open modal when add new step
2210 *
2211 * @param event
2212 * @since 1.0.0
2213 */
2214 $('.wpfnl-modal-close').on('click', function (e) {
2215 e.preventDefault()
2216 $(this).parents('.wpfnl-modal').fadeOut(200)
2217 })
2218
2219 $('.wpfnl-modal__wrapper').on('click', function (e) {
2220 e.stopPropagation()
2221 })
2222
2223 /**
2224 * step name change on step page
2225 *
2226 * @param event
2227 * @since 1.0.0
2228 */
2229 var stepName = ''
2230 $('.step-name-edit').on('click', function (e) {
2231 e.preventDefault()
2232 $(this).hide()
2233 stepName = $(this).parents('.title-area').find('.step-name-input').val()
2234 $(this).parents('.title-area').find('.step-name-input').show()
2235 $(this).parents('.title-area').find('.step-name-noupdate').show()
2236 $(this).parents('.title-area').find('.step-name').hide()
2237 $(this).parents('.title-area').find('.step-name-update').show()
2238 })
2239
2240 $('.step-name-update').on('click', function (e) {
2241 e.preventDefault()
2242 $(this).hide()
2243 $(this).parents('.title-area').find('.step-name-input').hide()
2244 $(this).parents('.title-area').find('.step-name-noupdate').hide()
2245 $(this).parents('.title-area').find('.step-name').show()
2246 $(this).parents('.title-area').find('.step-name-edit').show()
2247 })
2248
2249 $('.step-name-noupdate').on('click', function (e) {
2250 e.preventDefault()
2251 $(this).hide()
2252 $(this).parents('.title-area').find('.step-name-input').val(stepName).hide()
2253 $(this).parents('.title-area').find('.step-name-update').hide()
2254 $(this).parents('.title-area').find('.step-name').text(stepName).show()
2255 $(this).parents('.title-area').find('.step-name-edit').show()
2256 })
2257
2258 $('.step-name-input').keyup(function () {
2259 $(this).parents('.title-area').find('.step-name').text($(this).val())
2260 })
2261
2262 /**
2263 * step settings tab
2264 *
2265 * @since 1.0.0
2266 */
2267 $('.step-settings__single-tab-content:first-child').show()
2268
2269 $(document).on('click', '.steps-settings__tab-nav:not(.ab-nav) a', function (e) {
2270 if (!$(this).parent('li').hasClass('disabled')) {
2271 e.preventDefault()
2272 var dataID = $(this).attr('href')
2273
2274 $(this).parent('li').addClass('active').siblings().removeClass('active')
2275 $(this).parents('.steps-settings').find(dataID).show()
2276 $(this).parents('.steps-settings').find(dataID).siblings().hide()
2277 }
2278 })
2279
2280 /**
2281 * step settings product options tab
2282 *
2283 * @since 1.0.0
2284 */
2285 $('.product-options__tab-nav a').on('click', function (e) {
2286 e.preventDefault()
2287
2288 var dataID = $(this).attr('href')
2289 $(this).parent('li').addClass('active').siblings().removeClass('active')
2290
2291 $(this).parents('.wpfnl-product-options').find(dataID).show()
2292 $(this).parents('.wpfnl-product-options').find(dataID).siblings().hide()
2293 })
2294
2295 /**
2296 * wpfnl accordion
2297 *
2298 * @since 1.0.0
2299 */
2300 $('.wpfnl__accordion-content').hide()
2301 $('.wpfnl__single-accordion:first-child .wpfnl__accordion-content').show()
2302 $('.wpfnl__accordion-title').on('click', function (e) {
2303 e.preventDefault()
2304
2305 var dataID = $(this).attr('href')
2306
2307 $(this).parent('.wpfnl__single-accordion').find(dataID).slideToggle()
2308 $(this)
2309 .parents('.wpfnl__single-accordion')
2310 .siblings()
2311 .find('.wpfnl__accordion-content')
2312 .slideUp()
2313 })
2314
2315 /**
2316 * steps-header-hamburger toggle menu
2317 *
2318 * @since 1.0.0
2319 */
2320 $('body').on('click', function () {
2321 $('#steps-header-hamburger').removeClass('show')
2322 })
2323 // $(document).on("click", "#steps-header-hamburger", function(e) {
2324 $('#steps-header-hamburger').on('click', function (e) {
2325 e.stopPropagation()
2326 if (!$(this).hasClass('show')) {
2327 $(this).removeClass('show')
2328 } else {
2329 $(this).addClass('show')
2330 }
2331
2332 wpfnlDatePicker()
2333 })
2334
2335 /**
2336 * wpfnl step title edit
2337 *
2338 * @param event
2339 * @since 1.0.0
2340 */
2341 function step_edit(e) {
2342 e.preventDefault()
2343 var step_id = $(this).attr('data-id')
2344 var input = $('#step-name-input-' + step_id).val()
2345 var payload = {
2346 step_id: step_id,
2347 input: input,
2348 }
2349 wpAjaxHelperRequest('step-edit', payload)
2350 .success(function (response) {
2351 $('#setp-list-' + step_id + ' .title-txt').text(input)
2352
2353 if (response.success) {
2354 console.log('success')
2355 } else {
2356 console.log(response)
2357 }
2358 })
2359 .error(function (response) {
2360 console.log('error')
2361 })
2362 }
2363 $('.step-name-update').on('click', step_edit)
2364 })
2365
2366 function getUrlParameter(sParam) {
2367 var sPageURL = window.location.search.substring(1),
2368 sURLVariables = sPageURL.split('&'),
2369 sParameterName,
2370 i
2371
2372 for (i = 0; i < sURLVariables.length; i++) {
2373 sParameterName = sURLVariables[i].split('=')
2374
2375 if (sParameterName[0] === sParam) {
2376 return sParameterName[1] === undefined
2377 ? true
2378 : decodeURIComponent(sParameterName[1])
2379 }
2380 }
2381 }
2382
2383
2384
2385 /**
2386 * Checkout Edit Field delete alert modal
2387 *
2388 * @since 1.0.0
2389 */
2390 $(document).on('click', '.delete-checkout-field', function () {
2391 $(this)
2392 .parents('.checkout__single-field')
2393 .find('.wpfnl-delete-alert-wrapper')
2394 .css('display', 'flex')
2395 })
2396
2397 $(document).on('click', '.wpfnl-delete-confirm-btn .cancel', function () {
2398 $(this).parents('.wpfnl-delete-alert-wrapper').hide()
2399 })
2400
2401 /**
2402 * edit-field settings tab
2403 *
2404 * @since 1.0.0
2405 */
2406 $('.edit-field-settings__single-tab-content:first-child').show()
2407
2408 $(document).on('click', '.edit-field-settings__tab-nav a', function (e) {
2409 e.preventDefault()
2410 var dataID = $(this).attr('href')
2411 $(this).parent('li').addClass('active').siblings().removeClass('active')
2412 $(this).parents('.checkout-edit-field-tab__content-wrapper').find(dataID).show()
2413 $(this).parents('.checkout-edit-field-tab__content-wrapper').find(dataID).siblings().hide()
2414 })
2415
2416 /**
2417 * add new checkout field drawer
2418 *
2419 * @since 1.0.0
2420 */
2421 $('.add-new-checkout-field-btn').on('click', function (e) {
2422 e.preventDefault()
2423 $(this)
2424 .parents('.checkout-edit-field-tab__content-wrapper')
2425 .find('.add-checkout-field-wrapper')
2426 .addClass('show-drawer')
2427 })
2428
2429 $('.add-checkout-field-close').on('click', function (e) {
2430 e.preventDefault()
2431 $(this).parents('.add-checkout-field-wrapper').removeClass('show-drawer')
2432 })
2433
2434 /**
2435 * edit checkout field drawer
2436 *
2437 * @since 1.0.0
2438 */
2439 // $('button.edit-field').on('click', function(e) {
2440 $(document).on('click', 'button.edit-field', function (e) {
2441 e.preventDefault()
2442 $(this)
2443 .parents('.checkout-edit-field-tab__content-wrapper')
2444 .find('.edit-checkout-field-wrapper')
2445 .addClass('show-drawer')
2446 })
2447
2448 $('.add-checkout-field-close').on('click', function (e) {
2449 e.preventDefault()
2450 $(this).parents('.edit-checkout-field-wrapper').removeClass('show-drawer')
2451 })
2452
2453 /**
2454 * show edit field type options
2455 *
2456 * @since 1.0.0
2457 */
2458 $('.wpfnl-edit-field-type').on('change', function (e) {
2459 e.preventDefault()
2460 var thisVal = $(this).val()
2461
2462 if (thisVal == 'select') {
2463 $(this).parents('.field-body').find('.field-type-options').show()
2464 } else {
2465 $(this).parents('.field-body').find('.field-type-options').hide()
2466 }
2467 })
2468
2469 jQuery(document).ready(function () {
2470 var selectedType = $('.wpfnl-edit-field-type').val()
2471
2472 if (selectedType == 'select') {
2473 $('.wpfnl-edit-field-type').parents('.field-body').find('.field-type-options').show()
2474 } else {
2475 $('.wpfnl-edit-field-type').parents('.field-body').find('.field-type-options').hide()
2476 }
2477 })
2478
2479 /**
2480 * Step preview permalink copy to clipboard
2481 *
2482 * @since 2.2.5
2483 */
2484 $(document).on('click', '.steps-url-slug .copy-slug-url', function (e) {
2485 e.preventDefault()
2486 $(this).addClass('copy-confirmed')
2487 var $temp = $('<input>')
2488 $(this).parents('.field-group').append($temp)
2489 $temp.val($(this).parents('.field-group').find('#step-preview-link').val()).select()
2490 document.execCommand('copy')
2491 $temp.remove()
2492
2493 setTimeout(function () {
2494 $('.steps-url-slug .copy-slug-url').removeClass('copy-confirmed')
2495 }, 1000)
2496 })
2497
2498 $(document).on('keyup change input', '.wpfnl-set-quantity-limit', function (e) {
2499 // Get the input value
2500 var inputValue = $(this).val()
2501
2502 // If input is blank, default it to 1
2503 if (isNaN(inputValue)) {
2504 inputValue = '1'
2505 }
2506 // Remove any non-numeric characters except '.'
2507 inputValue = inputValue.replace(/[^0-9.]/g, '')
2508
2509 // Split the value into integer and decimal parts
2510 var parts = inputValue.split('.')
2511
2512 // If there are more than one decimal point, consider only the first part
2513 if (parts.length > 2) {
2514 inputValue = parts[0] + '.' + parts.slice(1).join('')
2515 }
2516
2517 // Parse the value into an integer
2518 var quantity = parseInt(inputValue)
2519 // Set the input value to the parsed integer
2520 $(this).val(quantity)
2521
2522 if (quantity < 1) {
2523 $(this).val(1)
2524 }
2525 })
2526
2527 $(document).on('blur', '.wpfnl-set-quantity-limit', function (e) {
2528 var inputValue = $(this).val()
2529 if (inputValue.trim() === '') {
2530 $(this).val('1')
2531 }
2532 })
2533
2534 /**
2535 * AB testing permalink copy to clipboard
2536 *
2537 * @since 3.1.0
2538 */
2539 $(document).on('click', '.copy-ab-url', function (e) {
2540 e.preventDefault()
2541 $(this).addClass('copy-confirmed')
2542 var $temp = $('<input>')
2543 $(this).parents('.header-right').append($temp)
2544 $temp.val($(this).parents('.header-right').find('#ab-testing-link').val()).select()
2545 document.execCommand('copy')
2546 $temp.remove()
2547
2548 setTimeout(function () {
2549 $('.copy-ab-url').removeClass('copy-confirmed')
2550 }, 1000)
2551 })
2552
2553 /**
2554 * rollback feature for WPF
2555 */
2556 $('select#wpfnl-rollback')
2557 .on('change', function () {
2558 var $this = $(this),
2559 $rollbackButton = $this.next('.wpfnl-rollback-button'),
2560 originalHref = $rollbackButton.attr('href'),
2561 selectedVersion = $this.val();
2562
2563 if (originalHref && originalHref.includes('VERSION')) {
2564 var updatedHref = originalHref.replace('VERSION', selectedVersion);
2565 $rollbackButton.attr('href', updatedHref);
2566 }
2567 })
2568 .trigger('change');
2569
2570
2571 $('.wpfnl-rollback-button').on('click', function (event) {
2572 event.preventDefault()
2573 var $this = $(this)
2574 if (confirm('Are you sure?')) {
2575 $this.addClass('show-loader')
2576 $this.addClass('loading')
2577 location.href = $this.attr('href')
2578 }
2579 })
2580
2581 // ---delete promotional-banner notice permanently ------
2582 $(document).on('click', '.gwpf-promotional-notice .close-promotional-banner', function (event) {
2583 event.preventDefault()
2584 $('.gwpf-promotional-notice').attr('style', 'display: none !important');
2585 wpAjaxHelperRequest('delete_promotional_banner')
2586 })
2587
2588 $(document).on('click', '.wpfnl-notification-counter__btn-area', function (event) {
2589 event.preventDefault()
2590 $('.gwpf-promotional-notice').attr('style', 'display: none !important');
2591 wpAjaxHelperRequest('delete_promotional_banner')
2592 })
2593
2594 // ---delete new UI notice permanently ------
2595 $(document).on('click', '.wpfunnels-newui-notice .close-newui-notice', function (event) {
2596 event.preventDefault()
2597 $('.wpfunnels-newui-notice.notice').css('display', 'none')
2598 wpAjaxHelperRequest('delete_new_ui_notice')
2599 })
2600
2601 /**
2602 * Multiple Orderbump Accordion
2603 *
2604 */
2605 $(document).on(
2606 'click',
2607 '.single-order-bump .order-bump-accordion-header .title-area',
2608 function (e) {
2609 e.preventDefault()
2610 $(this).parents('.single-order-bump').siblings().removeClass('expanded-orderbump')
2611 $(this).parents('.single-order-bump').toggleClass('expanded-orderbump')
2612
2613 $(this)
2614 .parents('.single-order-bump')
2615 .siblings()
2616 .find('.order-bump-accordion-content')
2617 .removeClass('show-content')
2618 $(this)
2619 .parents('.single-order-bump')
2620 .find('.order-bump-accordion-content')
2621 .toggleClass('show-content')
2622 },
2623 )
2624
2625 $(document).ready(function () {
2626 const $stickyElement = $('.wpfnl-pvf-table-header');
2627 if($stickyElement.length === 0) return;
2628 const stickyOffset = $stickyElement.offset().top;
2629
2630 $(window).on('scroll', function () {
2631 const scrollTop = $(this).scrollTop();
2632 if (scrollTop >= stickyOffset - 44) {
2633 $stickyElement.addClass('is-sticky');
2634 } else {
2635 $stickyElement.removeClass('is-sticky');
2636 }
2637 });
2638 });
2639
2640
2641 //------expand last orderbump when added a new orderbump----
2642 $(document).on('click', '.order-bump-header .add-new-orderbump', function (e) {
2643 e.preventDefault()
2644 $('.single-order-bump').siblings().removeClass('expanded-orderbump')
2645 $('.single-order-bump:last-child').addClass('expanded-orderbump')
2646
2647 $('.single-order-bump')
2648 .siblings()
2649 .find('.order-bump-accordion-content')
2650 .removeClass('show-content')
2651 $('.single-order-bump:last-child')
2652 .find('.order-bump-accordion-content')
2653 .addClass('show-content')
2654 })
2655
2656 /**
2657 * Automatic winner choose condition dropdown
2658 *
2659 */
2660 $(document).on('click', '.automatic-winner .set-condition .selected-item', function (e) {
2661 e.preventDefault()
2662 e.stopPropagation()
2663 $(this).parents('.wpfnl-selectbox').find('.selectable-option').slideToggle(300)
2664 })
2665 $(document).on('click', 'body', function () {
2666 $('.automatic-winner .set-condition .selectable-option').hide()
2667 })
2668
2669 $(document).on('click', '.automatic-winner .set-condition .selectable-option li', function (e) {
2670 e.preventDefault()
2671 var selected_item_text = $(this).text()
2672 var selected_item_data = $(this).attr('data-value')
2673
2674 $(this).siblings().removeClass('active')
2675 $(this).addClass('active')
2676 $('.automatic-winner .set-condition .selected-item')
2677 .text(selected_item_text)
2678 .attr('data-value', selected_item_data)
2679 })
2680
2681 /**
2682 * Show step control button when clik on step (on drawflow window page)
2683 *
2684 */
2685 $(document).on('click', '.drawflow .drawflow-node .single-node', function (e) {
2686 e.stopPropagation()
2687 $(this)
2688 .parents('.parent-node')
2689 .siblings()
2690 .find('.single-node')
2691 .removeClass('im-selected-node')
2692 $(this).siblings().removeClass('im-selected-node')
2693 $(this)
2694 .parent('.single-node-wrapper')
2695 .siblings()
2696 .find('.single-node')
2697 .removeClass('im-selected-node')
2698 $(this).addClass('im-selected-node')
2699 })
2700
2701 $(document).on('click', 'body', function () {
2702 $('.drawflow .drawflow-node .single-node').removeClass('im-selected-node')
2703 })
2704
2705 /**
2706 * Add list, add tag dropdown show/hide
2707 *
2708 */
2709 $(document).on('click', '.wpfnl-custom-selectbox .selectbox-selected-value', function (e) {
2710 e.stopPropagation()
2711 $(this).parents('.wpfnl-custom-selectbox').toggleClass('show-options')
2712 })
2713
2714 $(document).on('click', '.wpfnl-custom-selectbox .selectbox-options', function (e) {
2715 e.stopPropagation()
2716 })
2717
2718 $(document).on('click', 'body', function () {
2719 $('.wpfnl-custom-selectbox').removeClass('show-options')
2720 })
2721
2722 /**
2723 * Funnel Bulk select action dropdown
2724 *
2725 */
2726 $(document).on('click', '.bulk-delete-toggler', function (e) {
2727 e.stopPropagation()
2728 $(this).toggleClass('show-dropdown')
2729 })
2730
2731 $(document).on('click', '.wpfnl-dropdown', function (e) {
2732 e.stopPropagation()
2733 })
2734
2735 $(document).on('click', 'body', function () {
2736 $('.bulk-delete-toggler').removeClass('show-dropdown')
2737 })
2738
2739 $(document).on('change', 'select#wpfnl_listing_page_offset', updateFunnelListingPageOffset)
2740 function updateFunnelListingPageOffset() {
2741 const offset = $(this).find('option:selected').val()
2742 const queryParams = new URLSearchParams(window.location.search)
2743
2744 // Set new or modify existing parameter value.
2745 queryParams.set('pageno', '1')
2746 queryParams.set('per_page', offset)
2747 // Replace current querystring with the new one.
2748 history.replaceState(null, null, '?' + queryParams.toString())
2749 location.reload()
2750 }
2751
2752 function selectedFunnelIds(params) {
2753 let ids = []
2754 if (params.length > 0) {
2755 for (let key = 0; key < params.length; key++) {
2756 const inputItem = params[key]?.id
2757 const id = inputItem.match(/\d+/)[0]
2758 ids.push(parseInt(id))
2759 }
2760 }
2761 selectedIds = ids
2762 }
2763
2764 /**
2765 * Funnel Bulk select checkbox on change event
2766 *
2767 */
2768 function selectedFunnelCounter() {
2769 let totalSelectedFunnel = $('input[name=funnel-list-select]:checked').length
2770
2771 selectedFunnelIds($('input[name=funnel-list-select]:checked'))
2772
2773 if (totalSelectedFunnel > 0) {
2774 $('.funnel__single-list.list-header .bulk-action-wrapper').css('display', 'flex')
2775 } else {
2776 $('.funnel__single-list.list-header .bulk-action-wrapper').css('display', 'none')
2777 }
2778
2779 if (totalSelectedFunnel > 1) {
2780 $('.funnel__single-list.list-header .bulk-action-wrapper .selected-funnel-count').text(
2781 totalSelectedFunnel + ' Funnels',
2782 )
2783 } else {
2784 $('.funnel__single-list.list-header .bulk-action-wrapper .selected-funnel-count').text(
2785 totalSelectedFunnel + ' Funnel',
2786 )
2787 }
2788 }
2789
2790 $('.funnel__single-list.list-body input[name=funnel-list-select]').on('change', function () {
2791 $('.funnel-list__bulk-select.select-all-funnels input[name=funnel-list__bulk-select]').prop(
2792 'checked',
2793 false,
2794 )
2795 selectedFunnelCounter()
2796 })
2797
2798 $('.funnel-list__bulk-select.select-all-funnels input[name=funnel-list__bulk-select]').on(
2799 'change',
2800 function () {
2801 if ($(this).is(':checked')) {
2802 $('.funnel__single-list.list-body input[name=funnel-list-select]').prop(
2803 'checked',
2804 true,
2805 )
2806 selectedFunnelCounter()
2807 } else {
2808 $('.funnel__single-list.list-header .bulk-action-wrapper').css('display', 'none')
2809 $('.funnel__single-list.list-body input[name=funnel-list-select]').prop(
2810 'checked',
2811 false,
2812 )
2813 }
2814 },
2815 )
2816
2817 /**
2818 * add new step option dropdown show/hide.
2819 *
2820 */
2821 $(document).on('click', '.addstep .add-step-wrapper .icon', function (e) {
2822 e.stopPropagation()
2823 $(this).parent('.add-step-wrapper').toggleClass('show-options')
2824 })
2825
2826 $(document).on('click', '.option-duplicate', function (e) {
2827 e.stopPropagation()
2828 })
2829
2830 $(document).on('click', 'body', function () {
2831 $('.addstep .add-step-wrapper').removeClass('show-options')
2832 })
2833
2834 /**
2835 * Showmore option hide/show
2836 * Three dot more option hide/show.
2837 *
2838 */
2839 $(document).on('click', '.on-showmore-options', function (e) {
2840 e.stopPropagation()
2841 $(this).toggleClass('show-dropdown')
2842 })
2843 $(document).on('click', 'body', function () {
2844 $('.on-showmore-options').removeClass('show-dropdown')
2845 })
2846
2847 /*----mailmint actions dropdown------ */
2848 $(document).on('click', '.mailmint-automation .add-action > button', function (e) {
2849 e.stopPropagation()
2850
2851 $(this).parents('.logical-decision-box').siblings('.add-action').removeClass('show-actions')
2852 $(this).parents('.single-decision').find('.add-action').removeClass('show-actions')
2853 $(this)
2854 .parents('.single-decision')
2855 .siblings()
2856 .find('.add-action')
2857 .removeClass('show-actions')
2858
2859 $(this)
2860 .parents('.automation-single-step')
2861 .siblings()
2862 .find('.add-action')
2863 .removeClass('show-actions')
2864
2865 $(this).parents('.add-action').toggleClass('show-actions')
2866 })
2867
2868 $(document).on('click', '.mailmint-automation .mailmint-actions', function (e) {
2869 e.stopPropagation()
2870 })
2871
2872 $(document).on('click', 'body, .mailmint-single-action, .automation-start-point', function (e) {
2873 $('.mailmint-automation .add-action').removeClass('show-actions')
2874 })
2875
2876 //----when click first-action plus (+) button------
2877 $(document).on('click', '.mailmint-automation .add-action.first-action > button', function (e) {
2878 $('.automation-single-step .add-action').removeClass('show-actions')
2879 })
2880
2881 //----when click automation-single-step's plus (+) button------
2882 $(document).on('click', '.automation-single-step .add-action > button', function (e) {
2883 $('.selected-trigger .add-action').removeClass('show-actions')
2884 //$('.logical-decision-box .add-action').removeClass('show-actions');
2885 })
2886
2887 //--------select box placeholder color and active color--------
2888 $(document).on('change', 'select.has-placeholder-color', function () {
2889 var thisVal = $(this).find(':selected').val()
2890 if ('' != thisVal) {
2891 $(this).addClass('value-selected')
2892 } else {
2893 $(this).removeClass('value-selected')
2894 }
2895 })
2896
2897 $(document).on('click', '.add-new-webhook', function () {
2898 $('select.has-placeholder-color').removeClass('value-selected')
2899 })
2900
2901 /*----A|B testing modal header's more option's dropdown show/hide------ */
2902 $(document).on('click', '.ab-testing-drawer .header-right .more-options', function (e) {
2903 e.stopPropagation()
2904 $(this).toggleClass('show-options')
2905 })
2906
2907 $(document).on('click', 'body', function () {
2908 $('.ab-testing-drawer .header-right .more-options').removeClass('show-options')
2909 })
2910
2911 /*----A|B testing variations steps more option's dropdown show/hide------ */
2912 $(document).on('click', '.single-ab-step .more-option > button', function (e) {
2913 e.stopPropagation()
2914 $(this)
2915 .parents('.single-ab-step')
2916 .siblings()
2917 .find('.more-option')
2918 .removeClass('show-dorpdown')
2919 $(this).parents('li.more-option').toggleClass('show-dorpdown')
2920 })
2921
2922 $(document).on('click', '.single-ab-step .more-option .options-dropdown', function (e) {
2923 e.stopPropagation()
2924 })
2925
2926 $(document).on('click', 'body', function () {
2927 $('.ab-testing-drawer .single-ab-step li.more-option').removeClass('show-dorpdown')
2928 })
2929
2930 /**
2931 * wpfnl custom selectbox dropdown option hide/show
2932 *
2933 */
2934 $(document).on('click', '.wpfnl-selectbox .selected-option', function (e) {
2935 e.stopPropagation()
2936
2937 $(this)
2938 .parents('.single-rules')
2939 .siblings()
2940 .find('.wpfnl-selectbox')
2941 .removeClass('show-options')
2942 $(this).parents('.rules').siblings().find('.wpfnl-selectbox').removeClass('show-options')
2943
2944 $(this)
2945 .parents('.condition-single-row')
2946 .siblings()
2947 .find('.wpfnl-selectbox')
2948 .removeClass('show-options')
2949 $(this)
2950 .parents('.single-condition')
2951 .siblings()
2952 .find('.wpfnl-selectbox')
2953 .removeClass('show-options')
2954
2955 $(this).parent('.wpfnl-selectbox').toggleClass('show-options')
2956 })
2957 $(document).on('click', 'body', function () {
2958 $('.wpfnl-selectbox').removeClass('show-options')
2959 })
2960
2961 /**
2962 * wpfnl custom selectbox sub dropdown option hide/show
2963 *
2964 */
2965 $(document).on('click', '.single-rules .selectable-options > li', function (e) {
2966 e.stopPropagation()
2967
2968 $(this)
2969 .parents('.single-rules')
2970 .siblings()
2971 .find('.selectable-options > li')
2972 .removeClass('show-options')
2973 $(this)
2974 .parents('.rules')
2975 .siblings()
2976 .find('.selectable-options > li')
2977 .removeClass('show-options')
2978 $(this).siblings().removeClass('show-options')
2979
2980 $(this).toggleClass('show-options')
2981 })
2982 $(document).on('click', 'body', function () {
2983 $('.single-rules .wpfnl-selectbox').removeClass('show-options')
2984 $('.single-rules .selectable-options > li').removeClass('show-options')
2985 })
2986
2987 $(document).on(
2988 'click',
2989 '.single-rules .submenu > li, .rules-is .selectable-options > li',
2990 function () {
2991 $('.single-rules .wpfnl-selectbox').removeClass('show-options')
2992 },
2993 )
2994
2995 //---------------------------
2996 $(document).on('click', '.single-rules .selected-option', function (e) {
2997 $('.single-rules .wpfnl-custom-selectbox').removeClass('show-options')
2998 })
2999
3000 $(document).on('click', '.wpfnl-custom-selectbox .selectbox-selected-value', function (e) {
3001 $('.single-rules .wpfnl-selectbox ').removeClass('show-options')
3002 $(this)
3003 .parents('.single-rules')
3004 .siblings()
3005 .find('.wpfnl-custom-selectbox')
3006 .removeClass('show-options')
3007 })
3008
3009 // ------------------ Pro Modal Open and Close ---------------------- //
3010
3011 // close modal starts
3012 $(document).on('click', '#wpfnl-pro-modal-close', function (e) {
3013 const html = '<strong>Small</strong> <span>License for 1 site</span>';
3014 $('#pro-modal-package-type').html(html)
3015 $('.wpfnl-footer-btn-wrapper .btn-default.confirmed').attr('href', 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/');
3016 $('#wpfnl-pro-modal').hide()
3017 })
3018
3019 $(document).on('click', '#wpfnl-pro-modal-close-btn', function (e) {
3020 const html = '<strong>Small</strong> <span>License for 1 site</span>';
3021 $('#pro-modal-package-type').html(html)
3022 $('.wpfnl-footer-btn-wrapper .btn-default.confirmed').attr('href', 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/');
3023 $('#wpfnl-pro-modal').hide()
3024 })
3025 // close modal ends
3026
3027 /* Configure the pro modal
3028 * config[object] - parameter
3029 * showSubHeading - boolean
3030 * subHeading - string
3031 * confirmLink - string
3032 * features - Array of Object
3033 * label - String
3034 * value - String
3035 */
3036 const configureProModal = (config) => {
3037 const { showSubHeading, subHeading, confirmLink, features } = config
3038
3039 // Define Ratings and Users
3040 const ratings = 105
3041 const users = 8000
3042
3043 // Define Elements
3044 const modalElement = document.querySelector('#wpfnl-pro-modal')
3045 const subHeadingElement = document.querySelector('#wpfnl-pro-modal .wpfnl-pro-sub-heading')
3046 const confirmBtnElement = document.querySelector('#wpfnl-pro-modal .btn-default.confirmed')
3047 const modalBodyElement = document.querySelector('#wpfnl-pro-modal .wpfnl-pro-modal-body')
3048 const featureFirstColElement = document.querySelector(
3049 '#wpfnl-pro-modal .wpfnl-pro-modal-body .wpfnl-pro-features.first-col',
3050 )
3051 const featureSecondColElement = document.querySelector(
3052 '#wpfnl-pro-modal .wpfnl-pro-modal-body .wpfnl-pro-features.second-col',
3053 )
3054 const footerTextElement = document.querySelector(
3055 '#wpfnl-pro-modal .wpfnl-pro-modal-footer-text span',
3056 )
3057
3058 // Tic Icon for Features
3059 const ticIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1.45455 6.23252C1.17901 6.23329 0.909321 6.31206 0.676682 6.45971C0.444044 6.60736 0.257963 6.81786 0.139966 7.06685C0.0219701 7.31585 -0.0231188 7.59316 0.00991618 7.86671C0.0429511 8.14026 0.15276 8.39887 0.326638 8.61261L4.03332 13.1533C4.16548 13.3174 4.33489 13.4476 4.52748 13.5331C4.72006 13.6186 4.93026 13.6569 5.14063 13.6448C5.59054 13.6206 5.99673 13.38 6.2557 12.9842L13.9554 0.583858C13.9567 0.581801 13.958 0.579744 13.9593 0.577717C14.0316 0.46679 14.0082 0.246962 13.859 0.108864C13.8181 0.0709399 13.7698 0.0418041 13.7171 0.0232503C13.6645 0.00469649 13.6086 -0.00288247 13.5529 0.000980338C13.4972 0.00484315 13.4429 0.020066 13.3933 0.0457111C13.3437 0.0713562 13.2999 0.106881 13.2646 0.150097C13.2618 0.153494 13.259 0.156841 13.2561 0.160136L5.49078 8.93373C5.46124 8.96712 5.42535 8.9943 5.38521 9.0137C5.34507 9.0331 5.30147 9.04433 5.25695 9.04674C5.21243 9.04915 5.16788 9.04268 5.12588 9.02773C5.08388 9.01277 5.04527 8.98962 5.01229 8.95961L2.43514 6.61439C2.16749 6.36903 1.81765 6.23279 1.45455 6.23252Z" fill="#2FCF5C"></path></svg>`
3060
3061 // Show or hide subheading
3062 if (showSubHeading) {
3063 subHeadingElement.innerHTML = subHeading
3064 } else {
3065 modalElement.removeChild(subHeadingElement)
3066 }
3067
3068 // confirm link setting
3069 if (confirmLink) {
3070 confirmBtnElement.setAttribute('href', confirmLink)
3071 } else {
3072 confirmBtnElement.setAttribute('href', 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/')
3073 }
3074
3075 // features setting
3076 if (Array.isArray(features) && features?.length > 0) {
3077 let middle = Math.ceil(features.length / 2)
3078 featureFirstColElement.innerHTML = ''
3079 featureSecondColElement.innerHTML = ''
3080
3081 features.forEach((feature, index) => {
3082 if (index < middle) {
3083 featureFirstColElement.innerHTML += `<li>${ticIcon}<span>${feature.label}</span></li>`
3084 } else {
3085 featureSecondColElement.innerHTML += `<li>${ticIcon}<span>${feature.label}</span></li>`
3086 }
3087 })
3088 } else {
3089 modalElement.removeChild(modalBodyElement)
3090 }
3091
3092 // Set Footer Text
3093 if (footerTextElement)
3094 footerTextElement.innerHTML = `Easiest Funnel Builder: <strong>${users}+</strong> Users, <strong>${ratings}+</strong> Five-Star Reviews</strong>`
3095 }
3096
3097 // modal Open function
3098 const openModal = (config) => {
3099 // configureProModal(config)
3100 $('#wpfnl-pro-modal').css('display', 'flex')
3101 }
3102 // open modal starts
3103 $(document).on('click', '#wpfnl-export-all-pro', function (e) {
3104 const config = {
3105 showSubHeading: true,
3106 subHeading: 'Upgrade to Export Funnels.',
3107 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3108 features: [
3109 {
3110 label: 'Export Funnels',
3111 value: 'export_funnels',
3112 },
3113 {
3114 label: 'Download Funnel as JSON',
3115 value: 'download_funnel_as_json',
3116 },
3117 {
3118 label: 'Export Single Funnel',
3119 value: 'export_single_funnels',
3120 },
3121 {
3122 label: 'Bulk Export',
3123 value: 'bulk_export',
3124 },
3125 ],
3126 }
3127 openModal(config)
3128 })
3129
3130 $(document).on('click', '#wpfnl-import-funnels-pro, .pro-import-button', function (e) {
3131 const config = {
3132 showSubHeading: true,
3133 subHeading: 'Upgrade to Import Funnels.',
3134 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3135 features: [
3136
3137 {
3138 label: 'Import JSON File',
3139 value: 'import_json_to_create_funnel',
3140 },
3141 {
3142 label: 'Import Funnels',
3143 value: 'import_funnels',
3144 },
3145 {
3146 label: 'Bulk Import',
3147 value: 'bulk_import_funnels',
3148 },
3149 ],
3150 }
3151 openModal(config)
3152 })
3153
3154 $(document).on('click', '#wpfnl-offer-settings', function (e) {
3155 const config = {
3156 showSubHeading: true,
3157 subHeading: 'Upgrade to Unlock Offer Settings.',
3158 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3159 features: [
3160 {
3161 label: 'Create Child Order',
3162 value: 'create_child_order',
3163 },
3164 {
3165 label: 'Show Supported Payment Gateway',
3166 value: 'show_supported_payment_gateway',
3167 },
3168 {
3169 label: 'Skip Offer',
3170 value: 'skip_offer',
3171 },
3172 ],
3173 }
3174 openModal(config)
3175 })
3176
3177 $('.duplicate.wpfnl-export-funnel-pro').on('click', function (e) {
3178 const config = {
3179 showSubHeading: true,
3180 subHeading: 'Upgrade to Export Funnels.',
3181 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3182 features: [
3183 {
3184 label: 'Export Funnels',
3185 value: 'export_funnels',
3186 },
3187 {
3188 label: 'Download Funnel as JSON',
3189 value: 'download_funnel_as_json',
3190 },
3191 {
3192 label: 'Export Single Funnel',
3193 value: 'export_single_funnels',
3194 },
3195 {
3196 label: 'Bulk Export',
3197 value: 'bulk_export',
3198 },
3199 ],
3200 }
3201 openModal(config)
3202 })
3203
3204 $('#facebook-pixel-enable-pro').on('click', function (e) {
3205 const config = {
3206 showSubHeading: true,
3207 subHeading:
3208 'This feature is only available in the Pro version. Upgrade Now to continue all these awesome features',
3209 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3210 features: [
3211 {
3212 label: 'Unlimited Contacts k',
3213 value: 'unlimited_contacts',
3214 },
3215 {
3216 label: 'Conditional Prancing k',
3217 value: 'conditional_prancing',
3218 },
3219 {
3220 label: '360 Contacts view',
3221 value: '360_contacts_view',
3222 },
3223 {
3224 label: 'Connect with From Plugins',
3225 value: 'Connect_with_From_Plugins',
3226 },
3227 {
3228 label: 'Over 60+ Integrations',
3229 value: 'Over_60+_Integrations',
3230 },
3231 ],
3232 }
3233 openModal(config)
3234 })
3235
3236 $(document).on('click', '#facebook-pixel-enable-pro', function (e) {
3237 e.preventDefault()
3238 e.target.checked = false
3239 const config = {
3240 showSubHeading: true,
3241 subHeading: 'Upgrade to Pro for FB Pixel Tracking.',
3242 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3243 features: [
3244 {
3245 label: 'FB Pixel Tracking',
3246 value: 'fb_pixel_tracking',
3247 },
3248 {
3249 label: 'Enable/Disable for Single Funnel',
3250 value: 'enable_disable_single_funnel',
3251 },
3252 {
3253 label: 'Purchase Event Tracking',
3254 value: 'purchase_event_tracking',
3255 },
3256 {
3257 label: 'Page View Tracking',
3258 value: 'page_view_tracking',
3259 },
3260 {
3261 label: 'Add to Cart Tracking',
3262 value: 'add_to_cart_tracking',
3263 },
3264 {
3265 label: 'Upsell/Downsell Tracking',
3266 value: 'offer_tracking',
3267 },
3268 ],
3269 }
3270 openModal(config)
3271 })
3272
3273 $(document).on('click', '#gtm-enable-pro', function (e) {
3274 e.preventDefault()
3275 e.target.checked = false
3276 const config = {
3277 showSubHeading: true,
3278 subHeading: 'Upgrade to Pro for GTM Tracking.',
3279 confirmLink: 'https://useraccount.getwpfunnels.com/wpf-small-annual-brand-new/steps/wpf-sa-checkout/',
3280 features: [
3281 {
3282 label: 'GTM Tracking',
3283 value: 'gtm_tracking',
3284 },
3285 {
3286 label: 'Enable/Disable for Single Funnel',
3287 value: 'enable_disable_single_funnel',
3288 },
3289 {
3290 label: 'Purchase Event Tracking',
3291 value: 'purchase_event_tracking',
3292 },
3293 {
3294 label: 'Page View Tracking',
3295 value: 'page_view_tracking',
3296 },
3297 {
3298 label: 'Add to Cart Tracking',
3299 value: 'add_to_cart_tracking',
3300 },
3301 {
3302 label: 'Shipping Info Tracking',
3303 value: 'shipping_tracking',
3304 },
3305 {
3306 label: 'OrderBump Tracking',
3307 value: 'orderbump_tracking',
3308 },
3309 {
3310 label: 'Upsell/Downsell Tracking',
3311 value: 'offer_tracking',
3312 },
3313 ],
3314 }
3315 openModal(config)
3316 })
3317
3318 // open modal ends
3319
3320 // Close Toaster
3321 $(document).on('click', '#wpfnl-toaster-close-btn', function (e) {
3322 $('#wpfnl-toaster-wrapper').hide()
3323 })
3324
3325 // Pro modal
3326 $(document).on('click', '#pro-modal-dropdown-btn', function () {
3327 $('#pro-modal-dropdown-body').toggleClass('show-dropdown')
3328 $('#pro-modal-dropdown-btn').toggleClass('btn-rotate')
3329 })
3330
3331 $(document).on('click', '.wpfnl-pro-modal-dropdown li', function () {
3332 const selectedValue = $(this).attr('value')
3333 const url = $(this).data('url')
3334 const selectedHTML = $(this).html()
3335
3336 $('#pro-modal-package-type').html(selectedHTML)
3337 $('#pro-modal-package-price').html(`<strong>$ ${selectedValue}</strong> <span>/year</span>`)
3338 $('.wpfnl-footer-btn-wrapper .btn-default.confirmed').attr('href', url);
3339 $('#pro-modal-dropdown-body').toggleClass('show-dropdown')
3340 $('#pro-modal-dropdown-btn').toggleClass('btn-rotate')
3341 })
3342
3343
3344 // no funnels screen video popup
3345 $(document).on('click', '.no-funnel-play-button', function () {
3346 const $popup = $('#no-funnel-video-popup');
3347 const $iframe = $('#no-funnel-video-iframe');
3348 const videoSrc = $iframe.data('src');
3349
3350 // Set the iframe src to start video with autoplay
3351 if (videoSrc && !$iframe.attr('src')) {
3352 $iframe.attr('src', videoSrc);
3353 }
3354
3355 $popup.addClass('show');
3356 $('body').css('overflow', 'hidden');
3357 })
3358
3359 $(document).on('click', '#no-funnel-video-popup .video-popup-close, #no-funnel-video-popup', function (e) {
3360 // Only close if clicking the close button or overlay (not the content)
3361 if ($(e.target).is('#no-funnel-video-popup') || $(e.target).closest('.video-popup-close').length) {
3362 const $popup = $('#no-funnel-video-popup');
3363 const $iframe = $('#no-funnel-video-iframe');
3364
3365 // Remove src to stop the video
3366 $iframe.attr('src', '');
3367
3368 $popup.removeClass('show');
3369 $('body').css('overflow', '');
3370 }
3371 })
3372
3373 })(jQuery)
3374