Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core_courseformat\output\local\content\section;
18
 
1441 ariadna 19
use core\context\course as context_course;
20
use core\output\action_menu;
21
use core\output\action_menu\link;
22
use core\output\action_menu\link_secondary;
23
use core\output\pix_icon;
24
use core\output\renderer_base;
1 efrain 25
use core_courseformat\base as course_format;
1441 ariadna 26
use core_courseformat\output\local\content\basecontrolmenu;
27
use core\url;
1 efrain 28
use section_info;
29
 
30
/**
31
 * Base class to render section controls.
32
 *
33
 * @package   core_courseformat
34
 * @copyright 2020 Ferran Recio <ferran@moodle.com>
35
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
1441 ariadna 37
class controlmenu extends basecontrolmenu {
1 efrain 38
 
39
    /**
40
     * Constructor.
41
     *
42
     * @param course_format $format the course format
43
     * @param section_info $section the section info
44
     */
45
    public function __construct(course_format $format, section_info $section) {
1441 ariadna 46
        parent::__construct($format, $section, null, $section->id);
1 efrain 47
    }
48
 
49
    /**
1441 ariadna 50
     * Generate the action menu element depending on the section.
1 efrain 51
     *
1441 ariadna 52
     * Sections controlled by a plugin will delegate the control menu to the delegated section class.
53
     *
54
     * @param renderer_base $output typically, the renderer that's calling this function
55
     * @return action_menu|null the section action menu or null if no action menu is available
1 efrain 56
     */
1441 ariadna 57
    public function get_action_menu(renderer_base $output): ?action_menu {
58
 
59
        if (!empty($this->menu)) {
60
            return $this->menu;
1 efrain 61
        }
62
 
63
        $sectiondelegate = $this->section->get_component_instance();
64
        if ($sectiondelegate) {
65
            return $sectiondelegate->get_section_action_menu($this->format, $this, $output);
66
        }
67
        return $this->get_default_action_menu($output);
68
    }
69
 
70
    /**
71
     * Generate the default section action menu.
72
     *
73
     * This method is public in case some block needs to modify the menu before output it.
74
     *
1441 ariadna 75
     * @param renderer_base $output typically, the renderer that's calling this function
76
     * @return action_menu|null the section action menu
1 efrain 77
     */
1441 ariadna 78
    public function get_default_action_menu(renderer_base $output): ?action_menu {
1 efrain 79
        $controls = $this->section_control_items();
1441 ariadna 80
        return $this->format_controls($controls);
81
    }
82
 
83
    /**
84
     * Generate the edit control items of a section.
85
     *
86
     * @return array of edit control items
87
     */
88
    public function section_control_items() {
89
        // TODO remove this if as part of MDL-83530.
90
        if (!$this->format->supports_components()) {
91
            return $this->section_control_items_legacy();
92
        }
93
 
94
        $controls = [];
95
 
96
        $controls['view'] = $this->get_section_view_item();
97
 
98
        if (!$this->section->is_orphan()) {
99
            $controls['edit'] = $this->get_section_edit_item();
100
            $controls['duplicate'] = $this->get_section_duplicate_item();
101
            $controls['visibility'] = $this->get_section_visibility_item();
102
            $controls['movesection'] = $this->get_section_movesection_item();
103
            $controls['permalink'] = $this->get_section_permalink_item();
104
        }
105
 
106
        $controls['delete'] = $this->get_section_delete_item();
107
 
108
        return $controls;
109
    }
110
 
111
    /**
112
     * Retrieves the view item for the section control menu.
113
     *
114
     * @return link|null The menu item if applicable, otherwise null.
115
     */
116
    protected function get_section_view_item(): ?link {
117
        // Only show the view link if we are not already in the section view page.
118
        if ($this->format->get_sectionid() == $this->section->id) {
1 efrain 119
            return null;
120
        }
1441 ariadna 121
        return new link_secondary(
122
                url: new url('/course/section.php', ['id' => $this->section->id]),
123
                icon: new pix_icon('i/viewsection', ''),
124
                text: get_string('view'),
125
                attributes: ['class' => 'view'],
126
        );
127
    }
