Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * Plan actions via ajax.
18
 *
19
 * @module     tool_lp/planactions
20
 * @copyright  2015 David Monllao
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
define(['jquery',
24
        'core/templates',
25
        'core/ajax',
26
        'core/notification',
27
        'core/str',
28
        'tool_lp/menubar',
29
        'tool_lp/dialogue'],
30
        function($, templates, ajax, notification, str, Menubar, Dialogue) {
31
 
32
    /**
33
     * PlanActions class.
34
     *
35
     * Note that presently this cannot be instantiated more than once per page.
36
     *
37
     * @param {String} type The type of page we're in.
38
     */
39
    var PlanActions = function(type) {
40
        this._type = type;
41
 
42
        if (type === 'plan') {
43
            // This is the page to view one plan.
44
            this._region = '[data-region="plan-page"]';
45
            this._planNode = '[data-region="plan-page"]';
46
            this._template = 'tool_lp/plan_page';
47
            this._contextMethod = 'tool_lp_data_for_plan_page';
48
 
49
        } else if (type === 'plans') {
50
            // This is the page to view a list of plans.
51
            this._region = '[data-region="plans"]';
52
            this._planNode = '[data-region="plan-node"]';
53
            this._template = 'tool_lp/plans_page';
54
            this._contextMethod = 'tool_lp_data_for_plans_page';
55
 
56
        } else {
57
            throw new TypeError('Unexpected type.');
58
        }
59
    };
60
 
61
    /** @property {String} Ajax method to fetch the page data from. */
62
    PlanActions.prototype._contextMethod = null;
63
    /** @property {String} Selector to find the node describing the plan. */
64
    PlanActions.prototype._planNode = null;
65
    /** @property {String} Selector mapping to the region to update. Usually similar to wrapper. */
66
    PlanActions.prototype._region = null;
67
    /** @property {String} Name of the template used to render the region. */
68
    PlanActions.prototype._template = null;
69
    /** @property {String} Type of page/region we're in. */
70
    PlanActions.prototype._type = null;
71
 
72
    /**
73
     * Resolve the arguments to refresh the region.
74
     *
75
     * @param  {Object} planData Plan data from plan node.
76
     * @return {Object} List of arguments.
77
     */
78
    PlanActions.prototype._getContextArgs = function(planData) {
79
        var self = this,
80
            args = {};
81
 
82
        if (self._type === 'plan') {
83
            args = {
84
                planid: planData.id
85
            };
86
 
87
        } else if (self._type === 'plans') {
88
            args = {
89
                userid: planData.userid
90
            };
91
        }
92
 
93
        return args;
94
    };
95
 
96
    /**
97
     * Refresh the plan view.
98
     *
99
     * This is useful when you only want to refresh the view.
100
     *
101
     * @param  {String} selector The node to search the plan data from.
102
     */
103
    PlanActions.prototype.refresh = function(selector) {
104
        var planData = this._findPlanData($(selector));
105
        this._callAndRefresh([], planData);
106
    };
107
 
108
    /**
109
     * Callback to render the region template.
110
     *
111
     * @param {Object} context The context for the template.
112
     * @return {Promise}
113
     */
114
    PlanActions.prototype._renderView = function(context) {
115
        var self = this;
116
        return templates.render(self._template, context)
117
            .then(function(newhtml, newjs) {
118
                $(self._region).replaceWith(newhtml);
119
                templates.runTemplateJS(newjs);
120
                return;
121
            });
122
    };
123
 
124
    /**
125
     * Call multiple ajax methods, and refresh.
126
     *
127
     * @param  {Array}  calls    List of Ajax calls.
128
     * @param  {Object} planData Plan data from plan node.
129
     * @return {Promise}
130
     */
131
    PlanActions.prototype._callAndRefresh = function(calls, planData) {
132
        // Because this function causes a refresh, we must track the JS completion from start to finish to prevent
133
        // stale reference issues in Behat.
134
        var callKey = 'tool_lp/planactions:_callAndRefresh-' + Math.floor(Math.random() * Math.floor(1000));
135
        M.util.js_pending(callKey);
136
 
137
        var self = this;
138
        calls.push({
139
            methodname: self._contextMethod,
140
            args: self._getContextArgs(planData)
141
        });
142
 
143
        // Apply all the promises, and refresh when the last one is resolved.
144
        return $.when.apply($, ajax.call(calls))
145
            .then(function() {
146
                return self._renderView(arguments[arguments.length - 1]);
147
            })
148
            .fail(notification.exception)
149
            .always(function() {
150
                return M.util.js_complete(callKey);
151
            });
152
    };
153
 
154
    /**
155
     * Delete a plan and reload the region.
156
     *
157
     * @param  {Object} planData Plan data from plan node.
158
     */
159
    PlanActions.prototype._doDelete = function(planData) {
160
        var self = this,
161
            calls = [{
162
                methodname: 'core_competency_delete_plan',
163
                args: {id: planData.id}
164
            }];
165
        self._callAndRefresh(calls, planData);
166
    };
167
 
168
    /**
169
     * Delete a plan.
170
     *
171
     * @param  {Object} planData Plan data from plan node.
172
     */
173
    PlanActions.prototype.deletePlan = function(planData) {
174
        var self = this,
175
            requests;
176
 
177
        requests = ajax.call([{
178
            methodname: 'core_competency_read_plan',
179
            args: {id: planData.id}
180
        }]);
181
 
182
        requests[0].done(function(plan) {
183
            str.get_strings([
184
                {key: 'confirm', component: 'moodle'},
185
                {key: 'deleteplan', component: 'tool_lp', param: plan.name},
186
                {key: 'delete', component: 'moodle'},
187
                {key: 'cancel', component: 'moodle'}
188
            ]).done(function(strings) {
189
                notification.confirm(
190
                    strings[0], // Confirm.
191
                    strings[1], // Delete plan X?
192
                    strings[2], // Delete.
193
                    strings[3], // Cancel.
194
                    function() {
195
                        self._doDelete(planData);
196
                    }
197
                );
198
            }).fail(notification.exception);
199
        }).fail(notification.exception);
200
 
201
    };
202
 
203
    /**
204
     * Reopen plan and reload the region.
205
     *
206
     * @param  {Object} planData Plan data from plan node.
207
     */
208
    PlanActions.prototype._doReopenPlan = function(planData) {
209
        var self = this,
210
            calls = [{
211
                methodname: 'core_competency_reopen_plan',
212
                args: {planid: planData.id}
213
            }];
214
        self._callAndRefresh(calls, planData);
215
    };
216
 
217
    /**
218
     * Reopen a plan.
219
     *
220
     * @param  {Object} planData Plan data from plan node.
221
     */
222
    PlanActions.prototype.reopenPlan = function(planData) {
223
        var self = this,
224
            requests = ajax.call([{
225
                methodname: 'core_competency_read_plan',
226
                args: {id: planData.id}
227
            }]);
228
 
229
        requests[0].done(function(plan) {
230
            str.get_strings([
231
                {key: 'confirm', component: 'moodle'},
232
                {key: 'reopenplanconfirm', component: 'tool_lp', param: plan.name},
233
                {key: 'reopenplan', component: 'tool_lp'},
234
                {key: 'cancel', component: 'moodle'}
235
            ]).done(function(strings) {
236
                notification.confirm(
237
                    strings[0], // Confirm.
238
                    strings[1], // Reopen plan X?
239
                    strings[2], // Reopen.
240
                    strings[3], // Cancel.
241
                    function() {
242
                        self._doReopenPlan(planData);
243
                    }
244
                );
245
            }).fail(notification.exception);
246
        }).fail(notification.exception);
247
 
248
    };
249
 
250
    /**
251
     * Complete plan and reload the region.
252
     *
253
     * @param  {Object} planData Plan data from plan node.
254
     */
255
    PlanActions.prototype._doCompletePlan = function(planData) {
256
        var self = this,
257
            calls = [{
258
                methodname: 'core_competency_complete_plan',
259
                args: {planid: planData.id}
260
            }];
261
        self._callAndRefresh(calls, planData);
262
    };
263
 
264
    /**
265
     * Complete a plan process.
266
     *
267
     * @param  {Object} planData Plan data from plan node.
268
     */
269
    PlanActions.prototype.completePlan = function(planData) {
270
        var self = this,
271
            requests = ajax.call([{
272
                methodname: 'core_competency_read_plan',
273
                args: {id: planData.id}
274
            }]);
275
 
276
        requests[0].done(function(plan) {
277
            str.get_strings([
278
                {key: 'confirm', component: 'moodle'},
279
                {key: 'completeplanconfirm', component: 'tool_lp', param: plan.name},
280
                {key: 'completeplan', component: 'tool_lp'},
281
                {key: 'cancel', component: 'moodle'}
282
            ]).done(function(strings) {
283
                notification.confirm(
284
                    strings[0], // Confirm.
285
                    strings[1], // Complete plan X?
286
                    strings[2], // Complete.
287
                    strings[3], // Cancel.
288
                    function() {
289
                        self._doCompletePlan(planData);
290
                    }
291
                );
292
            }).fail(notification.exception);
293
        }).fail(notification.exception);
294
    };
295
 
296
    /**
297
     * Unlink plan and reload the region.
298
     *
299
     * @param  {Object} planData Plan data from plan node.
300
     */
301
    PlanActions.prototype._doUnlinkPlan = function(planData) {
302
        var self = this,
303
            calls = [{
304
                methodname: 'core_competency_unlink_plan_from_template',
305
                args: {planid: planData.id}
306
            }];
307
        self._callAndRefresh(calls, planData);
308
    };
309
 
310
    /**
311
     * Unlink a plan process.
312
     *
313
     * @param  {Object} planData Plan data from plan node.
314
     */
315
    PlanActions.prototype.unlinkPlan = function(planData) {
316
        var self = this,
317
            requests = ajax.call([{
318
                methodname: 'core_competency_read_plan',
319
                args: {id: planData.id}
320
            }]);
321
 
322
        requests[0].done(function(plan) {
323
            str.get_strings([
324
                {key: 'confirm', component: 'moodle'},
325
                {key: 'unlinkplantemplateconfirm', component: 'tool_lp', param: plan.name},
326
                {key: 'unlinkplantemplate', component: 'tool_lp'},
327
                {key: 'cancel', component: 'moodle'}
328
            ]).done(function(strings) {
329
                notification.confirm(
330
                    strings[0], // Confirm.
331
                    strings[1], // Unlink plan X?
332
                    strings[2], // Unlink.
333
                    strings[3], // Cancel.
334
                    function() {
335
                        self._doUnlinkPlan(planData);
336
                    }
337
                );
338
            }).fail(notification.exception);
339
        }).fail(notification.exception);
340
    };
341
 
342
    /**
343
     * Request review of a plan.
344
     *
345
     * @param  {Object} planData Plan data from plan node.
346
     * @method _doRequestReview
347
     */
348
    PlanActions.prototype._doRequestReview = function(planData) {
349
        var calls = [{
350
            methodname: 'core_competency_plan_request_review',
351
            args: {
352
                id: planData.id
353
            }
354
        }];
355
        this._callAndRefresh(calls, planData);
356
    };
357
 
358
    /**
359
     * Request review of a plan.
360
     *
361
     * @param  {Object} planData Plan data from plan node.
362
     * @method requestReview
363
     */
364
    PlanActions.prototype.requestReview = function(planData) {
365
        this._doRequestReview(planData);
366
    };
367
 
368
    /**
369
     * Cancel review request of a plan.
370
     *
371
     * @param  {Object} planData Plan data from plan node.
372
     * @method _doCancelReviewRequest
373
     */
374
    PlanActions.prototype._doCancelReviewRequest = function(planData) {
375
        var calls = [{
376
            methodname: 'core_competency_plan_cancel_review_request',
377
            args: {
378
                id: planData.id
379
            }
380
        }];
381
        this._callAndRefresh(calls, planData);
382
    };
383
 
384
    /**
385
     * Cancel review request of a plan.
386
     *
387
     * @param  {Object} planData Plan data from plan node.
388
     * @method cancelReviewRequest
389
     */
390
    PlanActions.prototype.cancelReviewRequest = function(planData) {
391
        this._doCancelReviewRequest(planData);
392
    };
393
 
394
    /**
395
     * Start review of a plan.
396
     *
397
     * @param  {Object} planData Plan data from plan node.
398
     * @method _doStartReview
399
     */
400
    PlanActions.prototype._doStartReview = function(planData) {
401
        var calls = [{
402
            methodname: 'core_competency_plan_start_review',
403
            args: {
404
                id: planData.id
405
            }
406
        }];
407
        this._callAndRefresh(calls, planData);
408
    };
409
 
410
    /**
411
     * Start review of a plan.
412
     *
413
     * @param  {Object} planData Plan data from plan node.
414
     * @method startReview
415
     */
416
    PlanActions.prototype.startReview = function(planData) {
417
        this._doStartReview(planData);
418
    };
419
 
420
    /**
421
     * Stop review of a plan.
422
     *
423
     * @param  {Object} planData Plan data from plan node.
424
     * @method _doStopReview
425
     */
426
    PlanActions.prototype._doStopReview = function(planData) {
427
        var calls = [{
428
            methodname: 'core_competency_plan_stop_review',
429
            args: {
430
                id: planData.id
431
            }
432
        }];
433
        this._callAndRefresh(calls, planData);
434
    };
435
 
436
    /**
437
     * Stop review of a plan.
438
     *
439
     * @param  {Object} planData Plan data from plan node.
440
     * @method stopReview
441
     */
442
    PlanActions.prototype.stopReview = function(planData) {
443
        this._doStopReview(planData);
444
    };
445
 
446
    /**
447
     * Approve a plan.
448
     *
449
     * @param  {Object} planData Plan data from plan node.
450
     * @method _doApprove
451
     */
452
    PlanActions.prototype._doApprove = function(planData) {
453
        var calls = [{
454
            methodname: 'core_competency_approve_plan',
455
            args: {
456
                id: planData.id
457
            }
458
        }];
459
        this._callAndRefresh(calls, planData);
460
    };
461
 
462
    /**
463
     * Approve a plan.
464
     *
465
     * @param  {Object} planData Plan data from plan node.
466
     * @method approve
467
     */
468
    PlanActions.prototype.approve = function(planData) {
469
        this._doApprove(planData);
470
    };
471
 
472
    /**
473
     * Unapprove a plan.
474
     *
475
     * @param  {Object} planData Plan data from plan node.
476
     * @method _doUnapprove
477
     */
478
    PlanActions.prototype._doUnapprove = function(planData) {
479
        var calls = [{
480
            methodname: 'core_competency_unapprove_plan',
481
            args: {
482
                id: planData.id
483
            }
484
        }];
485
        this._callAndRefresh(calls, planData);
486
    };
487
 
488
    /**
489
     * Unapprove a plan.
490
     *
491
     * @param  {Object} planData Plan data from plan node.
492
     * @method unapprove
493
     */
494
    PlanActions.prototype.unapprove = function(planData) {
495
        this._doUnapprove(planData);
496
    };
497
 
498
    /**
499
     * Display list of linked courses on a modal dialogue.
500
     *
501
     * @param  {Event} e The event.
502
     */
503
    PlanActions.prototype._showLinkedCoursesHandler = function(e) {
504
        e.preventDefault();
505
 
506
        var competencyid = $(e.target).data('id');
507
        var requests = ajax.call([{
508
            methodname: 'tool_lp_list_courses_using_competency',
509
            args: {id: competencyid}
510
        }]);
511
 
512
        requests[0].done(function(courses) {
513
            var context = {
514
                courses: courses
515
            };
516
            templates.render('tool_lp/linked_courses_summary', context).done(function(html) {
517
                str.get_string('linkedcourses', 'tool_lp').done(function(linkedcourses) {
518
                    new Dialogue(
519
                        linkedcourses, // Title.
520
                        html // The linked courses.
521
                    );
522
                }).fail(notification.exception);
523
            }).fail(notification.exception);
524
        }).fail(notification.exception);
525
    };
526
 
527
    /**
528
     * Plan event handler.
529
     *
530
     * @param  {String} method The method to call.
531
     * @param  {Event} e The event.
532
     * @method _eventHandler
533
     */
534
    PlanActions.prototype._eventHandler = function(method, e) {
535
        e.preventDefault();
536
        var data = this._findPlanData($(e.target));
537
        this[method](data);
538
    };
539
 
540
    /**
541
     * Find the plan data from the plan node.
542
     *
543
     * @param  {Node} node The node to search from.
544
     * @return {Object} Plan data.
545
     */
546
    PlanActions.prototype._findPlanData = function(node) {
547
        var parent = node.parentsUntil($(this._region).parent(), this._planNode),
548
            data;
549
 
550
        if (parent.length != 1) {
551
            throw new Error('The plan node was not located.');
552
        }
553
 
554
        data = parent.data();
555
        if (typeof data === 'undefined' || typeof data.id === 'undefined') {
556
            throw new Error('Plan data could not be found.');
557
        }
558
 
559
        return data;
560
    };
561
 
562
    /**
563
     * Enhance a menu bar.
564
     *
565
     * @param  {String} selector Menubar selector.
566
     */
567
    PlanActions.prototype.enhanceMenubar = function(selector) {
568
        Menubar.enhance(selector, {
569
            '[data-action="plan-delete"]': this._eventHandler.bind(this, 'deletePlan'),
570
            '[data-action="plan-complete"]': this._eventHandler.bind(this, 'completePlan'),
571
            '[data-action="plan-reopen"]': this._eventHandler.bind(this, 'reopenPlan'),
572
            '[data-action="plan-unlink"]': this._eventHandler.bind(this, 'unlinkPlan'),
573
            '[data-action="plan-request-review"]': this._eventHandler.bind(this, 'requestReview'),
574
            '[data-action="plan-cancel-review-request"]': this._eventHandler.bind(this, 'cancelReviewRequest'),
575
            '[data-action="plan-start-review"]': this._eventHandler.bind(this, 'startReview'),
576
            '[data-action="plan-stop-review"]': this._eventHandler.bind(this, 'stopReview'),
577
            '[data-action="plan-approve"]': this._eventHandler.bind(this, 'approve'),
578
            '[data-action="plan-unapprove"]': this._eventHandler.bind(this, 'unapprove'),
579
        });
580
    };
581
 
582
    /**
583
     * Register the events in the region.
584
     *
585
     * At this stage this cannot be used with enhanceMenubar or multiple handlers
586
     * will be added to the same node.
587
     */
588
    PlanActions.prototype.registerEvents = function() {
589
        var wrapper = $(this._region);
590
 
591
        wrapper.find('[data-action="plan-delete"]').click(this._eventHandler.bind(this, 'deletePlan'));
592
        wrapper.find('[data-action="plan-complete"]').click(this._eventHandler.bind(this, 'completePlan'));
593
        wrapper.find('[data-action="plan-reopen"]').click(this._eventHandler.bind(this, 'reopenPlan'));
594
        wrapper.find('[data-action="plan-unlink"]').click(this._eventHandler.bind(this, 'unlinkPlan'));
595
 
596
        wrapper.find('[data-action="plan-request-review"]').click(this._eventHandler.bind(this, 'requestReview'));
597
        wrapper.find('[data-action="plan-cancel-review-request"]').click(this._eventHandler.bind(this, 'cancelReviewRequest'));
598
        wrapper.find('[data-action="plan-start-review"]').click(this._eventHandler.bind(this, 'startReview'));
599
        wrapper.find('[data-action="plan-stop-review"]').click(this._eventHandler.bind(this, 'stopReview'));
600
        wrapper.find('[data-action="plan-approve"]').click(this._eventHandler.bind(this, 'approve'));
601
        wrapper.find('[data-action="plan-unapprove"]').click(this._eventHandler.bind(this, 'unapprove'));
602
 
603
        wrapper.find('[data-action="find-courses-link"]').click(this._showLinkedCoursesHandler.bind(this));
604
    };
605
 
606
    return PlanActions;
607
});