PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
booking / includes / booking_modes_v3 / _src / booking_modes.js

booking_modes.js in Booking Calendar 11.8.4, at includes/booking_modes_v3/_src/booking_modes.js

298 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global jQuery, wpbc_booking_modes_config, wpbc_admin_show_message */
2 (function ($) {
3 'use strict';
4
5 var switch_busy = false;
6 var switch_message_storage_key = 'wpbc_booking_modes_v3_switch_success';
7 var switch_message_max_age = 120000;
8
9 /**
10 * Read a user-facing error from a WordPress AJAX response.
11 *
12 * @param {Object|undefined} response Parsed AJAX response.
13 * @param {string|undefined} fallback Optional fallback message.
14 * @return {string} Safe error text.
15 */
16 function get_error_message(response, fallback) {
17 if (
18 response
19 && response.data
20 && typeof response.data.message === 'string'
21 && response.data.message.length
22 ) {
23 return response.data.message;
24 }
25
26 return fallback || wpbc_booking_modes_config.i18n.error;
27 }
28
29 /**
30 * Show a mode-switch error through the existing Booking Calendar notifier.
31 *
32 * @param {string} message Error message.
33 * @param {number|undefined} delay Optional display duration in milliseconds.
34 * @return {void}
35 */
36 function show_error(message, delay) {
37 if (typeof window.wpbc_admin_show_message === 'function') {
38 window.wpbc_admin_show_message(message, 'error', delay || 10000, false);
39 return;
40 }
41
42 window.alert(message);
43 }
44
45 /**
46 * Show a successful QuickStart message through the existing notifier.
47 *
48 * @param {string} message Success message.
49 * @return {void}
50 */
51 function show_success(message) {
52 if (typeof window.wpbc_admin_show_message === 'function') {
53 window.wpbc_admin_show_message(message, 'success', 10000, false);
54 return;
55 }
56
57 window.alert(message);
58 }
59
60 /**
61 * Show non-blocking mode-switch progress through the admin notifier.
62 *
63 * The request must continue immediately, so this intentionally has no alert
64 * fallback when the shared Booking Calendar notifier is unavailable.
65 *
66 * @param {string} message Progress message.
67 * @return {void}
68 */
69 function show_info(message) {
70 if (typeof window.wpbc_admin_show_message === 'function') {
71 window.wpbc_admin_show_message(message, 'info', 10000, false);
72 }
73 }
74
75 /**
76 * Show the server-confirmed mode activation before redirecting.
77 *
78 * @param {string} message Success message.
79 * @return {void}
80 */
81 function show_switch_success(message) {
82 if (message && typeof window.wpbc_admin_show_message === 'function') {
83 window.wpbc_admin_show_message(message, 'success', 1500, false);
84 }
85 }
86
87 /**
88 * Save the activated mode for a V1-compatible notice on the final page.
89 *
90 * V3 uses a signed full-administration landing before the final destination,
91 * so an in-page notice shown before navigation would otherwise disappear.
92 * Session storage keeps this presentation-only state out of WordPress data
93 * and naturally isolates it to the tab that initiated the switch.
94 *
95 * @param {string} mode_id Activated mode identifier.
96 * @return {void}
97 */
98 function store_switch_success(mode_id) {
99 var normalized_mode_id = typeof mode_id === 'string' ? mode_id : '';
100
101 if (!normalized_mode_id) {
102 return;
103 }
104
105 try {
106 window.sessionStorage.setItem(
107 switch_message_storage_key,
108 JSON.stringify({
109 mode_id: normalized_mode_id,
110 created_at: Date.now()
111 })
112 );
113 } catch (error) {
114 // A blocked or full browser store must never prevent mode switching.
115 }
116 }
117
118 /**
119 * Show and consume the pending switch message on the final WPBC page.
120 *
121 * The record is removed before validation or display so refreshes, malformed
122 * values, account changes, and stale records cannot replay it. Matching the
123 * localized selected mode prevents a notice from leaking into another mode.
124 *
125 * @return {void}
126 */
127 function show_pending_switch_success() {
128 var serialized_message;
129 var pending_message;
130 var current_mode_id = String(wpbc_booking_modes_config.selected_mode_id || '');
131 var success_message = wpbc_booking_modes_config.i18n.switch_success || '';
132
133 try {
134 serialized_message = window.sessionStorage.getItem(switch_message_storage_key);
135 window.sessionStorage.removeItem(switch_message_storage_key);
136 } catch (error) {
137 return;
138 }
139
140 if (!serialized_message || !current_mode_id || typeof success_message !== 'string' || !success_message) {
141 return;
142 }
143
144 try {
145 pending_message = JSON.parse(serialized_message);
146 } catch (error) {
147 return;
148 }
149
150 if (
151 !pending_message
152 || pending_message.mode_id !== current_mode_id
153 || typeof pending_message.created_at !== 'number'
154 || pending_message.created_at > Date.now()
155 || Date.now() - pending_message.created_at > switch_message_max_age
156 ) {
157 return;
158 }
159
160 show_switch_success(success_message);
161 }
162
163 /**
164 * Toggle the shared switching state and all dropdown choices.
165 *
166 * @param {jQuery} $selector Mode selector container.
167 * @param {boolean} is_busy Whether a mode-switch request is active.
168 * @return {void}
169 */
170 function set_switching_state($selector, is_busy) {
171 switch_busy = is_busy;
172 $selector.toggleClass('is-switching', is_busy);
173
174 if (is_busy) {
175 $selector.attr('aria-busy', 'true');
176 $selector.find('.wpbc_booking_mode_option').attr('aria-disabled', 'true');
177 return;
178 }
179
180 $selector.removeAttr('aria-busy');
181 $selector.find('.wpbc_booking_mode_option').removeAttr('aria-disabled');
182 }
183
184 /**
185 * Persist a selected mode and follow the server-approved redirect.
186 *
187 * @param {Event} event Click event for a selector option.
188 * @return {void}
189 */
190 function switch_mode(event) {
191 var $option = $(event.currentTarget);
192 var $selector = $option.closest('.wpbc_booking_modes_selector');
193 var mode_id = String($option.data('mode-id') || '');
194
195 event.preventDefault();
196
197 if (switch_busy || !mode_id || $option.hasClass('is-current')) {
198 return;
199 }
200
201 set_switching_state($selector, true);
202 show_info(wpbc_booking_modes_config.i18n.saving || 'Switching Booking Calendar mode...');
203
204 $.ajax({
205 url: wpbc_booking_modes_config.ajax_url,
206 method: 'POST',
207 dataType: 'json',
208 data: {
209 action: wpbc_booking_modes_config.action,
210 nonce: wpbc_booking_modes_config.nonce,
211 mode_id: mode_id,
212 origin_url: window.location.href.split('#')[0],
213 fragment: window.location.hash ? window.location.hash.substring(1) : ''
214 }
215 }).done(function (response) {
216 if (
217 !response
218 || response.success !== true
219 || !response.data
220 || typeof response.data.redirect_url !== 'string'
221 || !response.data.redirect_url.length
222 ) {
223 set_switching_state($selector, false);
224 show_error(get_error_message(response), 7000);
225 return;
226 }
227
228 show_switch_success(response.data.message || wpbc_booking_modes_config.i18n.switched);
229 store_switch_success(mode_id);
230 window.location.assign(response.data.redirect_url);
231 }).fail(function (xhr) {
232 set_switching_state($selector, false);
233 show_error(get_error_message(xhr.responseJSON), 7000);
234 });
235 }
236
237 /**
238 * Run a separately confirmed, state-changing QuickStart operation.
239 *
240 * @param {Event} event Click event for a QuickStart button.
241 * @return {void}
242 */
243 function run_quickstart(event) {
244 var $button = $(event.currentTarget);
245 var $actions = $button.closest('.wpbc_booking_modes_quickstart_actions');
246 var mode_id = String($button.data('mode-id') || '');
247 var quickstart = wpbc_booking_modes_config.quickstart || {};
248
249 event.preventDefault();
250
251 if (!mode_id || !quickstart.action || !quickstart.nonce || $button.prop('disabled')) {
252 return;
253 }
254
255 if (!window.confirm(wpbc_booking_modes_config.i18n.quickstart_confirm)) {
256 return;
257 }
258
259 $button.prop('disabled', true).attr('aria-busy', 'true');
260
261 $.ajax({
262 url: wpbc_booking_modes_config.ajax_url,
263 method: 'POST',
264 dataType: 'json',
265 data: {
266 action: quickstart.action,
267 nonce: quickstart.nonce,
268 mode_id: mode_id
269 }
270 }).done(function (response) {
271 var $test_page;
272
273 if (
274 !response
275 || response.success !== true
276 || !response.data
277 || typeof response.data.test_url !== 'string'
278 || !response.data.test_url.length
279 ) {
280 show_error(get_error_message(response, wpbc_booking_modes_config.i18n.quickstart_error));
281 return;
282 }
283
284 $test_page = $actions.find('.wpbc_booking_modes_test_page');
285 $test_page.attr('href', response.data.test_url).removeClass('is-hidden').trigger('focus');
286 show_success(response.data.message || wpbc_booking_modes_config.i18n.test_page);
287 }).fail(function (xhr) {
288 show_error(get_error_message(xhr.responseJSON, wpbc_booking_modes_config.i18n.quickstart_error));
289 }).always(function () {
290 $button.prop('disabled', false).removeAttr('aria-busy');
291 });
292 }
293
294 $(document).on('click', '.wpbc_booking_mode_option', switch_mode);
295 $(document).on('click', '.wpbc_booking_modes_quickstart_button', run_quickstart);
296 $(show_pending_switch_success);
297 }(jQuery));
298