1 efrain 128
 
1441 ariadna 129
    /**
130
     * Retrieves the edit item for the section control menu.
131
     *
132
     * @return link|null The menu item if applicable, otherwise null.
133
     */
134
    protected function get_section_edit_item(): ?link {
135
        if (!has_capability('moodle/course:update', $this->coursecontext)) {
136
            return null;
1 efrain 137
        }
1441 ariadna 138
 
139
        $url = new url(
140
            '/course/editsection.php',
141
            [
142
                'id' => $this->section->id,
143
                'sr' => $this->section->sectionnum,
144
            ]
145
        );
146
 
147
        return new link_secondary(
148
                url: $url,
149
                icon: new pix_icon('i/settings', ''),
150
                text: get_string('editsection'),
151
                attributes: ['class' => 'edit'],
152
        );
1 efrain 153
    }
154
 
155
    /**
1441 ariadna 156
     * Retrieves the duplicate item for the section control menu.
157
     *
158
     * @return link|null The menu item if applicable, otherwise null.
159
     */
160
    protected function get_section_duplicate_item(): ?link {
161
        if (
162
            $this->section->sectionnum == 0
163
            || !has_capability('moodle/course:update', $this->coursecontext)
164
        ) {
165
            return null;
166
        }
167
 
168
        $url = new url(
169
            $this->baseurl,
170
            [
171
                'sectionid' => $this->section->id,
172
                'duplicatesection' => 1,
173
                'sesskey' => sesskey(),
174
            ]
175
        );
176
 
177
        return new link_secondary(
178
                url: $url,
179
                icon: new pix_icon('t/copy', ''),
180
                text: get_string('duplicate'),
181
                attributes: ['class' => 'duplicate'],
182
        );
183
    }
184
 
185
    /**
186
     * Retrieves the get_section_visibility_menu_item item for the section control menu.
187
     *
188
     * @return link|null The menu item if applicable, otherwise null.
189
     */
190
    protected function get_section_visibility_item(): ?link {
191
        if (
192
            $this->section->sectionnum == 0
193
            || !has_capability('moodle/course:sectionvisibility', $this->coursecontext)
194
        ) {
195
            return null;
196
        }
197
        $sectionreturn = $this->format->get_sectionnum();
198
 
199
        $strhide = get_string('hide');
200
        $strshow = get_string('show');
201
 
202
        if ($this->section->visible) {
203
            $stateaction = 'section_hide';
204
            $icon = 'i/show';
205
            $name = $strhide;
206
            $attributes = [
207
                'class' => 'icon editing_showhide',
208
                'data-sectionreturn' => $sectionreturn,
209
                'data-action' => 'sectionHide',
210
                'data-id' => $this->section->id,
211
                'data-icon' => 'i/show',
212
                'data-swapname' => $strshow,
213
                'data-swapicon' => 'i/hide',
214
            ];
215
        } else {
216
            $stateaction = 'section_show';
217
            $icon = 'i/hide';
218
            $name = $strshow;
219
            $attributes = [
220
                'class' => 'editing_showhide',
221
                'data-sectionreturn' => $sectionreturn,
222
                'data-action' => 'sectionShow',
223
                'data-id' => $this->section->id,
224
                'data-icon' => 'i/hide',
225
                'data-swapname' => $strhide,
226
                'data-swapicon' => 'i/show',
227
            ];
228
        }
229
 
230
        $url = $this->format->get_update_url(
231
            action: $stateaction,
232
            ids: [$this->section->id],
233
            returnurl: $this->baseurl,
234
        );
235
 
236
        return new link_secondary(
237
                url: $url,
238
                icon: new pix_icon($icon, ''),
239
                text: $name,
240
                attributes: $attributes,
241
        );
242
    }
243
 
244
    /**
245
     * Retrieves the move item for the section control menu.
246
     *
247
     * @return link|null The menu item if applicable, otherwise null.
248
     */
