_agents.js
1 year ago
_calendar.js
3 months ago
_chart.js
9 months ago
_customers.js
1 year ago
_customers_import.js
9 months ago
_delete-confirm.js
1 week ago
_orders.js
9 months ago
_processes.js
1 year ago
_razorpay_connect.js
1 month ago
_steps.js
9 months ago
_stripe_connect.js
1 year ago
main.js
2 weeks ago
updates.js
3 months ago
_delete-confirm.js
119 lines
| 1 | /* |
| 2 | * Copyright (c) 2024 LatePoint LLC. All rights reserved. |
| 3 | */ |
| 4 | |
| 5 | /* |
| 6 | * The single "type delete to confirm" modal for the whole plugin. One modal, one set of |
| 7 | * os-delete-confirm-* classes, used for both: |
| 8 | * |
| 9 | * 1. Single-record delete — add the class os-delete-confirm to a normal data-os-action button that |
| 10 | * has data-os-prompt (services now, any tab later). Optional data-os-confirm-title sets the modal |
| 11 | * heading; the data-os-prompt text is the body. The gate in bin/actions.js calls |
| 12 | * latepoint_delete_confirm_show($trigger); on confirm the button's own data-os-action flow runs. |
| 13 | * |
| 14 | * 2. Bulk delete (e.g. appointments) — call it programmatically with an options object: |
| 15 | * latepoint_delete_confirm_show({ title: '...', body: '...', onConfirm: function(){ ... } }); |
| 16 | * and run the bulk request inside onConfirm. |
| 17 | * |
| 18 | * Shared strings (prompt template, confirm word, buttons) come from the single |
| 19 | * latepoint_delete_confirm_i18n localized object. |
| 20 | */ |
| 21 | |
| 22 | function latepoint_delete_confirm_show(arg){ |
| 23 | var i18n = (typeof latepoint_delete_confirm_i18n !== 'undefined') ? latepoint_delete_confirm_i18n : {}; |
| 24 | var confirm_word = i18n.modal_confirm_word || 'delete'; |
| 25 | var title, body, onConfirm; |
| 26 | |
| 27 | if(arg && arg.jquery){ |
| 28 | // Single delete: a .os-delete-confirm data-os-action button. Heading comes from the optional |
| 29 | // data-os-confirm-title; the body is the button's existing data-os-prompt message. On confirm, |
| 30 | // re-fire its click with os-delete-approved set so the gate in bin/actions.js skips the modal and runs |
| 31 | // its normal data-os-action flow. |
| 32 | var $trigger = arg; |
| 33 | title = $trigger.data('os-confirm-title') || ''; |
| 34 | body = $trigger.data('os-prompt') || ''; |
| 35 | onConfirm = function(){ $trigger.data('os-delete-approved', true).trigger('click'); }; |
| 36 | } else { |
| 37 | // Programmatic caller (e.g. appointments bulk delete): supplies its own title/body + confirm callback. |
| 38 | arg = arg || {}; |
| 39 | title = arg.title || ''; |
| 40 | body = arg.body || ''; |
| 41 | onConfirm = (typeof arg.onConfirm === 'function') ? arg.onConfirm : function(){}; |
| 42 | } |
| 43 | |
| 44 | // Build the modal via jQuery DOM methods so every user/translator supplied string is assigned via |
| 45 | // .text()/.attr() (jQuery escapes it) — no risk of attribute break-out or HTML injection. |
| 46 | var $modal = jQuery('<div class="os-delete-confirm-modal" />').attr('data-confirm-word', confirm_word); |
| 47 | $modal.append('<div class="os-delete-confirm-icon"><i class="latepoint-icon latepoint-icon-trash-2"></i></div>'); |
| 48 | if(title) $modal.append(jQuery('<h3 class="os-delete-confirm-title" />').text(title)); |
| 49 | if(body) $modal.append(jQuery('<p class="os-delete-confirm-body" />').text(body)); |
| 50 | |
| 51 | $modal.append( |
| 52 | jQuery('<input type="text" class="os-delete-confirm-input" autocomplete="off" spellcheck="false" />') |
| 53 | .attr('placeholder', i18n.modal_input_placeholder || '') |
| 54 | ); |
| 55 | |
| 56 | var $actions = jQuery('<div class="os-delete-confirm-actions" />'); |
| 57 | $actions.append( |
| 58 | jQuery('<a href="#" class="latepoint-btn latepoint-btn-grey latepoint-btn-outline os-delete-confirm-cancel" />') |
| 59 | .append(jQuery('<span />').text(i18n.modal_cancel || '')) |
| 60 | ); |
| 61 | $actions.append( |
| 62 | jQuery('<a href="#" class="latepoint-btn latepoint-btn-danger os-delete-confirm-go is-disabled" />') |
| 63 | .attr('aria-disabled', 'true') |
| 64 | .append(jQuery('<span />').text(i18n.modal_confirm || '')) |
| 65 | ); |
| 66 | $modal.append($actions); |
| 67 | |
| 68 | latepoint_show_data_in_lightbox($modal[0].outerHTML, 'width-500 os-delete-confirm-lightbox', true); |
| 69 | |
| 70 | // latepoint_show_data_in_lightbox appends the lightbox synchronously, so the modal is already in the |
| 71 | // DOM — store the confirm callback and focus the input without a fragile setTimeout. |
| 72 | var $live = jQuery('.os-delete-confirm-lightbox .os-delete-confirm-modal'); |
| 73 | $live.data('onConfirm', onConfirm); |
| 74 | $live.find('.os-delete-confirm-input').trigger('focus'); |
| 75 | } |
| 76 | |
| 77 | function latepoint_delete_confirm_run($go){ |
| 78 | var onConfirm = $go.closest('.os-delete-confirm-modal').data('onConfirm'); |
| 79 | latepoint_lightbox_close(); |
| 80 | if(typeof onConfirm === 'function') onConfirm(); |
| 81 | } |
| 82 | |
| 83 | function latepoint_init_delete_confirm(){ |
| 84 | var $body = jQuery('body'); |
| 85 | if($body.data('os-delete-confirm-bound')) return; |
| 86 | $body.data('os-delete-confirm-bound', true); |
| 87 | |
| 88 | $body.on('input keyup paste', '.os-delete-confirm-input', function(){ |
| 89 | var $modal = jQuery(this).closest('.os-delete-confirm-modal'); |
| 90 | var required = String($modal.data('confirm-word') || 'delete').toLowerCase(); |
| 91 | var typed = String(jQuery(this).val() || '').trim().toLowerCase(); |
| 92 | var $go = $modal.find('.os-delete-confirm-go'); |
| 93 | if(typed === required){ |
| 94 | $go.removeClass('is-disabled').attr('aria-disabled', 'false'); |
| 95 | } else { |
| 96 | $go.addClass('is-disabled').attr('aria-disabled', 'true'); |
| 97 | } |
| 98 | }); |
| 99 | |
| 100 | $body.on('keydown', '.os-delete-confirm-input', function(e){ |
| 101 | if(e.which !== 13) return; |
| 102 | e.preventDefault(); |
| 103 | var $go = jQuery(this).closest('.os-delete-confirm-modal').find('.os-delete-confirm-go'); |
| 104 | if(!$go.hasClass('is-disabled')) $go.trigger('click'); |
| 105 | }); |
| 106 | |
| 107 | $body.on('click', '.os-delete-confirm-cancel', function(e){ |
| 108 | e.preventDefault(); |
| 109 | latepoint_lightbox_close(); |
| 110 | }); |
| 111 | |
| 112 | $body.on('click', '.os-delete-confirm-go', function(e){ |
| 113 | e.preventDefault(); |
| 114 | var $this = jQuery(this); |
| 115 | if($this.hasClass('is-disabled') || $this.hasClass('os-loading')) return; |
| 116 | latepoint_delete_confirm_run($this); |
| 117 | }); |
| 118 | } |
| 119 |