PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / trunk
VikAppointments Services Booking Calendar vtrunk
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / admin / assets / js / wizard.js
vikappointments / admin / assets / js Last commit date
adapter 4 years ago index.html 7 years ago inspector.js 3 years ago mediamanager.js 6 months ago vikappointments.js 2 years ago wizard.js 4 years ago
wizard.js
443 lines
1 /**
2 * Wizard helper class.
3 */
4 class VAPWizard {
5
6 /**
7 * Returns the document step element.
8 *
9 * @param string id The step identifier.
10 *
11 * @return mixed The DOM element.
12 */
13 static getStep(id) {
14 return jQuery('.wizard-step-outer[data-id="' + id + '"]');
15 }
16
17 /**
18 * Returns the document form element.
19 *
20 * @return mixed The DOM element.
21 */
22 static getForm() {
23 // look for the default form ID
24 var form = jQuery('#adminForm');
25
26 if (form.length == 0) {
27 // lets try with the first available form
28 form = jQuery('form').first();
29 }
30
31 return form;
32 }
33
34 /**
35 * Returns the form data of the related step.
36 *
37 * @param string id An optional step ID.
38 * @param boolean asArray True to serialize as array.
39 *
40 * @return mixed The serialized form data.
41 */
42 static getFormData(id, asArray) {
43 // get form element
44 var form = VAPWizard.getForm();
45
46 if (id) {
47 // a step was passed, take only the fields
48 // that belong to that step
49 form = form.find(':input,select,textarea')
50 .filter('[name^="wizard[' + id + ']"]');
51 }
52
53 if (asArray) {
54 // serialize as array
55 return form.serializeArray();
56 }
57
58 // return serialized form
59 return form.serialize();
60 }
61
62 /**
63 * Searches for a temporary data registered
64 * by the wizard step.
65 *
66 * @param string id The step identifier.
67 * @param string key The data key.
68 * @param mixed def An optional default value.
69 *
70 * @return mixed The data value.
71 */
72 static getData(id, key, def) {
73 if (!VAPWizard.DATA.hasOwnProperty(id)) {
74 // no registered data for this step
75 return def;
76 }
77
78 if (!VAPWizard.DATA[id].hasOwnProperty(key)) {
79 // no registered key for the step data
80 return def;
81 }
82
83 // return registered data
84 return VAPWizard.DATA[id][key];
85 }
86
87 /**
88 * Registers a temporary data for the specified
89 * wizard step.
90 *
91 * @param string id The step identifier.
92 * @param string key The data key.
93 * @param mixed val The value to set.
94 *
95 * @return void
96 */
97 static setData(id, key, val) {
98 if (!VAPWizard.DATA.hasOwnProperty(id)) {
99 // register pool
100 VAPWizard.DATA[id] = {};
101 }
102
103 // register data
104 VAPWizard.DATA[id][key] = val;
105 }
106
107 /**
108 * Registers a preflight callback for the
109 * specified wizard step ID.
110 *
111 * @param string id The step identifier.
112 * @param function callback The callback to invoke.
113 *
114 * @return void
115 */
116 static addPreflight(id, callback) {
117 // register callback within the pool
118 VAPWizard.PREFLIGHTS[id] = callback;
119 }
120
121 /**
122 * Unregisters the preflight callback for the
123 * specified wizard step ID.
124 *
125 * @param string id The step identifier.
126 *
127 * @return void
128 */
129 static removePreflight(id) {
130 if (VAPWizard.PREFLIGHTS.hasOwnProperty(id)) {
131 // unregister callback from the pool
132 delete VAPWizard.PREFLIGHTS[id];
133 }
134 }
135
136 /**
137 * Executes the preflight of the specified
138 * wizard step, if registered.
139 *
140 * @param string id The step identifier.
141 * @param mixed step The step DOM element.
142 * @param mixed role The role to execute (ignore, dismiss, process).
143 *
144 * @return mixed The data to post.
145 */
146 static doPreflight(id, step, role) {
147 var data;
148
149 // build event parameters
150 const params = {
151 id: id,
152 step: step,
153 role: role,
154 };
155
156 // create event to trigger before the preflight is dispatched
157 const beforeEvent = jQuery.Event('wizard.preflight.before');
158 beforeEvent.params = params;
159
160 // trigger event to notify any subscriber
161 jQuery(window).trigger(beforeEvent);
162
163 // look for a registered step
164 if (VAPWizard.PREFLIGHTS.hasOwnProperty(id)) {
165 // process preflight (return false to abort request)
166 data = VAPWizard.PREFLIGHTS[id](role, step);
167 }
168
169 // check whether the preflight returned post data
170 if (data === undefined || data === null || data === true) {
171 // extract post data from step
172 data = VAPWizard.getFormData(id);
173 }
174
175 params.data = data;
176
177 // create event to trigger after the preflight is dispatched
178 const afterEvent = jQuery.Event('wizard.preflight.after');
179 afterEvent.params = params;
180
181 // trigger event to notify any subscriber
182 jQuery(window).trigger(afterEvent);
183
184 return data;
185 }
186
187 /**
188 * Registers a postflight callback for the
189 * specified wizard step ID.
190 *
191 * @param string id The step identifier.
192 * @param function callback The callback to invoke.
193 *
194 * @return void
195 */
196 static addPostflight(id, callback) {
197 // register callback within the pool
198 VAPWizard.POSTFLIGHTS[id] = callback;
199 }
200
201 /**
202 * Unregisters the postflight callback for the
203 * specified wizard step ID.
204 *
205 * @param string id The step identifier.
206 *
207 * @return void
208 */
209 static removePostflight(id) {
210 if (VAPWizard.POSTFLIGHTS.hasOwnProperty(id)) {
211 // unregister callback from the pool
212 delete VAPWizard.POSTFLIGHTS[id];
213 }
214 }
215
216 /**
217 * Executes the postflight of the specified
218 * wizard step, if registered.
219 *
220 * @param string id The step identifier.
221 * @param mixed step The step DOM element.
222 * @param mixed role The role to execute (ignore, dismiss, process).
223 * @param mixed error An optional error in case of failure.
224 *
225 * @return void
226 */
227 static doPostflight(id, step, role, error) {
228 // build event parameters
229 const params = {
230 id: id,
231 step: step,
232 role: role,
233 error: error,
234 };
235
236 // create event to trigger before the postflight is dispatched
237 const beforeEvent = jQuery.Event('wizard.postflight.before');
238 beforeEvent.params = params;
239
240 // trigger event to notify any subscriber
241 jQuery(window).trigger(beforeEvent);
242
243 // look for a registered step
244 if (VAPWizard.POSTFLIGHTS.hasOwnProperty(id)) {
245 // process postflight
246 VAPWizard.POSTFLIGHTS[id](role, step, error);
247 }
248
249 // create event to trigger after the postflight is dispatched
250 const afterEvent = jQuery.Event('wizard.postflight.after');
251 afterEvent.params = params;
252
253 // trigger event to notify any subscriber
254 jQuery(window).trigger(afterEvent);
255 }
256
257 /**
258 * Ignores the wizard step.
259 *
260 * @param mixed caller Either the step identifier or the exec button.
261 *
262 * @return Promise
263 */
264 static ignore(caller) {
265 // execute ignore role
266 return VAPWizard.execute(caller, 'ignore');
267 }
268
269 /**
270 * Dismisses the wizard step after completion.
271 *
272 * @param mixed caller Either the step identifier or the exec button.
273 *
274 * @return Promise
275 */
276 static dismiss(caller) {
277 // execute dismiss role
278 return VAPWizard.execute(caller, 'ignore');
279 }
280
281 /**
282 * Processes the wizard step for completion.
283 *
284 * @param mixed caller Either the step identifier or the exec button.
285 *
286 * @return Promise
287 */
288 static process(caller) {
289 // execute process role
290 return VAPWizard.execute(caller, 'process');
291 }
292
293 /**
294 * Executes the specified role for the wizard step.
295 *
296 * @param mixed caller Either the step identifier or the exec button.
297 * @param mixed role The role to execute (ignore, dismiss, process).
298 *
299 * @return Promise
300 */
301 static execute(caller, role) {
302 var id, btn;
303
304 if (typeof caller === 'undefined') {
305 // missing step
306 throw 'Wizard step is missing';
307 } else if (typeof caller === 'string') {
308 // a step ID assumed
309 id = caller;
310 } else {
311 // register button
312 btn = caller;
313
314 // otherwise exec button assumed, find the ID
315 id = jQuery(btn).closest('.wizard-step-outer[data-id]').data('id');
316
317 if (typeof role === 'undefined') {
318 // extract role from button data
319 role = jQuery(btn).data('role');
320 }
321 }
322
323 // create promise
324 return new Promise((resolve, reject) => {
325 // get step element
326 var step = VAPWizard.getStep(id);
327
328 if (!step.length) {
329 // step not found, raise error
330 reject('Wizard step [%s] not found'.replace(/%s/, id));
331
332 return false;
333 }
334
335 if (!btn) {
336 // find button from step
337 btn = step.find('[data-role="' + role + '"]');
338 }
339
340 // make sure the button hasn't been disabled
341 if (jQuery(btn).prop('disabled')) {
342 reject(false);
343
344 return false;
345 }
346
347 // launch preflight and get post data
348 var data = VAPWizard.doPreflight(id, step, role);
349
350 // check whether the preflight prevented the request
351 if (data === false) {
352 reject(false);
353
354 return false;
355 }
356
357 // disable button to avoid multiple executions
358 jQuery(btn).prop('disabled', true);
359
360 // In case the role contains a sub-directive, take only the main one for the request.
361 // In example, if we have process.foo, only process will be used as role for the AJAX call.
362 let task = role.split(/\./).shift();
363
364 // make request
365 UIAjax.do(
366 'index.php?option=com_vikappointments&task=wizard.' + task + '&id=' + id,
367 data,
368 (resp) => {
369 // iterate all steps in response
370 for (var k in resp.steps) {
371 // get temporary step
372 var tmp = VAPWizard.getStep(k);
373
374 // toggle visibility according to received response
375 if (resp.steps[k]) {
376 tmp.show();
377 } else {
378 tmp.hide();
379 }
380
381 // refresh step HTML
382 tmp.html(resp.steps[k]);
383
384 // launch postflight
385 VAPWizard.doPostflight(k, tmp, role, false);
386 }
387
388 // resolve promise on success
389 resolve(resp);
390 },
391 (error) => {
392 // enable button again to retry
393 jQuery(btn).prop('disabled', false);
394
395 // launch postflight on failure too
396 VAPWizard.doPostflight(id, step, role, error);
397
398 console.error(error);
399
400 // reject on failure
401 reject(error.responseText);
402 }
403 );
404 });
405 }
406 }
407
408 /**
409 * A lookup of temporary data that the steps can use
410 * to register their own details during preflights.
411 *
412 * @var object
413 */
414 VAPWizard.DATA = {};
415
416 /**
417 * A lookup of preflights to be used before refreshing
418 * the contents of the steps.
419 *
420 * If needed, a step can register its own callback
421 * to be executed before the AJAX request is started.
422 *
423 * The property name MUST BE equals to the ID of
424 * the step that is registering its callback.
425 *
426 * @var object
427 */
428 VAPWizard.PREFLIGHTS = {};
429
430 /**
431 * A lookup of callbacks to be used after refreshing
432 * the contents of the steps.
433 *
434 * If needed, a step can register its own callback
435 * to be executed once the AJAX request is completed.
436 *
437 * The property name MUST BE equals to the ID of
438 * the step that is registering its callback.
439 *
440 * @var object
441 */
442 VAPWizard.POSTFLIGHTS = {};
443