249
    protected function get_section_movesection_item(): ?link {
250
        if (
251
            $this->section->sectionnum == 0
252
            || $this->format->get_sectionid()
253
            || !has_capability('moodle/course:movesections', $this->coursecontext)
254
        ) {
255
            return null;
256
        }
257
 
258
        $url = new url(
259
            $this->baseurl,
260
            [
261
                'movesection' => $this->section->sectionnum,
262
                'section' => $this->section->sectionnum,
263
            ]
264
        );
265
 
266
        return new link_secondary(
267
            url: $url,
268
            icon: new pix_icon('i/dragdrop', ''),
269
            text: get_string('move'),
270
            attributes: [
271
                // This tool requires ajax and will appear only when the frontend state is ready.
272
                'class' => 'move waitstate',
273
                'data-action' => 'moveSection',
274
                'data-id' => $this->section->id,
275
            ],
276
        );
277
    }
278
 
279
    /**
280
     * Retrieves the move up for the section control menu.
281
     *
282
     * This actions only apply to non-component-based formats
283
     * or when javascript is not available.
284
     *
285
     * Note: this action will be removed, do not depend on it for your
286
     * custom formats. For more information, see MDL-83562. Use this method
287
     * only if your format is not compatible with the move section modal
288
     * and you are still migrating to components.
289
     *
290
     * @deprecated since Moodle 5.0
291
     * @todo Remove this method in Moodle 6.0 (MDL-83530).
292
     * @return link|null The menu item if applicable, otherwise null.
293
     */
294
    #[\core\attribute\deprecated(
295
        replacement: 'core_courseformat\output\local\content\section::get_section_movesection_item',
296
        since: '5.0',
297
        reason: 'Non-ajax section move is deprecated.',
298
        mdl: 'MDL-83562',
299
    )]
300
    protected function get_section_moveup_item(): ?link {
301
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
302
        if (
303
            $this->section->sectionnum <= 1
304
            || $this->format->get_sectionid()
305
            || !has_capability('moodle/course:movesections', $this->coursecontext)
306
        ) {
307
            return null;
308
        }
309
 
310
        $url = new url(
311
            $this->baseurl,
312
            [
313
                'section' => $this->section->sectionnum,
314
                'move' => -1,
315
                'sesskey' => sesskey(),
316
            ]
317
        );
318
 
319
        return new link_secondary(
320
            url: $url,
321
            icon: new pix_icon('i/up', ''),
322
            text: get_string('moveup'),
323
            attributes: [
324
                // This tool disappears when the state is ready whilenostate.
325
                'class' => 'moveup whilenostate',
326
            ],
327
        );
328
    }
329
 
330
    /**
331
     * Retrieves the move down for the section control menu.
332
     *
333
     * This actions only apply to non-component-based formats
334
     * or when javascript is not available.
335
     *
336
     * Note: this action will be removed, do not depend on it for your
337
     * custom formats. For more information, see MDL-83562.
338
     *
339
     * @deprecated since Moodle 5.0
340
     * @todo Remove this method in Moodle 6.0 (MDL-83530).
341
     * @return link|null The menu item if applicable, otherwise null.
342
     */
343
    #[\core\attribute\deprecated(
344
        replacement: 'core_courseformat\output\local\content\section::get_section_movesection_item',
345
        since: '5.0',
346
        reason: 'Non-ajax section move is deprecated.',
347
        mdl: 'MDL-83562',
348
    )]
349
    protected function get_section_movedown_item(): ?link {
350
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
351
        $numsections = $this->format->get_last_section_number();
352
 
353
        if (
354
            $this->section->sectionnum == 0
355
            || $this->section->sectionnum >= $numsections
356
            || $this->format->get_sectionid()
357
            || !has_capability('moodle/course:movesections', $this->coursecontext)
358
        ) {
359
            return null;
360
        }
361
 
362
        $url = new url(
363
            $this->baseurl,
364
            [
365
                'section' => $this->section->sectionnum,
366
                'move' => 1,
367
                'sesskey' => sesskey(),
368
            ]
369
        );
370
 
371
        return new link_secondary(
372
            url: $url,
373
            icon: new pix_icon('i/down', ''),
374
            text: get_string('movedown'),
375
            attributes: [
376
                // This tool disappears when the state is ready.
377
                'class' => 'movedown whilenostate',
378
            ],
379
        );
380
    }
