PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / assets / js / admin / charitable-admin-addons.js

charitable-admin-addons.js in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at assets/js/admin/charitable-admin-addons.js

317 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Charitable Admin Addons functionality.
3 *
4 * @package Charitable/Admin Scripts
5 * @author David Bisset
6 * @copyright Copyright (c) 2024, WP Charitable LLC
7 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8 * @since 1.8.7.6
9 * @version 1.8.7.6
10 */
11
12 ( function( $ ) {
13 'use strict';
14
15 // Global settings access.
16 var s;
17
18 // Charitable Admin Addons object.
19 var CharitableAdminAddons = {
20
21 // Settings.
22 settings: {
23 iconActivate: '<i class="fa fa-toggle-on fa-flip-horizontal" aria-hidden="true"></i>',
24 iconDeactivate: '<i class="fa fa-toggle-on" aria-hidden="true"></i>',
25 iconInstall: '<i class="fa fa-cloud-download" aria-hidden="true"></i>',
26 iconSpinner: '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>',
27 },
28
29 /**
30 * Start the engine.
31 *
32 * @since 1.8.7.6
33 */
34 init: function() {
35
36 // Settings shortcut.
37 s = this.settings;
38
39 // Document ready.
40 $( CharitableAdminAddons.ready );
41 },
42
43 /**
44 * Document ready.
45 *
46 * @since 1.8.7.6
47 */
48 ready: function() {
49
50 // Only run on the addons page.
51 if ( ! $( '#charitable-admin-addons' ).length ) {
52 return;
53 }
54
55 // Addon button clicks.
56 $( document ).on( 'click', '#charitable-admin-addons .action-button button', CharitableAdminAddons.handleAddonAction );
57 },
58
59 /**
60 * Handle addon action button clicks.
61 *
62 * @since 1.8.7.6
63 */
64 handleAddonAction: function( e ) {
65 e.preventDefault();
66
67 var $btn = $( this );
68 var $footer = $btn.parents( '.addon-item' );
69 var classes = {
70 active: 'status-active',
71 activating: 'status-activating',
72 incompatible: 'status-incompatible',
73 installed: 'status-installed',
74 missing: 'status-missing',
75 goToUrl: 'status-go-to-url',
76 withError: 'status-with-error',
77 };
78
79 // Open url in new tab.
80 if ( $footer.hasClass( classes.goToUrl ) ) {
81 window.open( $btn.attr( 'data-plugin' ), '_blank' );
82 return;
83 }
84
85 $btn.prop( 'disabled', true );
86
87 var checked = $btn.is( ':checked' );
88 var cssClass;
89 var plugin = $btn.attr( 'data-plugin' );
90 var pluginType = $btn.attr( 'data-type' );
91 var $addon = $btn.parents( '.addon-item' );
92 var state = CharitableAdminAddons.getAddonState( $footer, classes, $btn );
93
94 // Update button state.
95 CharitableAdminAddons.updateAddonButton( $btn, state, true );
96
97 // Make AJAX call.
98 CharitableAdminAddons.setAddonState( plugin, state, pluginType, function( res ) {
99 CharitableAdminAddons.handleAddonStateResponse( res, $addon, $btn, state, pluginType, cssClass );
100 }, function( xhr ) {
101 CharitableAdminAddons.handleAddonStateError( xhr, $addon, $btn, state );
102 } );
103 },
104
105 /**
106 * Get addon state based on current classes and button state.
107 *
108 * @since 1.8.7.6
109 */
110 getAddonState: function( $footer, classes, $btn ) {
111 // Prefer footer-level state when present.
112 if ( $footer.hasClass( classes.missing ) ) {
113 return 'install';
114 }
115 if ( $footer.hasClass( classes.installed ) ) {
116 return 'activate';
117 }
118 if ( $footer.hasClass( classes.active ) ) {
119 return 'deactivate';
120 }
121 if ( $footer.hasClass( classes.incompatible ) ) {
122 return 'incompatible';
123 }
124
125 // Fallback to button classes when footer has no state classes.
126 if ( $btn.hasClass( 'status-missing' ) ) {
127 return 'install';
128 }
129 if ( $btn.hasClass( 'status-installed' ) ) {
130 return 'activate';
131 }
132 if ( $btn.hasClass( 'status-active' ) ) {
133 return 'deactivate';
134 }
135
136 return 'install';
137 },
138
139 /**
140 * Update addon button state.
141 *
142 * @since 1.8.7.6
143 */
144 updateAddonButton: function( $btn, state, loading ) {
145 var text = '';
146 var cssClass = '';
147
148 if ( loading ) {
149 if ( state === 'install' ) {
150 text = s.iconSpinner + ' Installing...';
151 } else if ( state === 'deactivate' ) {
152 text = s.iconSpinner + ' Deactivating...';
153 } else {
154 text = s.iconSpinner + ' Activating...';
155 }
156 cssClass = 'button button-secondary loading';
157 } else {
158 switch ( state ) {
159 case 'install':
160 text = s.iconInstall + ' Install Plugin';
161 cssClass = 'status-missing button button-primary';
162 break;
163 case 'activate':
164 text = s.iconActivate + ' Activate';
165 cssClass = 'status-installed button button-secondary';
166 break;
167 case 'deactivate':
168 text = s.iconDeactivate + ' Deactivate';
169 cssClass = 'status-active button button-secondary';
170 break;
171 case 'incompatible':
172 text = 'Incompatible';
173 cssClass = 'status-incompatible button button-secondary disabled';
174 break;
175 }
176 }
177
178 $btn.removeClass().addClass( cssClass ).html( text );
179 },
180
181 /**
182 * Set addon state via AJAX.
183 *
184 * @since 1.8.7.6
185 */
186 setAddonState: function( plugin, state, pluginType, callback, errorCallback ) {
187 var actions = {
188 activate: 'charitable_addons_activate',
189 install: 'charitable_addons_install_wporg',
190 deactivate: 'charitable_addons_deactivate',
191 incompatible: 'charitable_addons_activate',
192 };
193 var action = actions[ state ];
194
195 if ( ! action ) {
196 return;
197 }
198
199 var data = {
200 action: action,
201 nonce: charitable_admin_addons.nonce,
202 plugin: plugin,
203 type: pluginType,
204 };
205
206 $.post( charitable_admin_addons.ajax_url, data, function( res ) {
207 callback( res );
208 } ).fail( function( xhr ) {
209 errorCallback( xhr );
210 } );
211 },
212
213 /**
214 * Handle successful addon state response.
215 *
216 * @since 1.8.7.6
217 */
218 handleAddonStateResponse: function( res, $addon, $btn, state, pluginType, cssClass ) {
219 $btn.prop( 'disabled', false );
220 $btn.removeClass( 'loading' );
221
222 if ( res.success ) {
223
224 // Server may include a `redirect` URL when the just-completed action
225 // should navigate the admin somewhere new (e.g. installing/activating
226 // Charitable Pro auto-deactivates Lite, so we send the user to the
227 // Charitable dashboard rather than letting them land on a now-missing
228 // admin screen).
229 if ( res.data && 'object' === typeof res.data && res.data.redirect ) {
230 window.location.href = res.data.redirect;
231 return;
232 }
233
234 var successText = '';
235 var stateText = '';
236 var buttonText = '';
237
238 if ( 'install' === state ) {
239 $btn.attr( 'data-plugin', res.data.basename );
240 successText = res.data.msg;
241 if ( ! res.data.is_activated ) {
242 stateText = 'Inactive';
243 buttonText = 'plugin' === pluginType ? 'Activate' : s.iconActivate + ' Activate';
244 cssClass = 'plugin' === pluginType ? 'status-installed button button-secondary' : 'status-installed';
245 }
246 } else {
247 successText = ( res.data && 'object' === typeof res.data && res.data.msg ) ? res.data.msg : res.data;
248 // Reflect new state in UI.
249 if ( state === 'activate' ) {
250 stateText = 'Active';
251 buttonText = pluginType === 'plugin' ? 'Deactivate' : s.iconDeactivate + ' Deactivate';
252 cssClass = pluginType === 'plugin' ? 'status-active button button-secondary' : 'status-active';
253 } else if ( state === 'deactivate' ) {
254 stateText = 'Inactive';
255 buttonText = pluginType === 'plugin' ? 'Activate' : s.iconActivate + ' Activate';
256 cssClass = pluginType === 'plugin' ? 'status-installed button button-secondary' : 'status-installed';
257 }
258 }
259
260 $addon.find( '.actions' ).append( '<div class="msg success">' + successText + '</div>' );
261 $addon.find( 'span.status-label' )
262 .removeClass( 'status-active status-installed status-missing' )
263 .addClass( cssClass )
264 .removeClass( 'button button-primary button-secondary disabled' )
265 .text( stateText );
266 $btn
267 .removeClass( 'status-active status-installed status-missing' )
268 .removeClass( 'button button-primary button-secondary disabled loading' )
269 .addClass( cssClass ).html( buttonText );
270 } else {
271 if ( 'object' === typeof res.data ) {
272 if ( pluginType === 'addon' ) {
273 $addon.find( '.actions' ).append( '<div class="msg error"><p>Error installing addon</p></div>' );
274 } else {
275 $addon.find( '.actions' ).append( '<div class="msg error"><p>' + res.data + '</p></div>' );
276 }
277 } else {
278 $addon.find( '.actions' ).append( '<div class="msg error"><p>' + res.data + '</p></div>' );
279 }
280 $btn.removeClass( 'loading' );
281 CharitableAdminAddons.updateAddonButton( $btn, state, false );
282 }
283
284 // Remove success/error messages after 3 seconds.
285 setTimeout( function() {
286 $addon.find( '.msg' ).fadeOut( 300, function() {
287 $( this ).remove();
288 } );
289 }, 3000 );
290 },
291
292 /**
293 * Handle addon state error.
294 *
295 * @since 1.8.7.6
296 */
297 handleAddonStateError: function( xhr, $addon, $btn, state ) {
298 $btn.prop( 'disabled', false );
299 $addon.find( '.actions' ).append( '<div class="msg error"><p>Network error. Please try again.</p></div>' );
300 CharitableAdminAddons.updateAddonButton( $btn, state, false );
301
302 // Remove error message after 3 seconds.
303 setTimeout( function() {
304 $addon.find( '.msg' ).fadeOut( 300, function() {
305 $( this ).remove();
306 } );
307 }, 3000 );
308 },
309 };
310
311 // Initialize when document is ready.
312 $( document ).ready( function() {
313 CharitableAdminAddons.init();
314 } );
315
316 } )( jQuery );
317