381
 
382
    /**
383
     * Retrieves the permalink item for the section control menu.
384
     *
385
     * @return link|null The menu item if applicable, otherwise null.
386
     */
387
    protected function get_section_permalink_item(): ?link {
388
        if (!has_any_capability(
389
                [
390
                    'moodle/course:movesections',
391
                    'moodle/course:update',
392
                    'moodle/course:sectionvisibility',
393
                ],
394
                $this->coursecontext
395
            )
396
        ) {
397
            return null;
398
        }
399
 
400
        $url = new url(
401
            '/course/section.php',
402
            ['id' => $this->section->id]
403
        );
404
        return new link_secondary(
405
            url: $url,
406
            icon: new pix_icon('i/link', ''),
407
            text: get_string('sectionlink', 'course'),
408
            attributes: [
409
                'class' => 'permalink',
410
                'data-action' => 'permalink',
411
            ],
412
        );
413
    }
414
 
415
    /**
416
     * Retrieves the delete item for the section control menu.
417
     *
418
     * @return link|null The menu item if applicable, otherwise null.
419
     */
420
    protected function get_section_delete_item(): ?link {
421
        if (!course_can_delete_section($this->format->get_course(), $this->section)) {
422
            return null;
423
        }
424
 
425
        $url = $this->format->get_update_url(
426
            action: 'section_delete',
427
            ids: [$this->section->id],
428
            returnurl: $this->baseurl,
429
        );
430
        return new link_secondary(
431
            url: $url,
432
            icon: new pix_icon('i/delete', ''),
433
            text: get_string('delete'),
434
            attributes: [
435
                'class' => 'editing_delete text-danger',
436
                'data-action' => 'deleteSection',
437
                'data-id' => $this->section->id,
438
            ],
439
        );
440
    }
441
 
442
    /**
1 efrain 443
     * Generate the edit control items of a section.
444
     *
445
     * It is not clear this kind of controls are still available in 4.0 so, for now, this
446
     * method is almost a clone of the previous section_control_items from the course/renderer.php.
447
     *
448
     * This method must remain public until the final deprecation of section_edit_control_items.
449
     *
1441 ariadna 450
     * @deprecated since Moodle 5.0
451
     * @todo Remove this method in Moodle 6.0 (MDL-83530).
1 efrain 452
     * @return array of edit control items
453
     */
1441 ariadna 454
    #[\core\attribute\deprecated(
455
        replacement: 'section_control_items',
456
        since: '5.0',
457
        mdl: 'MDL-83527',
458
    )]
459
    protected function section_control_items_legacy(): array {
1 efrain 460
        global $USER, $PAGE;
1441 ariadna 461
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
1 efrain 462
 
463
        $format = $this->format;
464
        $section = $this->section;
465
        $course = $format->get_course();
466
        $sectionreturn = !is_null($format->get_sectionid()) ? $format->get_sectionnum() : null;
467
        $user = $USER;
468
 
469
        $usecomponents = $format->supports_components();
470
        $coursecontext = context_course::instance($course->id);
471
        $numsections = $format->get_last_section_number();
1441 ariadna 472
        $isstealth = $section->is_orphan();
1 efrain 473
 
474
        $baseurl = course_get_url($course, $sectionreturn);
475
        $baseurl->param('sesskey', sesskey());
476
 
477
        $controls = [];
478
 
479
        // Only show the view link if we are not already in the section view page.
480
        if ($PAGE->pagetype !== 'course-view-section-' . $course->format) {
481
            $controls['view'] = [
1441 ariadna 482
                'url'   => new url('/course/section.php', ['id' => $section->id]),
1 efrain 483
                'icon' => 'i/viewsection',
484
                'name' => get_string('view'),
485
                'pixattr' => ['class' => ''],
486
                'attr' => ['class' => 'icon view'],
487
            ];
488
        }
489
 
490
        if (!$isstealth && has_capability('moodle/course:update', $coursecontext, $user)) {
491
            $params = ['id' => $section->id];
492
            $params['sr'] = $section->section;
493
            if (get_string_manager()->string_exists('editsection', 'format_'.$format->get_format())) {
494
                $streditsection = get_string('editsection', 'format_'.$format->get_format());
495
            } else {
496
                $streditsection = get_string('editsection');
497
            }
498
 
499
            $controls['edit'] = [
1441 ariadna 500
                'url'   => new url('/course/editsection.php', $params),
1 efrain 501
                'icon' => 'i/settings',
502
                'name' => $streditsection,
503
                'pixattr' => ['class' => ''],
504
                'attr' => ['class' => 'icon edit'],
505
            ];
506
 
11 efrain 507
            if ($section->section) {
508
                $duplicatesectionurl = clone($baseurl);
509
                $duplicatesectionurl->param('sectionid', $section->id);
510
                $duplicatesectionurl->param('duplicatesection', 1);
511
                if (!is_null($sectionreturn)) {
512
                    $duplicatesectionurl->param('sr', $sectionreturn);
513
                }
514
                $controls['duplicate'] = [
515
                    'url' => $duplicatesectionurl,
516
                    'icon' => 't/copy',
517
                    'name' => get_string('duplicate'),
518
                    'pixattr' => ['class' => ''],
519
                    'attr' => ['class' => 'icon duplicate'],
520
                ];
1 efrain 521
            }
522
        }
523
 
524
        if ($section->section) {
525
            $url = clone($baseurl);
526
            if (!is_null($sectionreturn)) {
527
                $url->param('sectionid', $format->get_sectionid());
528
            }
529
            if (!$isstealth) {
530
                if (has_capability('moodle/course:sectionvisibility', $coursecontext, $user)) {
531
                    $strhidefromothers = get_string('hidefromothers', 'format_' . $course->format);
532
                    $strshowfromothers = get_string('showfromothers', 'format_' . $course->format);
533
                    if ($section->visible) { // Show the hide/show eye.
534
                        $url->param('hide', $section->section);
11 efrain 535
                        $controls['visibility'] = [
1 efrain 536
                            'url' => $url,
11 efrain 537
                            'icon' => 'i/show',
1 efrain 538
                            'name' => $strhidefromothers,
539
                            'pixattr' => ['class' => ''],
540
                            'attr' => [
541
                                'class' => 'icon editing_showhide',
542
                                'data-sectionreturn' => $sectionreturn,
543
                                'data-action' => ($usecomponents) ? 'sectionHide' : 'hide',
544
                                'data-id' => $section->id,
11 efrain 545
                                'data-icon' => 'i/show',
1 efrain 546
                                'data-swapname' => $strshowfromothers,
11 efrain 547
                                'data-swapicon' => 'i/hide',
1 efrain 548
                            ],
549
                        ];
550
                    } else {
551
                        $url->param('show',  $section->section);
11 efrain 552
                        $controls['visibility'] = [
1 efrain 553
                            'url' => $url,
11 efrain 554
                            'icon' => 'i/hide',
1 efrain 555
                            'name' => $strshowfromothers,
556
                            'pixattr' => ['class' => ''],
557
                            'attr' => [
558
                                'class' => 'icon editing_showhide',
559
                                'data-sectionreturn' => $sectionreturn,
560
                                'data-action' => ($usecomponents) ? 'sectionShow' : 'show',
561
                                'data-id' => $section->id,
11 efrain 562
                                'data-icon' => 'i/hide',
1 efrain 563
                                'data-swapname' => $strhidefromothers,
11 efrain 564
                                'data-swapicon' => 'i/show',
1 efrain 565
                            ],
566
                        ];
567
                    }
568
                }
569
 
570
                if (!$sectionreturn && has_capability('moodle/course:movesections', $coursecontext, $user)) {
571
                    if ($usecomponents) {
572
                        // This tool will appear only when the state is ready.
573
                        $url = clone ($baseurl);
574
                        $url->param('movesection', $section->section);
575
                        $url->param('section', $section->section);
576
                        $controls['movesection'] = [
577
                            'url' => $url,
578
                            'icon' => 'i/dragdrop',
579
                            'name' => get_string('move', 'moodle'),
580
                            'pixattr' => ['class' => ''],
581
                            'attr' => [
582
                                'class' => 'icon move waitstate',
583
                                'data-action' => 'moveSection',
584
                                'data-id' => $section->id,
585
                            ],
586
                        ];
587
                    }
588
                    // Legacy move up and down links for non component-based formats.
589
                    $url = clone($baseurl);
590
                    if ($section->section > 1) { // Add a arrow to move section up.
591
                        $url->param('section', $section->section);
592
                        $url->param('move', -1);
593
                        $strmoveup = get_string('moveup');
594
                        $controls['moveup'] = [
595
                            'url' => $url,
596
                            'icon' => 'i/up',
597
                            'name' => $strmoveup,
598
                            'pixattr' => ['class' => ''],
599
                            'attr' => ['class' => 'icon moveup whilenostate'],
600
                        ];
601
                    }
602
 
603
                    $url = clone($baseurl);
604
                    if ($section->section < $numsections) { // Add a arrow to move section down.
605
                        $url->param('section', $section->section);
606
                        $url->param('move', 1);
607
                        $strmovedown = get_string('movedown');
608
                        $controls['movedown'] = [
609
                            'url' => $url,
610
                            'icon' => 'i/down',
611
                            'name' => $strmovedown,
612
                            'pixattr' => ['class' => ''],
613
                            'attr' => ['class' => 'icon movedown whilenostate'],
614
                        ];
615
                    }
616
                }
617
            }
618
 
619
            if (course_can_delete_section($course, $section)) {
620
                if (get_string_manager()->string_exists('deletesection', 'format_'.$course->format)) {
621
                    $strdelete = get_string('deletesection', 'format_'.$course->format);
622
                } else {
623
                    $strdelete = get_string('deletesection');
624
                }
625
                $params = [
626
                    'id' => $section->id,
627
                    'delete' => 1,
628
                    'sesskey' => sesskey(),
629
                ];
630
                if (!is_null($sectionreturn)) {
631
                    $params['sr'] = $sectionreturn;
632
                }
1441 ariadna 633
                $url = new url(
1 efrain 634
                    '/course/editsection.php',
635
                    $params,
636
                );
637
                $controls['delete'] = [
638
                    'url' => $url,
639
                    'icon' => 'i/delete',
640
                    'name' => $strdelete,
641
                    'pixattr' => ['class' => ''],
642
                    'attr' => [
643
                        'class' => 'icon editing_delete text-danger',
644
                        'data-action' => 'deleteSection',
645
                        'data-id' => $section->id,
646
                    ],
647
                ];
648
            }
649
        }
650
        if (
1441 ariadna 651
            !$isstealth &&
1 efrain 652
            has_any_capability([
653
                'moodle/course:movesections',
654
                'moodle/course:update',
655
                'moodle/course:sectionvisibility',
656
            ], $coursecontext)
657
        ) {
1441 ariadna 658
            $sectionlink = new url(
1 efrain 659
                '/course/section.php',
660
                ['id' => $section->id]
661
            );
662
            $controls['permalink'] = [
663
                'url' => $sectionlink,
664
                'icon' => 'i/link',
665
                'name' => get_string('sectionlink', 'course'),
666
                'pixattr' => ['class' => ''],
667
                'attr' => [
668
                    'class' => 'icon',
669
                    'data-action' => 'permalink',
670
                ],
671
            ];
672
        }
673
 
674
        return $controls;
675
    }
676
}