Proyectos de Subversion Moodle

Rev

Rev 1298 | Rev 1300 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
256 ariadna 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
 
1298 ariadna 17
namespace theme_universe\output;
256 ariadna 18
 
19
use html_writer;
20
use stdClass;
21
use moodle_url;
22
use context_course;
23
use context_system;
24
use core_course_list_element;
25
use custom_menu;
26
use action_menu_filler;
27
use action_menu_link_secondary;
28
use action_menu;
29
use action_link;
30
use core_text;
31
use coding_exception;
32
use navigation_node;
33
use context_header;
34
use pix_icon;
35
use renderer_base;
36
use theme_config;
37
use get_string;
38
use core_course_category;
39
use theme_universe\util\user;
40
use theme_universe\util\course;
41
 
42
require_once($CFG->dirroot . '/cesa/statics_blocks.php'); // Incluimos StaticsBlocks
43
 
44
 
45
/**
46
 * Renderers to align Moodle's HTML with that expected by Bootstrap
47
 *
48
 * @package    theme_universe
49
 * @copyright  2023 Marcin Czaja (https://rosea.io)
50
 * @license    Commercial https://themeforest.net/licenses
51
 */
1298 ariadna 52
class core_renderer extends \core_renderer
1291 ariadna 53
{
54
 
1298 ariadna 55
    public function edit_button(moodle_url $url, string $method = 'post')
1295 ariadna 56
    {
1298 ariadna 57
        if ($this->page->theme->haseditswitch) {
58
            return;
59
        }
60
        $url->param('sesskey', sesskey());
61
        if ($this->page->user_is_editing()) {
62
            $url->param('edit', 'off');
63
            $editstring = get_string('turneditingoff');
64
        } else {
65
            $url->param('edit', 'on');
66
            $editstring = get_string('turneditingon');
67
        }
68
        $button = new \single_button($url, $editstring, 'post', ['class' => 'btn btn-primary']);
69
        return $this->render_single_button($button);
70
    }
1295 ariadna 71
 
1298 ariadna 72
    /**
73
     * The standard tags (meta tags, links to stylesheets and JavaScript, etc.)
74
     * that should be included in the <head> tag. Designed to be called in theme
75
     * layout.php files.
76
     *
77
     * @return string HTML fragment.
78
     */
79
    public function standard_head_html()
80
    {
81
        $output = parent::standard_head_html();
82
        global $USER;
1295 ariadna 83
 
1298 ariadna 84
        $googleanalyticscode = "<script
85
                                    async
86
                                    src='https://www.googletagmanager.com/gtag/js?id=GOOGLE-ANALYTICS-CODE'>
87
                                </script>
88
                                <script>
89
                                    window.dataLayer = window.dataLayer || [];
90
                                    function gtag() {
91
                                        dataLayer.push(arguments);
92
                                    }
93
                                    gtag('js', new Date());
94
                                    gtag('config', 'GOOGLE-ANALYTICS-CODE');
95
                                </script>";
1295 ariadna 96
 
1298 ariadna 97
        $theme = theme_config::load('universe');
1295 ariadna 98
 
1298 ariadna 99
        if (!empty($theme->settings->googleanalytics) && isloggedin()) {
100
            $output .= str_replace(
101
                "GOOGLE-ANALYTICS-CODE",
102
                trim($theme->settings->googleanalytics),
103
                $googleanalyticscode
104
            );
105
        }
1295 ariadna 106
 
1298 ariadna 107
        return $output;
108
    }
1295 ariadna 109
 
110
 
1298 ariadna 111
    /**
112
     *
113
     * Method to load theme element form 'layout/parts' folder
114
     *
115
     */
116
    public function theme_part($name, $vars = array())
117
    {
118
 
119
        global $CFG;
120
 
121
        $element = $name . '.php';
122
        $candidate1 = $this->page->theme->dir . '/layout/parts/' . $element;
123
 
124
        // Require for child theme.
125
        if (file_exists($candidate1)) {
126
            $candidate = $candidate1;
127
        } else {
128
            $candidate = $CFG->dirroot . theme_universe_themedir() . '/universe/layout/parts/' . $element;
129
        }
130
 
131
        if (!is_readable($candidate)) {
132
            debugging("Could not include element $name.");
133
            return;
134
        }
135
 
136
        ob_start();
137
        include($candidate);
138
        $output = ob_get_clean();
139
        return $output;
140
    }
141
 
142
    /**
143
     * Renders the custom menu
144
     *
145
     * @param custom_menu $menu
146
     * @return mixed
147
     */
148
    protected function render_custom_menu(custom_menu $menu)
149
    {
150
        if (!$menu->has_children()) {
1295 ariadna 151
            return '';
152
        }
153
 
1298 ariadna 154
        $content = '';
155
        foreach ($menu->get_children() as $item) {
156
            $context = $item->export_for_template($this);
157
            $content .= $this->render_from_template('core/moremenu_children', $context);
158
        }
1295 ariadna 159
 
1298 ariadna 160
        return $content;
161
    }
162
 
163
    /**
164
     * Outputs the favicon urlbase.
165
     *
166
     * @return string an url
167
     */
168
    public function favicon()
169
    {
170
        global $CFG;
171
        $theme = theme_config::load('universe');
172
        $favicon = $theme->setting_file_url('favicon', 'favicon');
173
 
174
        if (!empty(($favicon))) {
175
            $urlreplace = preg_replace('|^https?://|i', '//', $CFG->wwwroot);
176
            $favicon = str_replace($urlreplace, '', $favicon);
177
 
178
            return new moodle_url($favicon);
1295 ariadna 179
        }
180
 
1298 ariadna 181
        return parent::favicon();
182
    }
1295 ariadna 183
 
1298 ariadna 184
    public function render_lang_menu()
185
    {
186
        $langs = get_string_manager()->get_list_of_translations();
187
        $haslangmenu = $this->lang_menu() != '';
188
        $menu = new custom_menu;
1295 ariadna 189
 
1298 ariadna 190
        if ($haslangmenu) {
191
            $strlang = get_string('language');
192
            $currentlang = current_language();
193
            if (isset($langs[$currentlang])) {
194
                $currentlang = $langs[$currentlang];
195
            } else {
196
                $currentlang = $strlang;
197
            }
198
            $this->language = $menu->add($currentlang, new moodle_url('#'), $strlang, 10000);
199
            foreach ($langs as $langtype => $langname) {
200
                $this->language->add($langname, new moodle_url($this->page->url, array('lang' => $langtype)), $langname);
201
            }
202
            foreach ($menu->get_children() as $item) {
203
                $context = $item->export_for_template($this);
204
            }
1295 ariadna 205
 
1298 ariadna 206
            $context->currentlangname = array_search($currentlang, $langs);
207
 
208
            if (isset($context)) {
209
                return $this->render_from_template('theme_universe/lang_menu', $context);
1295 ariadna 210
            }
211
        }
1298 ariadna 212
    }
1295 ariadna 213
 
1298 ariadna 214
    public function render_lang_menu_login()
215
    {
216
        $langs = get_string_manager()->get_list_of_translations();
217
        $haslangmenu = $this->lang_menu() != '';
218
        $menu = new custom_menu;
1295 ariadna 219
 
1298 ariadna 220
        if ($haslangmenu) {
221
            $strlang = get_string('language');
222
            $currentlang = current_language();
223
            if (isset($langs[$currentlang])) {
224
                $currentlang = $langs[$currentlang];
225
            } else {
226
                $currentlang = $strlang;
227
            }
228
            $this->language = $menu->add($currentlang, new moodle_url('#'), $strlang, 10000);
229
            foreach ($langs as $langtype => $langname) {
230
                $this->language->add($langname, new moodle_url($this->page->url, array('lang' => $langtype)), $langname);
231
            }
232
            foreach ($menu->get_children() as $item) {
233
                $context = $item->export_for_template($this);
234
            }
1295 ariadna 235
 
1298 ariadna 236
            $context->currentlangname = array_search($currentlang, $langs);
1295 ariadna 237
 
1298 ariadna 238
            if (isset($context)) {
239
                return $this->render_from_template('theme_universe/lang_menu_login', $context);
240
            }
241
        }
242
    }
1295 ariadna 243
 
1298 ariadna 244
    public static function get_course_progress_count($course, $userid = 0)
245
    {
246
        global $USER;
1295 ariadna 247
 
1298 ariadna 248
        // Make sure we continue with a valid userid.
249
        if (empty($userid)) {
250
            $userid = $USER->id;
251
        }
1295 ariadna 252
 
1298 ariadna 253
        $completion = new \completion_info($course);
1295 ariadna 254
 
1298 ariadna 255
        // First, let's make sure completion is enabled.
256
        if (!$completion->is_enabled()) {
257
            return null;
258
        }
1295 ariadna 259
 
1298 ariadna 260
        if (!$completion->is_tracked_user($userid)) {
261
            return null;
1295 ariadna 262
        }
263
 
1298 ariadna 264
        // Before we check how many modules have been completed see if the course has.
265
        if ($completion->is_course_complete($userid)) {
266
            return 100;
267
        }
1295 ariadna 268
 
1298 ariadna 269
        // Get the number of modules that support completion.
270
        $modules = $completion->get_activities();
271
        $count = count($modules);
272
        if (!$count) {
273
            return null;
274
        }
1295 ariadna 275
 
1298 ariadna 276
        // Get the number of modules that have been completed.
277
        $completed = 0;
278
        foreach ($modules as $module) {
279
            $data = $completion->get_data($module, true, $userid);
280
            $completed += $data->completionstate == COMPLETION_INCOMPLETE ? 0 : 1;
281
        }
1295 ariadna 282
 
1298 ariadna 283
        return ($completed / $count) * 100;
284
    }
1295 ariadna 285
 
1298 ariadna 286
    /**
287
     *
288
     * Outputs the course progress if course completion is on.
289
     *
290
     * @return string Markup.
291
     */
292
    protected function courseprogress($course)
293
    {
294
        global $USER;
295
        $theme = \theme_config::load('universe');
1295 ariadna 296
 
1298 ariadna 297
        $output = '';
298
        $courseformat = course_get_format($course);
1295 ariadna 299
 
1298 ariadna 300
        if (get_class($courseformat) != 'format_tiles') {
301
            $completion = new \completion_info($course);
1295 ariadna 302
 
1298 ariadna 303
            // Start Course progress count.
304
            // Make sure we continue with a valid userid.
305
            if (empty($userid)) {
306
                $userid = $USER->id;
307
            }
308
            $completion = new \completion_info($course);
1295 ariadna 309
 
1298 ariadna 310
            // Get the number of modules that support completion.
311
            $modules = $completion->get_activities();
312
            $count = count($modules);
313
            if (!$count) {
314
                return null;
315
            }
1295 ariadna 316
 
1298 ariadna 317
            // Get the number of modules that have been completed.
318
            $completed = 0;
319
            foreach ($modules as $module) {
320
                $data = $completion->get_data($module, true, $userid);
321
                $completed += $data->completionstate == COMPLETION_INCOMPLETE ? 0 : 1;
322
            }
323
            $progresscountc = $completed;
324
            $progresscounttotal = $count;
325
            // End progress count.
1295 ariadna 326
 
1298 ariadna 327
            if ($completion->is_enabled()) {
328
                $templatedata = new \stdClass;
329
                $templatedata->progress = \core_completion\progress::get_course_progress_percentage($course);
330
                $templatedata->progresscountc = $progresscountc;
331
                $templatedata->progresscounttotal = $progresscounttotal;
332
 
333
                if (!is_null($templatedata->progress)) {
334
                    $templatedata->progress = floor($templatedata->progress);
335
                } else {
336
                    $templatedata->progress = 0;
1295 ariadna 337
                }
1298 ariadna 338
                if (get_config('theme_universe', 'courseprogressbar') == 1) {
339
                    $progressbar = '<div class="rui-course-progresschart">' .
340
                        $this->render_from_template('theme_universe/progress-chart', $templatedata) .
341
                        '</div>';
342
                    if (has_capability('report/progress:view',  \context_course::instance($course->id))) {
343
                        $courseprogress = new \moodle_url('/report/progress/index.php');
344
                        $courseprogress->param('course', $course->id);
345
                        $courseprogress->param('sesskey', sesskey());
346
                        $output .= html_writer::link($courseprogress, $progressbar, array('class' => 'rui-course-progressbar border rounded px-3 pt-2 mb-3'));
347
                    } else {
348
                        $output .= $progressbar;
349
                    }
350
                }
1295 ariadna 351
            }
1298 ariadna 352
        }
1295 ariadna 353
 
1298 ariadna 354
        return $output;
355
    }
1295 ariadna 356
 
357
 
1298 ariadna 358
    /**
359
     *
360
     * Returns HTML to display course contacts.
361
     *
362
     */
363
    public function course_teachers()
364
    {
365
        global $CFG, $COURSE, $DB;
366
        $course = $DB->get_record('course', ['id' => $COURSE->id]);
367
        $course = new core_course_list_element($course);
368
        $instructors = $course->get_course_contacts();
1295 ariadna 369
 
1298 ariadna 370
        if (!empty($instructors)) {
371
            $content = html_writer::start_div('course-teachers-box');
372
 
373
            foreach ($instructors as $key => $instructor) {
374
                $name = $instructor['username'];
375
                $role = $instructor['rolename'];
376
                $roleshortname = $instructor['role']->shortname;
377
 
378
                if ($instructor['role']->id == '3') {
379
                    $url = $CFG->wwwroot . '/user/profile.php?id=' . $key;
380
                    $user = $instructor['user'];
381
                    $userutil = new user($user->id);
382
                    $picture = $userutil->get_user_picture();
383
 
384
                    $content .= "<div class='course-contact-title-item'>
385
                        <a href='{$url}' 'title='{$name}'
386
                            class='course-contact rui-user-{$roleshortname}'>";
387
                    $content .= "<img src='{$picture}'
388
                        class='course-teacher-avatar' alt='{$name}'
389
                        title='{$name} - {$role}' data-toggle='tooltip'/>";
390
                    $content .= "<div class='course-teacher-content'>
391
                        <span class='course-teacher-role'>{$role}</span>
392
                        <h4 class='course-teacher-name'>{$name}</h4></div>";
393
                    $content .= "</a></div>";
394
                }
1295 ariadna 395
            }
396
 
1298 ariadna 397
            $content .= html_writer::end_div(); // End .teachers-box.
398
            return $content;
399
        }
400
    }
1295 ariadna 401
 
1298 ariadna 402
    public function course_contacts()
403
    {
404
        global $CFG, $COURSE, $DB;
405
        $course = $DB->get_record('course', ['id' => $COURSE->id]);
406
        $course = new core_course_list_element($course);
407
        $instructors = $course->get_course_contacts();
1295 ariadna 408
 
1298 ariadna 409
        if (!empty($instructors)) {
410
            $content = html_writer::start_div('course-teachers-box w-100');
1295 ariadna 411
 
1298 ariadna 412
            foreach ($instructors as $key => $instructor) {
413
                $name = $instructor['username'];
414
                $role = $instructor['rolename'];
415
                $roleshortname = $instructor['role']->shortname;
1295 ariadna 416
 
1298 ariadna 417
                $url = $CFG->wwwroot . '/user/profile.php?id=' . $key;
418
                $user = $instructor['user'];
419
                $userutil = new user($user->id);
420
                $picture = $userutil->get_user_picture(384);
1295 ariadna 421
 
1298 ariadna 422
                $user = $DB->get_record('user', array('id' => $key));
423
                $desc = $user->description;
1295 ariadna 424
 
1298 ariadna 425
                $content .= "<div class='rui-block-team-item text-center text-md-left
426
                    d-inline-flex flex-wrap align-items-start align-items-md-center'>";
427
                $content .= "<div class='rui-card-team--img-smpl'><img src='{$picture}'
428
                    class='rui-card-team--img-smpl mr-3 mr-md-5'
429
                    alt='{$name}, {$role}'/></div>";
430
                $content .= "<div class='rui-course-teacher--item col px-0 text-left'>
431
                    <a href='{$url}' 'title='{$name}'
432
                        class='course-contact rui-user-{$roleshortname}'>
433
                        <h4 class='mb-0'>{$name}</h4></a>
434
                        <span class='rui-block-text--3 rui-block-text--light mb-3'>{$role}</span>";
435
                $content .= "<div class='rui-block-text--2 mt-2'>{$desc}</div></div></div>";
1295 ariadna 436
            }
1298 ariadna 437
            $content .= html_writer::end_div(); // End .teachers-box.
438
            return $content;
1295 ariadna 439
        }
1298 ariadna 440
    }
1295 ariadna 441
 
1298 ariadna 442
    /**
443
     *
444
     * Returns HTML to display course details.
445
     *
446
     */
447
    protected function course_details()
448
    {
449
        global $CFG, $COURSE, $DB;
450
        $course = $DB->get_record('course', ['id' => $COURSE->id]);
451
        $course = new core_course_list_element($course);
452
        $content = '';
453
        $tempcourse = $DB->get_record('course_categories', ['id' => $COURSE->id]);
1295 ariadna 454
 
1298 ariadna 455
        $content .= html_writer::start_div('rui-course-details mt-4');
456
        $content .= html_writer::start_div('rui-custom-field-box rui-course-startdate');
457
        $content .= html_writer::tag('span', get_string('startdate', 'moodle'), ['class' => 'rui-custom-field-name']);
458
        $content .= html_writer::tag('span', date("F j, Y", $COURSE->startdate), ['class' => 'rui-custom-field-value']);
459
        $content .= html_writer::end_div();
1295 ariadna 460
 
1298 ariadna 461
        // Course End date.
462
        $courseenddate = $COURSE->enddate;
463
        if ($courseenddate != '0') {
464
            $content .= html_writer::start_div('rui-custom-field-box rui-course-startdate');
465
            $content .= html_writer::tag('span', get_string('enddate', 'moodle'), ['class' => 'rui-course-enddate-label rui-custom-field-name']);
466
            $content .= html_writer::tag('span', date("F j, Y", $courseenddate), ['class' => 'rui-course-enddate rui-custom-field-value']);
467
            $content .= html_writer::end_div();
468
        }
469
        $content .= html_writer::end_div(); // .rui-course-details.
1295 ariadna 470
 
1298 ariadna 471
        return $content;
472
    }
1295 ariadna 473
 
1298 ariadna 474
    /**
475
     *
476
     * Returns HTML to display course summary.
477
     *
478
     */
479
    protected function course_summary($courseid = 0, $content = '')
480
    {
481
        global $COURSE, $CFG;
482
        $output = '';
1295 ariadna 483
 
1298 ariadna 484
        require_once($CFG->libdir . '/filelib.php');
1295 ariadna 485
 
1298 ariadna 486
        $iscourseid = $courseid ? $courseid : $COURSE->id;
487
        $iscontent = $content ? $content : $COURSE->summary;
488
        $context = context_course::instance($iscourseid);
489
        $desc = file_rewrite_pluginfile_urls($iscontent, 'pluginfile.php', $context->id, 'course', 'summary', null);
490
 
491
        $output .= html_writer::start_div('rui-course-desc');
492
        $output .= format_text($desc, FORMAT_HTML);
493
        $output .= html_writer::end_div();
494
 
495
        return $output;
496
    }
497
 
498
    /**
499
     * Outputs the pix url base
500
     *
501
     * @return string an URL.
502
     */
503
    public function get_pix_image_url_base()
504
    {
505
        global $CFG;
506
 
507
        return $CFG->wwwroot . "/theme/universe/pix";
508
    }
509
 
510
    /**
511
     *
512
     */
513
    public function course_hero_url()
514
    {
515
        global $CFG, $COURSE, $DB;
516
 
517
        $course = $DB->get_record('course', ['id' => $COURSE->id]);
518
 
519
        $course = new core_course_list_element($course);
520
 
521
        $courseimage = '';
522
        $imageindex = 1;
523
        foreach ($course->get_course_overviewfiles() as $file) {
524
            $isimage = $file->is_valid_image();
525
 
526
            $url = new moodle_url("$CFG->wwwroot/pluginfile.php" . '/' .
527
                $file->get_contextid() . '/' . $file->get_component() . '/' .
528
                $file->get_filearea() .
529
                $file->get_filepath() .
530
                $file->get_filename(), ['forcedownload' => !$isimage]);
531
 
532
            if ($isimage) {
533
                $courseimage = $url;
1295 ariadna 534
            }
535
 
1298 ariadna 536
            if ($imageindex == 2) {
537
                break;
538
            }
1295 ariadna 539
 
1298 ariadna 540
            $imageindex++;
541
        }
1295 ariadna 542
 
1298 ariadna 543
        $html = '';
544
        // Create html for header.
545
        if (!empty($courseimage)) {
546
            $html .= $courseimage;
1295 ariadna 547
        }
1298 ariadna 548
        return $html;
549
    }
1295 ariadna 550
 
1298 ariadna 551
    /**
552
     * Returns HTML to display course hero.
553
     *
554
     */
555
    public function course_hero()
556
    {
557
        global $CFG, $COURSE, $DB;
1295 ariadna 558
 
1298 ariadna 559
        $course = $DB->get_record('course', ['id' => $COURSE->id]);
1295 ariadna 560
 
1298 ariadna 561
        $course = new core_course_list_element($course);
1295 ariadna 562
 
1298 ariadna 563
        $courseimage = '';
1295 ariadna 564
 
1298 ariadna 565
        $courseutil = new course($course);
566
        $courseimage = $courseutil->get_summary_image(false); // Remove repeatable pattern on the course page.
1295 ariadna 567
 
1298 ariadna 568
        $html = '';
569
        // Create html for header.
570
        if (!empty($courseimage)) {
571
            $html .= $courseimage;
572
        }
573
        return $html;
574
    }
1295 ariadna 575
 
576
 
577
 
578
 
1298 ariadna 579
    /**
580
     * Breadcrumbs
581
     *
582
     */
583
    public function breadcrumbs()
584
    {
585
        global $USER, $COURSE, $CFG;
1295 ariadna 586
 
1298 ariadna 587
        $header = new stdClass();
588
        $header->hasnavbar = empty($this->page->layout_options['nonavbar']);
589
        $header->navbar = $this->navbar();
590
        $header->courseheader = $this->course_header();
591
        $html = $this->render_from_template('theme_universe/breadcrumbs', $header);
592
 
593
        return $html;
594
    }
595
 
596
 
597
    /**
598
     * Wrapper for header elements.
599
     *
600
     * @return string HTML to display the main header.
601
     */
602
    public function simple_header()
603
    {
604
 
605
        global $USER, $COURSE, $CFG;
606
        $html = null;
607
 
608
        if (
609
            $this->page->include_region_main_settings_in_header_actions() &&
610
            !$this->page->blocks->is_block_present('settings')
611
        ) {
612
            // Only include the region main settings if the page has requested it and it doesn't already have
613
            // the settings block on it. The region main settings are included in the settings block and
614
            // duplicating the content causes behat failures.
615
            $this->page->add_header_action(html_writer::div(
616
                $this->region_main_settings_menu(),
617
                'd-print-none',
618
                ['id' => 'region-main-settings-menu']
619
            ));
1295 ariadna 620
        }
621
 
1298 ariadna 622
        $header = new stdClass();
623
        $header->settingsmenu = $this->context_header_settings_menu();
624
        $header->contextheader = $this->context_header();
625
        $header->hasnavbar = empty($this->page->layout_options['nonavbar']);
626
        $header->navbar = $this->navbar();
627
        $header->pageheadingbutton = $this->page_heading_button();
628
        $header->courseheader = $this->course_header();
629
        $header->headeractions = $this->page->get_header_actions();
1295 ariadna 630
 
1298 ariadna 631
        if ($this->page->pagelayout != 'admin') {
632
            $html .= $this->render_from_template('theme_universe/header', $header);
633
        }
1295 ariadna 634
 
1298 ariadna 635
        if ($this->page->pagelayout == 'admin') {
636
            $html .= $this->render_from_template('theme_universe/header_admin', $header);
637
        }
1295 ariadna 638
 
1298 ariadna 639
        return $html;
640
    }
1295 ariadna 641
 
1298 ariadna 642
    public function display_course_progress()
643
    {
644
        $html = null;
645
        $html .= $this->courseprogress($this->page->course);
646
        return $html;
647
    }
1295 ariadna 648
 
1298 ariadna 649
    /**
650
     * Wrapper for header elements.
651
     *
652
     * @return string HTML to display the main header.
653
     */
654
    public function full_header()
655
    {
656
        global $USER, $COURSE, $CFG;
657
        $theme = \theme_config::load('universe');
658
        $html = null;
659
        $pagetype = $this->page->pagetype;
660
        $homepage = get_home_page();
661
        $homepagetype = null;
662
        // Add a special case since /my/courses is a part of the /my subsystem.
663
        if ($homepage == HOMEPAGE_MY || $homepage == HOMEPAGE_MYCOURSES) {
664
            $homepagetype = 'my-index';
665
        } else if ($homepage == HOMEPAGE_SITE) {
666
            $homepagetype = 'site-index';
667
        }
668
        if (
669
            $this->page->include_region_main_settings_in_header_actions() &&
670
            !$this->page->blocks->is_block_present('settings')
671
        ) {
672
            // Only include the region main settings if the page has requested it and it doesn't already have
673
            // the settings block on it. The region main settings are included in the settings block and
674
            // duplicating the content causes behat failures.
675
            $this->page->add_header_action(html_writer::div(
676
                $this->region_main_settings_menu(),
677
                'd-print-none',
678
                ['id' => 'region-main-settings-menu']
679
            ));
680
        }
681
 
682
        $header = new stdClass();
683
        $header->settingsmenu = $this->context_header_settings_menu();
684
        $header->contextheader = $this->context_header();
685
        $header->hasnavbar = empty($this->page->layout_options['nonavbar']);
686
        $header->navbar = $this->navbar();
687
        $header->pageheadingbutton = $this->page_heading_button();
688
        $header->courseheader = $this->course_header();
689
        $header->headeractions = $this->page->get_header_actions();
690
 
691
        if ($this->page->theme->settings->ipcoursedetails == 1) {
692
            $html .= $this->course_details();
693
        }
694
 
695
        $html .= $this->render_from_template('theme_universe/header', $header);
696
        if ($this->page->theme->settings->ipcoursesummary == 1) {
697
            $html .= $this->course_summary();
698
        }
699
 
700
        $html .= html_writer::start_tag('div', array('class' => 'rui-course-header-color'));
701
        if ($this->page->theme->settings->cccteachers == 1) {
702
            $html .= $this->course_teachers();
703
        }
704
 
705
        $html .= html_writer::end_tag('div'); // End .rui-course-header.
706
 
707
        return $html;
708
    }
709
 
710
 
711
    /**
712
     * Wrapper for header elements.
713
     *
714
     * @return string HTML to display the main header.
715
     */
716
    public function clean_header()
717
    {
718
        global $USER, $COURSE, $CFG;
719
        $theme = \theme_config::load('universe');
720
        $html = null;
721
        $pagetype = $this->page->pagetype;
722
        $homepage = get_home_page();
723
        $homepagetype = null;
724
        // Add a special case since /my/courses is a part of the /my subsystem.
725
        if ($homepage == HOMEPAGE_MY || $homepage == HOMEPAGE_MYCOURSES) {
726
            $homepagetype = 'my-index';
727
        } else if ($homepage == HOMEPAGE_SITE) {
728
            $homepagetype = 'site-index';
729
        }
730
        if (
731
            $this->page->include_region_main_settings_in_header_actions() &&
732
            !$this->page->blocks->is_block_present('settings')
733
        ) {
734
            // Only include the region main settings if the page has requested it and it doesn't already have
735
            // the settings block on it. The region main settings are included in the settings block and
736
            // duplicating the content causes behat failures.
737
            $this->page->add_header_action(html_writer::div(
738
                $this->region_main_settings_menu(),
739
                'd-print-none',
740
                ['id' => 'region-main-settings-menu']
741
            ));
742
        }
743
 
744
        $header = new stdClass();
745
        $header->courseheader = $this->course_header();
746
        $header->headeractions = $this->page->get_header_actions();
747
 
748
        $html .= $this->render_from_template('theme_universe/header', $header);
749
 
750
        return $html;
751
    }
752
 
753
 
754
    /**
755
     * Returns standard navigation between activities in a course.
756
     *
757
     * @return string the navigation HTML.
758
     */
759
    public function activity_navigation()
760
    {
761
        // First we should check if we want to add navigation.
762
        $context = $this->page->context;
763
        if (($this->page->pagelayout !== 'incourse' && $this->page->pagelayout !== 'frametop')
764
            || $context->contextlevel != CONTEXT_MODULE
765
        ) {
766
            return '';
767
        }
768
        // If the activity is in stealth mode, show no links.
769
        if ($this->page->cm->is_stealth()) {
770
            return '';
771
        }
772
        $course = $this->page->cm->get_course();
773
        $courseformat = course_get_format($course);
774
 
775
        // Get a list of all the activities in the course.
776
        $modules = get_fast_modinfo($course->id)->get_cms();
777
        // Put the modules into an array in order by the position they are shown in the course.
778
        $mods = [];
779
        $activitylist = [];
780
        foreach ($modules as $module) {
781
            // Only add activities the user can access, aren't in stealth mode and have a url (eg. mod_label does not).
782
            if (!$module->uservisible || $module->is_stealth() || empty($module->url)) {
1295 ariadna 783
                continue;
784
            }
1298 ariadna 785
            $mods[$module->id] = $module;
786
            // No need to add the current module to the list for the activity dropdown menu.
787
            if ($module->id == $this->page->cm->id) {
788
                continue;
789
            }
790
            // Module name.
791
            $modname = $module->get_formatted_name();
792
            // Display the hidden text if necessary.
793
            if (!$module->visible) {
794
                $modname .= ' ' . get_string('hiddenwithbrackets');
795
            }
796
            // Module URL.
797
            $linkurl = new moodle_url($module->url, array('forceview' => 1));
798
            // Add module URL (as key) and name (as value) to the activity list array.
799
            $activitylist[$linkurl->out(false)] = $modname;
800
        }
801
        $nummods = count($mods);
802
        // If there is only one mod then do nothing.
803
        if ($nummods == 1) {
804
            return '';
805
        }
806
        // Get an array of just the course module ids used to get the cmid value based on their position in the course.
807
        $modids = array_keys($mods);
808
        // Get the position in the array of the course module we are viewing.
809
        $position = array_search($this->page->cm->id, $modids);
810
        $prevmod = null;
811
        $nextmod = null;
812
        // Check if we have a previous mod to show.
813
        if ($position > 0) {
814
            $prevmod = $mods[$modids[$position - 1]];
815
        }
816
        // Check if we have a next mod to show.
817
        if ($position < ($nummods - 1)) {
818
            $nextmod = $mods[$modids[$position + 1]];
819
        }
820
        $activitynav = new \core_course\output\activity_navigation($prevmod, $nextmod, $activitylist);
821
        $renderer = $this->page->get_renderer('core', 'course');
822
        return $renderer->render($activitynav);
823
    }
1295 ariadna 824
 
825
 
1298 ariadna 826
    /**
827
     * This is an optional menu that can be added to a layout by a theme. It contains the
828
     * menu for the course administration, only on the course main page.
829
     *
830
     * @return string
831
     */
832
    public function context_header_settings_menu()
833
    {
834
        $context = $this->page->context;
835
        $menu = new action_menu();
1295 ariadna 836
 
1298 ariadna 837
        $items = $this->page->navbar->get_items();
838
        $currentnode = end($items);
839
 
840
        $showcoursemenu = false;
841
        $showfrontpagemenu = false;
842
        $showusermenu = false;
843
 
844
        // We are on the course home page.
845
        if (($context->contextlevel == CONTEXT_COURSE) &&
846
            !empty($currentnode) &&
847
            ($currentnode->type == navigation_node::TYPE_COURSE || $currentnode->type == navigation_node::TYPE_SECTION)
848
        ) {
849
            $showcoursemenu = true;
850
        }
851
 
852
        $courseformat = course_get_format($this->page->course);
853
        // This is a single activity course format, always show the course menu on the activity main page.
854
        if (
855
            $context->contextlevel == CONTEXT_MODULE &&
856
            !$courseformat->has_view_page()
857
        ) {
858
 
859
            $this->page->navigation->initialise();
860
            $activenode = $this->page->navigation->find_active_node();
861
            // If the settings menu has been forced then show the menu.
862
            if ($this->page->is_settings_menu_forced()) {
863
                $showcoursemenu = true;
864
            } else if (!empty($activenode) && ($activenode->type == navigation_node::TYPE_ACTIVITY ||
865
                $activenode->type == navigation_node::TYPE_RESOURCE)) {
866
 
867
                // We only want to show the menu on the first page of the activity. This means
868
                // the breadcrumb has no additional nodes.
869
                if ($currentnode && ($currentnode->key == $activenode->key && $currentnode->type == $activenode->type)) {
870
                    $showcoursemenu = true;
1295 ariadna 871
                }
1298 ariadna 872
            }
873
        }
1295 ariadna 874
 
1298 ariadna 875
        // This is the site front page.
876
        if (
877
            $context->contextlevel == CONTEXT_COURSE &&
878
            !empty($currentnode) &&
879
            $currentnode->key === 'home'
880
        ) {
881
            $showfrontpagemenu = true;
882
        }
883
 
884
        // This is the user profile page.
885
        if (
886
            $context->contextlevel == CONTEXT_USER &&
887
            !empty($currentnode) &&
888
            ($currentnode->key === 'myprofile')
889
        ) {
890
            $showusermenu = true;
891
        }
892
 
893
        if ($showfrontpagemenu) {
894
            $settingsnode = $this->page->settingsnav->find('frontpage', navigation_node::TYPE_SETTING);
895
            if ($settingsnode) {
896
                // Build an action menu based on the visible nodes from this navigation tree.
897
                $skipped = $this->build_action_menu_from_navigation($menu, $settingsnode, false, true);
898
 
899
                // We only add a list to the full settings menu if we didn't include every node in the short menu.
900
                if ($skipped) {
901
                    $text = get_string('morenavigationlinks');
902
                    $url = new moodle_url('/course/admin.php', array('courseid' => $this->page->course->id));
903
                    $link = new action_link($url, $text, null, null, new pix_icon('t/edit', $text));
904
                    $menu->add_secondary_action($link);
1295 ariadna 905
                }
1298 ariadna 906
            }
907
        } else if ($showcoursemenu) {
908
            $settingsnode = $this->page->settingsnav->find('courseadmin', navigation_node::TYPE_COURSE);
909
            if ($settingsnode) {
910
                // Build an action menu based on the visible nodes from this navigation tree.
911
                $skipped = $this->build_action_menu_from_navigation($menu, $settingsnode, false, true);
1295 ariadna 912
 
1298 ariadna 913
                // We only add a list to the full settings menu if we didn't include every node in the short menu.
914
                if ($skipped) {
915
                    $text = get_string('morenavigationlinks');
916
                    $url = new moodle_url('/course/admin.php', array('courseid' => $this->page->course->id));
917
                    $link = new action_link($url, $text, null, null, new pix_icon('t/edit', $text));
918
                    $menu->add_secondary_action($link);
919
                }
920
            }
921
        } else if ($showusermenu) {
922
            // Get the course admin node from the settings navigation.
923
            $settingsnode = $this->page->settingsnav->find('useraccount', navigation_node::TYPE_CONTAINER);
924
            if ($settingsnode) {
925
                // Build an action menu based on the visible nodes from this navigation tree.
926
                $this->build_action_menu_from_navigation($menu, $settingsnode);
927
            }
928
        }
1295 ariadna 929
 
1298 ariadna 930
        return $this->render($menu);
931
    }
1295 ariadna 932
 
1298 ariadna 933
    public function customeditblockbtn()
934
    {
935
        $header = new stdClass();
936
        $header->settingsmenu = $this->context_header_settings_menu();
937
        $header->pageheadingbutton = $this->page_heading_button();
1295 ariadna 938
 
1298 ariadna 939
        $html = $this->render_from_template('theme_universe/header_settings_menu', $header);
1295 ariadna 940
 
1298 ariadna 941
        return $html;
942
    }
1295 ariadna 943
 
1298 ariadna 944
    /**
945
     * Renders the context header for the page.
946
     *
947
     * @param array $headerinfo Heading information.
948
     * @param int $headinglevel What 'h' level to make the heading.
949
     * @return string A rendered context header.
950
     */
951
    public function context_header($headerinfo = null, $headinglevel = 1): string
952
    {
953
        global $DB, $USER, $CFG, $SITE;
954
        require_once($CFG->dirroot . '/user/lib.php');
955
        $context = $this->page->context;
956
        $heading = null;
957
        $imagedata = null;
958
        $subheader = null;
959
        $userbuttons = null;
1295 ariadna 960
 
1298 ariadna 961
        // Make sure to use the heading if it has been set.
962
        if (isset($headerinfo['heading'])) {
963
            $heading = $headerinfo['heading'];
964
        } else {
965
            $heading = $this->page->heading;
966
        }
1295 ariadna 967
 
1298 ariadna 968
        // The user context currently has images and buttons. Other contexts may follow.
969
        if ((isset($headerinfo['user']) || $context->contextlevel == CONTEXT_USER) && $this->page->pagetype !== 'my-index') {
970
            if (isset($headerinfo['user'])) {
971
                $user = $headerinfo['user'];
972
            } else {
973
                // Look up the user information if it is not supplied.
974
                $user = $DB->get_record('user', array('id' => $context->instanceid));
975
            }
1295 ariadna 976
 
1298 ariadna 977
            // If the user context is set, then use that for capability checks.
978
            if (isset($headerinfo['usercontext'])) {
979
                $context = $headerinfo['usercontext'];
980
            }
1295 ariadna 981
 
1298 ariadna 982
            // Only provide user information if the user is the current user, or a user which the current user can view.
983
            // When checking user_can_view_profile(), either:
984
            // If the page context is course, check the course context (from the page object) or;
985
            // If page context is NOT course, then check across all courses.
986
            $course = ($this->page->context->contextlevel == CONTEXT_COURSE) ? $this->page->course : null;
1295 ariadna 987
 
1298 ariadna 988
            if (user_can_view_profile($user, $course)) {
989
                // Use the user's full name if the heading isn't set.
990
                if (empty($heading)) {
991
                    $heading = fullname($user);
992
                }
1295 ariadna 993
 
1298 ariadna 994
                $imagedata = $this->user_picture($user, array('size' => 100));
1295 ariadna 995
 
1298 ariadna 996
                // Check to see if we should be displaying a message button.
997
                if (!empty($CFG->messaging) && has_capability('moodle/site:sendmessage', $context)) {
998
                    $userbuttons = array(
999
                        'messages' => array(
1000
                            'buttontype' => 'message',
1001
                            'title' => get_string('message', 'message'),
1002
                            'url' => new moodle_url('/message/index.php', array('id' => $user->id)),
1003
                            'image' => 'message',
1004
                            'linkattributes' => \core_message\helper::messageuser_link_params($user->id),
1005
                            'page' => $this->page
1006
                        )
1007
                    );
1008
 
1009
                    if ($USER->id != $user->id) {
1010
                        $iscontact = \core_message\api::is_contact($USER->id, $user->id);
1011
                        $contacttitle = $iscontact ? 'removefromyourcontacts' : 'addtoyourcontacts';
1012
                        $contacturlaction = $iscontact ? 'removecontact' : 'addcontact';
1013
                        $contactimage = $iscontact ? 'removecontact' : 'addcontact';
1014
                        $userbuttons['togglecontact'] = array(
1015
                            'buttontype' => 'togglecontact',
1016
                            'title' => get_string($contacttitle, 'message'),
1017
                            'url' => new moodle_url(
1018
                                '/message/index.php',
1019
                                array(
1020
                                    'user1' => $USER->id,
1021
                                    'user2' => $user->id,
1022
                                    $contacturlaction => $user->id,
1023
                                    'sesskey' => sesskey()
1024
                                )
1025
                            ),
1026
                            'image' => $contactimage,
1027
                            'linkattributes' => \core_message\helper::togglecontact_link_params($user, $iscontact),
1028
                            'page' => $this->page
1029
                        );
1295 ariadna 1030
                    }
1298 ariadna 1031
 
1032
                    $this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
1295 ariadna 1033
                }
1298 ariadna 1034
            } else {
1035
                $heading = null;
1036
            }
1037
        }
1295 ariadna 1038
 
1298 ariadna 1039
        $prefix = null;
1040
        if ($context->contextlevel == CONTEXT_MODULE) {
1041
            if ($this->page->course->format === 'singleactivity') {
1042
                $heading = $this->page->course->fullname;
1043
            } else {
1044
                $heading = $this->page->cm->get_formatted_name();
1045
                $imagedata = $this->pix_icon('monologo', '', $this->page->activityname, ['class' => 'activityicon']);
1046
                $purposeclass = plugin_supports('mod', $this->page->activityname, FEATURE_MOD_PURPOSE);
1047
                $purposeclass .= ' activityiconcontainer';
1048
                $purposeclass .= ' modicon_' . $this->page->activityname;
1049
                $imagedata = html_writer::tag('div', $imagedata, ['class' => $purposeclass]);
1050
                $prefix = get_string('modulename', $this->page->activityname);
1051
            }
1052
        }
1295 ariadna 1053
 
1298 ariadna 1054
        $contextheader = new \context_header($heading, $headinglevel, $imagedata, $userbuttons, $prefix);
1055
        return $this->render_context_header($contextheader);
1056
    }
1295 ariadna 1057
 
1058
 
1298 ariadna 1059
    /**
1060
     * Construct a user menu, returning HTML that can be echoed out by a
1061
     * layout file.
1062
     *
1063
     * @param stdClass $user A user object, usually $USER.
1064
     * @param bool $withlinks true if a dropdown should be built.
1065
     * @return string HTML fragment.
1066
     */
1067
    public function user_menu($user = null, $withlinks = null)
1068
    {
1069
        global $USER, $CFG;
1070
        require_once($CFG->dirroot . '/user/lib.php');
1071
 
1072
        if (is_null($user)) {
1073
            $user = $USER;
1074
        }
1075
 
1076
        // Note: this behaviour is intended to match that of core_renderer::login_info,
1077
        // but should not be considered to be good practice; layout options are
1078
        // intended to be theme-specific. Please don't copy this snippet anywhere else.
1079
        if (is_null($withlinks)) {
1080
            $withlinks = empty($this->page->layout_options['nologinlinks']);
1081
        }
1082
 
1083
        // Add a class for when $withlinks is false.
1084
        $usermenuclasses = 'usermenu';
1085
        if (!$withlinks) {
1086
            $usermenuclasses .= ' withoutlinks';
1087
        }
1088
 
1089
        $returnstr = "";
1090
 
1091
        // If during initial install, return the empty return string.
1092
        if (during_initial_install()) {
1093
            return $returnstr;
1094
        }
1095
 
1096
        $loginpage = $this->is_login_page();
1097
        $loginurl = get_login_url();
1098
        // If not logged in, show the typical not-logged-in string.
1099
        if (!isloggedin()) {
1100
            if (!$loginpage) {
1101
                $returnstr .= "<a class=\"rui-topbar-btn rui-login-btn\" href=\"$loginurl\"><span class=\"rui-login-btn-txt\">" .
1102
                    get_string('login') .
1103
                    '</span>
1104
                <svg class="ml-2" width="20" height="20" fill="none" viewBox="0 0 24 24">
1105
                <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
1106
                d="M9.75 8.75L13.25 12L9.75 15.25"></path>
1107
                <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
1108
                d="M9.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25 6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H9.75">
1109
                </path>
1110
                <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 12H4.75"></path>
1111
                </svg></a>';
1112
            }
1113
            return html_writer::div(
1114
                html_writer::span(
1115
                    $returnstr,
1116
                    'login'
1117
                ),
1118
                $usermenuclasses
1119
            );
1120
        }
1121
 
1122
        // If logged in as a guest user, show a string to that effect.
1123
        if (isguestuser()) {
1124
            $icon = '<svg class="mr-2"
1125
                width="24"
1126
                height="24"
1127
                viewBox="0 0 24 24"
1128
                fill="none"
1129
                xmlns="http://www.w3.org/2000/svg">
1130
            <path d="M10 12C10 12.5523 9.55228 13 9 13C8.44772 13 8 12.5523 8
1131
            12C8 11.4477 8.44772 11 9 11C9.55228 11 10 11.4477 10 12Z"
1132
                fill="currentColor"
1133
                />
1134
            <path d="M15 13C15.5523 13 16 12.5523 16 12C16 11.4477 15.5523 11
1135
            15 11C14.4477 11 14 11.4477 14 12C14 12.5523 14.4477 13 15 13Z"
1136
                fill="currentColor"
1137
                />
1138
            <path fill-rule="evenodd"
1139
                clip-rule="evenodd"
1140
                d="M12.0244 2.00003L12 2C6.47715 2 2 6.47715 2 12C2 17.5228
1141
                6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.74235
1142
            17.9425 2.43237 12.788 2.03059L12.7886 2.0282C12.5329 2.00891
1143
            12.278 1.99961 12.0244 2.00003ZM12 20C16.4183 20 20 16.4183 20
1144
            12C20 11.3014 19.9105 10.6237 19.7422
1145
            9.97775C16.1597 10.2313 12.7359 8.52461 10.7605 5.60246C9.31322
1146
            7.07886 7.2982 7.99666 5.06879 8.00253C4.38902 9.17866 4 10.5439 4
1147
            12C4 16.4183 7.58172 20
1148
            12 20ZM11.9785 4.00003L12.0236 4.00003L12 4L11.9785 4.00003Z"
1149
                fill="currentColor"
1150
                /></svg>';
1151
            $returnstr = '<div class="rui-badge-guest">' . $icon . get_string('loggedinasguest') . '</div>';
1152
            if (!$loginpage && $withlinks) {
1153
                $returnstr .= "<a class=\"rui-topbar-btn rui-login-btn\"
1154
                    href=\"$loginurl\"><span class=\"rui-login-btn-txt\">" .
1155
                    get_string('login') .
1156
                    '</span>
1157
                <svg class="ml-2"
1158
                    width="20"
1159
                    height="20"
1160
                    fill="none"
1161
                    viewBox="0 0 24 24">
1162
                <path stroke="currentColor"
1163
                    stroke-linecap="round"
1164
                    stroke-linejoin="round"
1165
                    stroke-width="2"
1166
                    d="M9.75 8.75L13.25 12L9.75 15.25"></path>
1167
                <path stroke="currentColor"
1168
                    stroke-linecap="round"
1169
                    stroke-linejoin="round"
1170
                    stroke-width="2"
1171
                    d="M9.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25
1172
                    6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H9.75"></path>
1173
                    <path stroke="currentColor"
1174
                        stroke-linecap="round"
1175
                        stroke-linejoin="round"
1176
                        stroke-width="2"
1177
                        d="M13 12H4.75"></path></svg></a>';
1178
            }
1179
 
1180
            return html_writer::div(
1181
                html_writer::span(
1182
                    $returnstr,
1183
                    'login'
1184
                ),
1185
                $usermenuclasses
1186
            );
1187
        }
1188
 
1189
        // Get some navigation opts.
1190
        $opts = user_get_user_navigation_info($user, $this->page, array('avatarsize' => 56));
1191
 
1192
        $avatarclasses = "avatars";
1193
        $avatarcontents = html_writer::span($opts->metadata['useravatar'], 'avatar current');
1194
        $usertextcontents = '<span class="rui-fullname">' . $opts->metadata['userfullname'] . '</span>';
1195
        $usertextmail = $user->email;
1196
        $usernick = '<svg class="mr-1"
1197
            width="16"
1198
            height="16"
1199
            fill="none"
1200
            viewBox="0 0 24 24">
1201
        <path stroke="currentColor"
1202
            stroke-linecap="round"
1203
            stroke-linejoin="round"
1204
            stroke-width="2"
1205
            d="M12 13V15"></path>
1206
        <circle cx="12"
1207
            cy="9"
1208
            r="1"
1209
            fill="currentColor"></circle>
1210
        <circle cx="12"
1211
            cy="12"
1212
            r="7.25"
1213
            stroke="currentColor"
1214
            stroke-linecap="round"
1215
            stroke-linejoin="round"
1216
            stroke-width="1.5"></circle>
1217
        </svg>' . $user->username;
1218
 
1219
        // Other user.
1220
        $usermeta = '';
1221
        if (!empty($opts->metadata['asotheruser'])) {
1222
            $avatarcontents .= html_writer::span(
1223
                $opts->metadata['realuseravatar'],
1224
                'avatar realuser'
1225
            );
1226
            $usermeta .= $opts->metadata['realuserfullname'];
1227
            $usermeta .= html_writer::tag(
1228
                'span',
1229
                get_string(
1230
                    'loggedinas',
1231
                    'moodle',
1232
                    html_writer::span(
1233
                        $opts->metadata['userfullname'],
1234
                        'value'
1235
                    )
1236
                ),
1237
                array('class' => 'meta viewingas')
1238
            );
1239
        }
1240
 
1241
        // Role.
1242
        if (!empty($opts->metadata['asotherrole'])) {
1243
            $role = core_text::strtolower(preg_replace('#[ ]+#', '-', trim($opts->metadata['rolename'])));
1244
            $usermeta .= html_writer::span(
1245
                $opts->metadata['rolename'],
1246
                'meta role role-' . $role
1247
            );
1248
        }
1249
 
1250
        // User login failures.
1251
        if (!empty($opts->metadata['userloginfail'])) {
1252
            $usermeta .= html_writer::div(
1253
                '<svg class="mr-1"
1254
                width="16"
1255
                height="16"
1256
                fill="none"
1257
                viewBox="0 0 24 24"><path stroke="currentColor"
1258
                stroke-linecap="round"
1259
                stroke-linejoin="round"
1260
                stroke-width="1.5"
1261
                d="M4.9522 16.3536L10.2152 5.85658C10.9531 4.38481 13.0539
1262
                4.3852 13.7913 5.85723L19.0495 16.3543C19.7156 17.6841 18.7487
1263
                19.25 17.2613 19.25H6.74007C5.25234
1264
                19.25 4.2854 17.6835 4.9522 16.3536Z">
1265
                </path><path stroke="currentColor"
1266
                stroke-linecap="round"
1267
                stroke-linejoin="round"
1268
                stroke-width="2"
1269
                d="M12 10V12"></path>
1270
                <circle cx="12" cy="16" r="1" fill="currentColor"></circle></svg>' .
1271
                    $opts->metadata['userloginfail'],
1272
                'meta loginfailures'
1273
            );
1274
        }
1275
 
1276
        // MNet.
1277
        if (!empty($opts->metadata['asmnetuser'])) {
1278
            $mnet = strtolower(preg_replace('#[ ]+#', '-', trim($opts->metadata['mnetidprovidername'])));
1279
            $usermeta .= html_writer::span(
1280
                $opts->metadata['mnetidprovidername'],
1281
                'meta mnet mnet-' . $mnet
1282
            );
1283
        }
1284
 
1285
        $returnstr .= html_writer::span(
1286
            html_writer::span($avatarcontents, $avatarclasses),
1287
            'userbutton'
1288
        );
1289
 
1290
        // Create a divider (well, a filler).
1291
        $divider = new action_menu_filler();
1292
        $divider->primary = false;
1293
 
1294
        $am = new action_menu();
1295
        $am->set_menu_trigger(
1296
            $returnstr
1297
        );
1298
        $am->set_action_label(get_string('usermenu'));
1299
        $am->set_nowrap_on_items();
1300
 
1301
        if ($CFG->enabledashboard) {
1302
            $dashboardlink = '<div class="dropdown-item-wrapper"><a class="dropdown-item" href="' .
1303
                new moodle_url('/my/') .
1304
                '" data-identifier="dashboard,moodle" title="dashboard,moodle">' .
1305
                get_string('myhome', 'moodle') .
1306
                '</a></div>';
1307
        } else {
1308
            $dashboardlink = null;
1309
        }
1310
 
1311
        $am->add(
1312
            '<div class="dropdown-user-wrapper"><div class="dropdown-user">' . $usertextcontents  . '</div>'
1313
                . '<div class="dropdown-user-mail text-truncate" title="' . $usertextmail . '">' . $usertextmail . '</div>'
1314
                . '<span class="dropdown-user-nick w-100">' . $usernick . '</span>'
1315
                . '<div class="dropdown-user-meta"><span class="badge-xs badge-sq badge-warning flex-wrap">' .
1316
                $usermeta . '</span></div>'
1317
                . '</div><div class="dropdown-divider dropdown-divider-user"></div>' . $dashboardlink
1318
        );
1319
 
1320
        if ($withlinks) {
1321
            $navitemcount = count($opts->navitems);
1322
            $idx = 0;
1323
            foreach ($opts->navitems as $key => $value) {
1324
 
1325
                switch ($value->itemtype) {
1326
                    case 'divider':
1327
                        // If the nav item is a divider, add one and skip link processing.
1328
                        $am->add($divider);
1329
                        break;
1330
 
1331
                    case 'invalid':
1332
                        // Silently skip invalid entries (should we post a notification?).
1333
                        break;
1334
 
1335
                    case 'link':
1336
                        $al = '<a class="dropdown-item" href="' .
1337
                            $value->url .
1338
                            '" data-identifier="' .
1339
                            $value->titleidentifier .
1340
                            '" title="' .
1341
                            $value->titleidentifier .
1342
                            '">' .
1343
                            $value->title . '</a>';
1344
                        $am->add($al);
1345
                        break;
1295 ariadna 1346
                }
1347
 
1298 ariadna 1348
                $idx++;
1295 ariadna 1349
 
1298 ariadna 1350
                // Add dividers after the first item and before the last item.
1351
                if ($idx == 1 || $idx == $navitemcount - 1) {
1352
                    $am->add($divider);
1295 ariadna 1353
                }
1298 ariadna 1354
            }
1355
        }
1295 ariadna 1356
 
1298 ariadna 1357
        return html_writer::div(
1358
            $this->render($am),
1359
            $usermenuclasses
1360
        );
1361
    }
1362
 
1363
 
1364
    /**
1365
     * Returns standard main content placeholder.
1366
     * Designed to be called in theme layout.php files.
1367
     *
1368
     * @return string HTML fragment.
1369
     */
1370
    public function main_content()
1371
    {
1372
        // This is here because it is the only place we can inject the "main" role over the entire main content area
1373
        // without requiring all theme's to manually do it, and without creating yet another thing people need to
1374
        // remember in the theme.
1375
        // This is an unfortunate hack. DO NO EVER add anything more here.
1376
        // DO NOT add classes.
1377
        // DO NOT add an id.
1378
        return '<div class="main-content" role="main">' . $this->unique_main_content_token . '</div>';
1379
    }
1380
 
1381
    /**
1382
     * Outputs a heading
1383
     *
1384
     * @param string $text The text of the heading
1385
     * @param int $level The level of importance of the heading. Defaulting to 2
1386
     * @param string $classes A space-separated list of CSS classes. Defaulting to null
1387
     * @param string $id An optional ID
1388
     * @return string the HTML to output.
1389
     */
1390
    public function heading($text, $level = 2, $classes = null, $id = null)
1391
    {
1392
        $level = (int) $level;
1393
        if ($level < 1 || $level > 6) {
1394
            throw new coding_exception('Heading level must be an integer between 1 and 6.');
1395
        }
1396
        return html_writer::tag('div', html_writer::tag('h' .
1397
            $level, $text, array('id' => $id, 'class' => renderer_base::prepare_classes($classes) .
1398
            ' rui-main-content-title rui-main-content-title--h' .
1399
            $level)), array('class' => 'rui-title-container'));
1400
    }
1401
 
1402
 
1403
    public function headingwithavatar($text, $level = 2, $classes = null, $id = null)
1404
    {
1405
        $level = (int) $level;
1406
        if ($level < 1 || $level > 6) {
1407
            throw new coding_exception('Heading level must be an integer between 1 and 6.');
1408
        }
1409
        return html_writer::tag('div', html_writer::tag('h' .
1410
            $level, $text, array('id' => $id, 'class' => renderer_base::prepare_classes($classes) .
1411
            ' rui-main-content-title-with-avatar')), array('class' => 'rui-title-container-with-avatar'));
1412
    }
1413
 
1414
    /**
1415
     * Renders the login form.
1416
     *
1417
     * @param \core_auth\output\login $form The renderable.
1418
     * @return string
1419
     */
1420
    public function render_login(\core_auth\output\login $form)
1421
    {
1422
        global $CFG, $SITE;
1423
 
1424
        $context = $form->export_for_template($this);
1425
 
1426
        // Override because rendering is not supported in template yet.
1427
        if ($CFG->rememberusername == 0) {
1428
            $context->cookieshelpiconformatted = $this->help_icon('cookiesenabledonlysession');
1429
        } else {
1430
            $context->cookieshelpiconformatted = $this->help_icon('cookiesenabled');
1431
        }
1432
        $context->errorformatted = $this->error_text($context->error);
1433
        $url = $this->get_logo_url();
1434
        if ($url) {
1435
            $url = $url->out(false);
1436
        }
1437
        $context->logourl = $url;
1438
        $context->sitename = format_string(
1439
            $SITE->fullname,
1440
            true,
1441
            ['context' => context_course::instance(SITEID), "escape" => false]
1442
        );
1443
 
1444
        if ($this->page->theme->settings->setloginlayout == 1) {
1445
            $context->loginlayout1 = 1;
1446
        } else if ($this->page->theme->settings->setloginlayout == 2) {
1447
            $context->loginlayout2 = 1;
1448
            if (isset($this->page->theme->settings->loginbg)) {
1449
                $context->loginlayoutimg = 1;
1295 ariadna 1450
            }
1298 ariadna 1451
        } else if ($this->page->theme->settings->setloginlayout == 3) {
1452
            $context->loginlayout3 = 1;
1453
            if (isset($this->page->theme->settings->loginbg)) {
1454
                $context->loginlayoutimg = 1;
1455
            }
1456
        } else if ($this->page->theme->settings->setloginlayout == 4) {
1457
            $context->loginlayout4 = 1;
1458
        } else if ($this->page->theme->settings->setloginlayout == 5) {
1459
            $context->loginlayout5 = 1;
1460
        }
1295 ariadna 1461
 
1298 ariadna 1462
        if (isset($this->page->theme->settings->loginlogooutside)) {
1463
            $context->loginlogooutside = $this->page->theme->settings->loginlogooutside;
1464
        }
1295 ariadna 1465
 
1298 ariadna 1466
        if (isset($this->page->theme->settings->customsignupoutside)) {
1467
            $context->customsignupoutside = $this->page->theme->settings->customsignupoutside;
1468
        }
1295 ariadna 1469
 
1298 ariadna 1470
        if (isset($this->page->theme->settings->loginidprovtop)) {
1471
            $context->loginidprovtop = $this->page->theme->settings->loginidprovtop;
1472
        }
1473
 
1474
        if (isset($this->page->theme->settings->stringca)) {
1475
            $context->stringca = format_text(($this->page->theme->settings->stringca),
1476
                FORMAT_HTML,
1477
                array('noclean' => true)
1478
            );
1479
        }
1480
 
1481
        if (isset($this->page->theme->settings->stringca)) {
1482
            $context->stringca = format_text(($this->page->theme->settings->stringca),
1483
                FORMAT_HTML,
1484
                array('noclean' => true)
1485
            );
1486
        }
1487
 
1488
        if (isset($this->page->theme->settings->loginhtmlcontent1)) {
1489
            $context->loginhtmlcontent1 = format_text(($this->page->theme->settings->loginhtmlcontent1),
1490
                FORMAT_HTML,
1491
                array('noclean' => true)
1492
            );
1493
        }
1494
 
1495
        if (isset($this->page->theme->settings->loginhtmlcontent2)) {
1496
            $context->loginhtmlcontent2 = format_text(($this->page->theme->settings->loginhtmlcontent2),
1497
                FORMAT_HTML,
1498
                array('noclean' => true)
1499
            );
1500
        }
1501
 
1502
        if (isset($this->page->theme->settings->loginhtmlcontent3)) {
1503
            $context->loginhtmlcontent3 = format_text(($this->page->theme->settings->loginhtmlcontent3),
1504
                FORMAT_HTML,
1505
                array('noclean' => true)
1506
            );
1507
        }
1508
 
1509
        if (isset($this->page->theme->settings->loginhtmlcontent2)) {
1510
            $context->loginhtmlcontent2 = format_text(($this->page->theme->settings->loginhtmlcontent2),
1511
                FORMAT_HTML,
1512
                array('noclean' => true)
1513
            );
1514
        }
1515
 
1516
        if (isset($this->page->theme->settings->logincustomfooterhtml)) {
1517
            $context->logincustomfooterhtml = format_text(($this->page->theme->settings->logincustomfooterhtml),
1518
                FORMAT_HTML,
1519
                array('noclean' => true)
1520
            );
1521
        }
1522
 
1523
        if (isset($this->page->theme->settings->loginhtmlblockbottom)) {
1524
            $context->loginhtmlblockbottom = format_text(($this->page->theme->settings->loginhtmlblockbottom),
1525
                FORMAT_HTML,
1526
                array('noclean' => true)
1527
            );
1528
        }
1529
 
1530
        if (isset($this->page->theme->settings->loginfootercontent)) {
1531
            $context->loginfootercontent = format_text(($this->page->theme->settings->loginfootercontent),
1532
                FORMAT_HTML,
1533
                array('noclean' => true)
1534
            );
1535
        }
1536
 
1537
        if (isset($this->page->theme->settings->footercopy)) {
1538
            $context->footercopy = format_text(($this->page->theme->settings->footercopy),
1539
                FORMAT_HTML,
1540
                array('noclean' => true)
1541
            );
1542
        }
1543
 
1544
        if (isset($this->page->theme->settings->loginintrotext)) {
1545
            $context->loginintrotext = format_text(($this->page->theme->settings->loginintrotext),
1546
                FORMAT_HTML,
1547
                array('noclean' => true)
1548
            );
1549
        }
1550
 
1551
        if (isset($this->page->theme->settings->loginintrotext)) {
1552
            $context->loginintrotext = format_text(($this->page->theme->settings->loginintrotext),
1553
                FORMAT_HTML,
1554
                array('noclean' => true)
1555
            );
1556
        }
1557
 
1558
        if (isset($this->page->theme->settings->customloginlogo)) {
1559
            $context->customloginlogo = $this->page->theme->setting_file_url('customloginlogo', 'customloginlogo');
1560
        }
1561
 
1562
        if (isset($this->page->theme->settings->loginbg)) {
1563
            $context->loginbg = $this->page->theme->setting_file_url('loginbg', 'loginbg');
1564
        }
1565
 
1566
        if (isset($this->page->theme->settings->hideforgotpassword)) {
1567
            $context->hideforgotpassword = $this->page->theme->settings->hideforgotpassword == 1;
1568
        }
1569
 
1570
        if (isset($this->page->theme->settings->logininfobox)) {
1571
            $context->logininfobox = format_text(($this->page->theme->settings->logininfobox),
1572
                FORMAT_HTML,
1573
                array('noclean' => true)
1574
            );
1575
        }
1576
 
1577
        return $this->render_from_template('core/loginform', $context);
1578
    }
1579
 
1580
    /**
1581
     * Render the login signup form into a nice template for the theme.
1582
     *
1583
     * @param mform $form
1584
     * @return string
1585
     */
1586
    public function render_login_signup_form($form)
1587
    {
1588
        global $SITE;
1589
 
1590
        $context = $form->export_for_template($this);
1591
        $url = $this->get_logo_url();
1592
        if ($url) {
1593
            $url = $url->out(false);
1594
        }
1595
        $context['logourl'] = $url;
1596
        $context['sitename'] = format_string(
1597
            $SITE->fullname,
1598
            true,
1599
            ['context' => context_course::instance(SITEID), "escape" => false]
1600
        );
1601
 
1602
        if ($this->page->theme->settings->setloginlayout == 1) {
1603
            $context['loginlayout1'] = 1;
1604
        } else if ($this->page->theme->settings->setloginlayout == 2) {
1605
            $context['loginlayout2'] = 1;
1606
            if (isset($this->page->theme->settings->loginbg)) {
1607
                $context['loginlayoutimg'] = 1;
1608
            }
1609
        } else if ($this->page->theme->settings->setloginlayout == 3) {
1610
            $context['loginlayout3'] = 1;
1611
            if (isset($this->page->theme->settings->loginbg)) {
1612
                $context['loginlayoutimg'] = 1;
1613
            }
1614
        } else if ($this->page->theme->settings->setloginlayout == 4) {
1615
            $context['loginlayout4'] = 1;
1616
        } else if ($this->page->theme->settings->setloginlayout == 5) {
1617
            $context['loginlayout5'] = 1;
1618
        }
1619
 
1620
        if (isset($this->page->theme->settings->loginlogooutside)) {
1621
            $context['loginlogooutside'] = $this->page->theme->settings->loginlogooutside;
1622
        }
1623
 
1624
        if (isset($this->page->theme->settings->stringbacktologin)) {
1625
            $context['stringbacktologin'] = format_text(($this->page->theme->settings->stringbacktologin),
1626
                FORMAT_HTML,
1627
                array('noclean' => true)
1628
            );
1629
        }
1630
        if (isset($this->page->theme->settings->signupintrotext)) {
1631
            $context['signupintrotext'] = format_text(($this->page->theme->settings->signupintrotext),
1632
                FORMAT_HTML,
1633
                array('noclean' => true)
1634
            );
1635
        }
1636
        if (isset($this->page->theme->settings->signuptext)) {
1637
            $context['signuptext'] = format_text(($this->page->theme->settings->signuptext),
1638
                FORMAT_HTML,
1639
                array('noclean' => true)
1640
            );
1641
        }
1642
 
1643
        if (!empty($this->page->theme->settings->customloginlogo)) {
1644
            $url = $this->page->theme->setting_file_url('customloginlogo', 'customloginlogo');
1645
            $context['customloginlogo'] = $url;
1646
        }
1647
 
1648
        if (!empty($this->page->theme->settings->loginbg)) {
1649
            $url = $this->page->theme->setting_file_url('loginbg', 'loginbg');
1650
            $context['loginbg'] = $url;
1651
        }
1652
 
1653
        if (isset($this->page->theme->settings->loginfootercontent)) {
1654
            $context['loginfootercontent'] = format_text(($this->page->theme->settings->loginfootercontent),
1655
                FORMAT_HTML,
1656
                array('noclean' => true)
1657
            );
1658
        }
1659
 
1660
        return $this->render_from_template('core/signup_form_layout', $context);
1661
    }
1662
 
1663
 
1664
    /**
1665
     * Renders the header bar.
1666
     *
1667
     * @param context_header $contextheader Header bar object.
1668
     * @return string HTML for the header bar.
1669
     */
1670
    protected function render_context_header(\context_header $contextheader)
1671
    {
1672
        $heading = null;
1673
        $imagedata = null;
1674
        $html = null;
1675
 
1676
        // Generate the heading first and before everything else as we might have to do an early return.
1677
        if (!isset($contextheader->heading)) {
1678
            $heading = $this->heading($this->page->heading, $contextheader->headinglevel);
1679
        } else {
1680
            $heading = $this->heading($contextheader->heading, $contextheader->headinglevel);
1681
        }
1682
 
1683
        // All the html stuff goes here.
1684
        $html = html_writer::start_div('page-context-header d-flex align-items-center flex-wrap');
1685
 
1686
        // Image data.
1687
        if (isset($contextheader->imagedata)) {
1688
            // Header specific image.
1689
            $html .= html_writer::div($contextheader->imagedata, 'page-header-image');
1690
        }
1691
 
1692
        // Headings.
1693
        if (isset($contextheader->prefix)) {
1694
            $prefix = html_writer::div($contextheader->prefix, 'text-muted text-uppercase small line-height-3');
1695
            $heading = $prefix . $heading;
1696
        }
1697
 
1698
        if (!isset($contextheader->heading)) {
1699
            $html .= html_writer::tag('h3', $heading, array('class' => 'rui-page-title rui-page-title--page'));
1700
        } else if (isset($contextheader->imagedata)) {
1701
            $html .= html_writer::tag(
1702
                'div',
1703
                $this->heading($contextheader->heading, 4),
1704
                array('class' => 'rui-page-title rui-page-title--icon')
1705
            );
1706
        } else {
1707
            $html .= html_writer::tag('h2', $heading, array('class' => 'page-header-headings
1708
                rui-page-title rui-page-title--context'));
1709
        }
1710
 
1711
        // Buttons.
1712
        if (isset($contextheader->additionalbuttons)) {
1713
            $html .= html_writer::start_div('btn-group header-button-group my-2 my-lg-0 ml-lg-4');
1714
            foreach ($contextheader->additionalbuttons as $button) {
1715
                if (!isset($button->page)) {
1716
                    // Include js for messaging.
1717
                    if ($button['buttontype'] === 'togglecontact') {
1718
                        \core_message\helper::togglecontact_requirejs();
1719
                    }
1720
                    if ($button['buttontype'] === 'message') {
1721
                        \core_message\helper::messageuser_requirejs();
1722
                    }
1723
                    $image = $this->pix_icon($button['formattedimage'], $button['title'], 'moodle', array(
1724
                        'class' => 'iconsmall',
1725
                        'role' => 'presentation'
1726
                    ));
1727
                    $image .= html_writer::span($button['title'], 'header-button-title');
1295 ariadna 1728
                } else {
1298 ariadna 1729
                    $image = html_writer::empty_tag('img', array(
1730
                        'src' => $button['formattedimage'],
1731
                        'role' => 'presentation'
1732
                    ));
1295 ariadna 1733
                }
1298 ariadna 1734
                $html .= html_writer::link($button['url'], html_writer::tag('span', $image), $button['linkattributes']);
1735
            }
1736
            $html .= html_writer::end_div();
1737
        }
1738
        $html .= html_writer::end_div();
1295 ariadna 1739
 
1298 ariadna 1740
        return $html;
1741
    }
1295 ariadna 1742
 
1298 ariadna 1743
    public function header()
1744
    {
1745
        global $USER, $COURSE;
1746
        $theme = theme_config::load('universe');
1295 ariadna 1747
 
1298 ariadna 1748
        $context = context_course::instance($COURSE->id);
1749
        $roles = get_user_roles($context, $USER->id, true);
1750
 
1751
        if (is_array($roles) && !empty($roles)) {
1752
            foreach ($roles as $role) {
1753
                $this->page->add_body_class('role-' . $role->shortname);
1295 ariadna 1754
            }
1298 ariadna 1755
        } else {
1756
            $this->page->add_body_class('role-none');
1757
        }
1295 ariadna 1758
 
1298 ariadna 1759
        if ($theme->settings->topbareditmode == '1') {
1760
            $this->page->add_body_class('rui-editmode--top');
1761
        } else {
1762
            $this->page->add_body_class('rui-editmode--footer');
1763
        }
1295 ariadna 1764
 
1298 ariadna 1765
        return parent::header();
1766
    }
1767
 
1768
 
1769
    /**
1770
     * See if this is the first view of the current cm in the session if it has fake blocks.
1771
     *
1772
     * (We track up to 100 cms so as not to overflow the session.)
1773
     * This is done for drawer regions containing fake blocks so we can show blocks automatically.
1774
     *
1775
     * @return boolean true if the page has fakeblocks and this is the first visit.
1776
     */
1777
    public function firstview_fakeblocks(): bool
1778
    {
1779
        global $SESSION;
1780
 
1781
        $firstview = false;
1782
        if ($this->page->cm) {
1783
            if (!$this->page->blocks->region_has_fakeblocks('side-pre')) {
1784
                return false;
1785
            }
1786
            if (!property_exists($SESSION, 'firstview_fakeblocks')) {
1787
                $SESSION->firstview_fakeblocks = [];
1788
            }
1789
            if (array_key_exists($this->page->cm->id, $SESSION->firstview_fakeblocks)) {
1790
                $firstview = false;
1791
            } else {
1792
                $SESSION->firstview_fakeblocks[$this->page->cm->id] = true;
1793
                $firstview = true;
1794
                if (count($SESSION->firstview_fakeblocks) > 100) {
1795
                    array_shift($SESSION->firstview_fakeblocks);
1796
                }
1797
            }
1295 ariadna 1798
        }
1298 ariadna 1799
        return $firstview;
1800
    }
1295 ariadna 1801
 
1298 ariadna 1802
 
1803
    /**
1804
     * Build the guest access hint HTML code.
1805
     *
1806
     * @param int $courseid The course ID.
1807
     * @return string.
1808
     */
1809
    public function theme_universe_get_course_guest_access_hint($courseid)
1810
    {
1811
        global $CFG;
1812
        require_once($CFG->dirroot . '/enrol/self/lib.php');
1813
 
1814
        $html = '';
1815
        $instances = enrol_get_instances($courseid, true);
1816
        $plugins = enrol_get_plugins(true);
1817
        foreach ($instances as $instance) {
1818
            if (!isset($plugins[$instance->enrol])) {
1819
                continue;
1820
            }
1821
            $plugin = $plugins[$instance->enrol];
1822
            if ($plugin->show_enrolme_link($instance)) {
1823
                $html = html_writer::tag('div', get_string(
1824
                    'showhintcourseguestaccesssettinglink',
1825
                    'theme_universe',
1826
                    array('url' => $CFG->wwwroot . '/enrol/index.php?id=' . $courseid)
1827
                ));
1828
                break;
1829
            }
1295 ariadna 1830
        }
1831
 
1298 ariadna 1832
        return $html;
1833
    }
1834
 
1835
 
1836
    /**
1837
     * Color Customization
1838
     * @return string HTML fragment.
1839
     */
1840
    public function additional_head_html()
1841
    {
1842
        global $SITE, $DB, $CFG, $COURSE, $PAGE;
1843
 
1844
        $output = null;
1845
 
1846
        if ($PAGE->pagelayout == 'course' || $PAGE->pagelayout == 'incourse') {
1847
            if ($DB->record_exists('customfield_field', array('shortname' => 'maincolor1'), 'id')) {
1848
                // Get custom field by name
1849
                $customfieldid1 = $DB->get_record('customfield_field', array('shortname' => 'maincolor1'));
1850
                // Get value
1851
                $mainthemecolor = $DB->get_record('customfield_data', array('fieldid' => $customfieldid1->id, 'instanceid' => $COURSE->id));
1852
            } else {
1853
                $mainthemecolor = null;
1854
            }
1855
 
1856
            if ($DB->record_exists('customfield_field', array('shortname' => 'maincolor2'), 'id')) {
1857
                $customfieldid2 = $DB->get_record('customfield_field', array('shortname' => 'maincolor2'));
1858
                $mainthemecolor2 = $DB->get_record('customfield_data', array('fieldid' => $customfieldid2->id, 'instanceid' => $COURSE->id));
1859
            }
1860
 
1861
            if ($DB->record_exists('customfield_field', array('shortname' => 'topbarcolor'), 'id')) {
1862
                // Get custom field by name
1863
                $customfieldid3 = $DB->get_record('customfield_field', array('shortname' => 'topbarcolor'));
1864
                // Get value
1865
                $topbarcolor = $DB->get_record('customfield_data', array('fieldid' => $customfieldid3->id, 'instanceid' => $COURSE->id));
1866
            }
1867
 
1868
            if ($DB->record_exists('customfield_field', array('shortname' => 'dmtopbarcolor'), 'id')) {
1869
                // Get custom field by name
1870
                $customfieldid3 = $DB->get_record('customfield_field', array('shortname' => 'dmtopbarcolor'));
1871
                // Get value
1872
                $dmtopbarcolor = $DB->get_record('customfield_data', array('fieldid' => $customfieldid3->id, 'instanceid' => $COURSE->id));
1873
            } else {
1874
                $dmtopbarcolor = null;
1875
            }
1876
 
1877
 
1878
            if ($DB->record_exists('customfield_field', array('shortname' => 'footerbgcolor'), 'id')) {
1879
                // Get custom field by name
1880
                $customfieldid4 = $DB->get_record('customfield_field', array('shortname' => 'footerbgcolor'));
1881
                // Get value
1882
                $footercolor = $DB->get_record('customfield_data', array('fieldid' => $customfieldid4->id, 'instanceid' => $COURSE->id));
1883
            } else {
1884
                $footercolor = null;
1885
            }
1886
 
1887
 
1888
            $css = '';
1889
 
1890
            $css .= ':root { ';
1891
            if ($DB->record_exists('customfield_field', array('shortname' => 'maincolor1'), 'id')) {
1892
                if ($mainthemecolor != null) {
1893
                    $css .= '--main-theme-color: ' . $mainthemecolor->value . '; ';
1894
                    $css .= '--primary-color-100: ' . $mainthemecolor->value . '30; ';
1895
                    $css .= '--primary-color-300: ' . $mainthemecolor->value . '70; ';
1896
                    $css .= '--main-theme-color-gradient: ' . $mainthemecolor->value . '; ';
1897
                    $css .= '--btn-primary-color-bg: ' . $mainthemecolor->value . '; ';
1898
                    $css .= '--btn-primary-color-bg-hover: ' . $mainthemecolor->value . '95; ';
1899
 
1900
                    if ($DB->record_exists('customfield_field', array('shortname' => 'maincolor2'), 'id')) {
1901
                        if ($mainthemecolor2 != null) {
1902
                            $css .= '--main-theme-color-gradient-2: ' . $mainthemecolor2->value . '; ';
1903
                        } else {
1904
                            $css .= '--main-theme-color-gradient-2: ' . $mainthemecolor->value . '30; ';
1905
                        }
1906
                    }
1907
                }
1908
            }
1909
 
1910
            if ($DB->record_exists('customfield_field', array('shortname' => 'topbarcolor'), 'id')) {
1911
                if ($topbarcolor != null) {
1912
                    $css .= '--topbar-color: ' . $topbarcolor->value . '; ';
1913
                    if ($dmtopbarcolor != null) {
1914
                        $css .= '--dm-topbar-color: ' . $dmtopbarcolor->value . '; ';
1915
                    } else {
1916
                        $css .= '--dm-topbar-color: ' . $topbarcolor->value . '; ';
1917
                    }
1918
                }
1919
            }
1920
 
1921
            if ($DB->record_exists('customfield_field', array('shortname' => 'footerbgcolor'), 'id')) {
1922
                if ($footercolor != null) {
1923
                    $css .= '--footer-color: ' . $footercolor->value . '; ';
1924
                }
1925
            }
1926
 
1927
            $css .= '}';
1928
 
1929
            if ($css) {
1930
                $output .= '<style>' . $css . '</style>';
1931
            }
1295 ariadna 1932
        }
1933
 
1298 ariadna 1934
        return $output;
1935
    }
1295 ariadna 1936
 
1298 ariadna 1937
    public function custom_course_logo()
1938
    {
1939
        global $DB, $CFG, $COURSE, $PAGE;
1295 ariadna 1940
 
1298 ariadna 1941
        $output = null;
1295 ariadna 1942
 
1298 ariadna 1943
        if ($PAGE->pagelayout == 'course' || $PAGE->pagelayout == 'incourse') {
1944
            if ($DB->record_exists('customfield_field', array('shortname' => 'customcourselogo'))) {
1945
                // Get custom field ID
1946
                $customfieldpic = $DB->get_record('customfield_field', array('shortname' => 'customcourselogo'));
1947
                $customfieldpicid = $customfieldpic->id;
1948
                // Get value
1949
                $customlogo = $DB->get_record(
1950
                    'customfield_data',
1951
                    array('fieldid' => $customfieldpicid, 'instanceid' => $COURSE->id)
1952
                );
1295 ariadna 1953
 
1298 ariadna 1954
                $customlogoid = $customlogo->id;
1955
                $contextid = $customlogo->contextid;
1956
 
1957
                if ($customfieldpic != null) {
1958
                    $files = get_file_storage()->get_area_files(
1959
                        $contextid,
1960
                        'customfield_picture',
1961
                        'file',
1962
                        $customlogoid,
1963
                        '',
1964
                        false
1965
                    );
1966
 
1967
                    if (empty($files)) {
1968
                        return null;
1969
                    }
1970
 
1971
                    $file = reset($files);
1972
                    $fileurl = moodle_url::make_pluginfile_url(
1973
                        $file->get_contextid(),
1974
                        $file->get_component(),
1975
                        $file->get_filearea(),
1976
                        $file->get_itemid(),
1977
                        $file->get_filepath(),
1978
                        $file->get_filename()
1979
                    );
1980
 
1981
                    $output .= $fileurl;
1982
                }
1983
            }
1984
        }
1985
 
1986
        return $output;
1295 ariadna 1987
    }
1988
 
1298 ariadna 1989
    public function custom_course_dmlogo()
1294 ariadna 1990
    {
1298 ariadna 1991
        global $DB, $CFG, $COURSE, $PAGE;
1294 ariadna 1992
 
1298 ariadna 1993
        $output = null;
1994
 
1995
        if ($PAGE->pagelayout == 'course' || $PAGE->pagelayout == 'incourse') {
1996
            if ($DB->record_exists('customfield_field', array('shortname' => 'customcoursedmlogo'))) {
1997
                // Get custom field ID
1998
                $customfieldpic = $DB->get_record('customfield_field', array('shortname' => 'customcoursedmlogo'));
1999
                $customfieldpicid = $customfieldpic->id;
2000
                // Get value
2001
                $customlogo = $DB->get_record(
2002
                    'customfield_data',
2003
                    array('fieldid' => $customfieldpicid, 'instanceid' => $COURSE->id)
2004
                );
2005
 
2006
                $customlogoid = $customlogo->id;
2007
                $contextid = $customlogo->contextid;
2008
 
2009
                if ($customfieldpic != null) {
2010
                    $files = get_file_storage()->get_area_files(
2011
                        $contextid,
2012
                        'customfield_picture',
2013
                        'file',
2014
                        $customlogoid,
2015
                        '',
2016
                        false
2017
                    );
2018
 
2019
                    if (empty($files)) {
2020
                        return null;
2021
                    }
2022
 
2023
                    $file = reset($files);
2024
                    $fileurl = moodle_url::make_pluginfile_url(
2025
                        $file->get_contextid(),
2026
                        $file->get_component(),
2027
                        $file->get_filearea(),
2028
                        $file->get_itemid(),
2029
                        $file->get_filepath(),
2030
                        $file->get_filename()
2031
                    );
2032
 
2033
                    $output .= $fileurl;
2034
                }
2035
            }
1294 ariadna 2036
        }
2037
 
1298 ariadna 2038
        return $output;
2039
    }
1294 ariadna 2040
 
1298 ariadna 2041
    public function custom_course_favicon()
2042
    {
2043
        global $DB, $CFG, $COURSE, $PAGE;
1294 ariadna 2044
 
1298 ariadna 2045
        $output = null;
2046
 
2047
        if ($PAGE->pagelayout == 'course' || $PAGE->pagelayout == 'incourse') {
2048
            if ($DB->record_exists('customfield_field', array('shortname' => 'customcoursefavicon'))) {
2049
                // Get custom field ID
2050
                $customfieldpic = $DB->get_record('customfield_field', array('shortname' => 'customcoursefavicon'));
2051
                $customfieldpicid = $customfieldpic->id;
2052
                // Get value
2053
                $customfavicon = $DB->get_record(
2054
                    'customfield_data',
2055
                    array('fieldid' => $customfieldpicid, 'instanceid' => $COURSE->id)
2056
                );
2057
 
2058
                $customfaviconid = $customfavicon->id;
2059
                $contextid = $customfavicon->contextid;
2060
 
2061
                if ($customfieldpic != null) {
2062
                    $files = get_file_storage()->get_area_files(
2063
                        $contextid,
2064
                        'customfield_picture',
2065
                        'file',
2066
                        $customfaviconid,
2067
                        '',
2068
                        false
2069
                    );
2070
 
2071
                    if (empty($files)) {
2072
                        return null;
2073
                    }
2074
 
2075
                    $file = reset($files);
2076
                    $fileurl = moodle_url::make_pluginfile_url(
2077
                        $file->get_contextid(),
2078
                        $file->get_component(),
2079
                        $file->get_filearea(),
2080
                        $file->get_itemid(),
2081
                        $file->get_filepath(),
2082
                        $file->get_filename()
2083
                    );
2084
 
2085
                    $output .= $fileurl;
2086
                }
2087
            }
2088
        }
2089
 
2090
        return $output;
1294 ariadna 2091
    }
1297 ariadna 2092
 
1298 ariadna 2093
    public function custom_course_name()
1297 ariadna 2094
    {
1298 ariadna 2095
        global $DB, $CFG, $COURSE, $PAGE;
1297 ariadna 2096
 
1298 ariadna 2097
        $output = null;
2098
 
2099
        if ($PAGE->pagelayout == 'course' || $PAGE->pagelayout == 'incourse') {
2100
            if ($DB->record_exists('customfield_field', array('shortname' => 'customcoursename'), 'id')) {
2101
                // Get custom field by name
2102
                $customfieldid = $DB->get_record('customfield_field', array('shortname' => 'customcoursename'));
2103
                // Get value
2104
                $customcoursename = $DB->get_record('customfield_data', array('fieldid' => $customfieldid->id, 'instanceid' => $COURSE->id));
2105
                if (!empty($customcoursename)) {
2106
                    $output .= $customcoursename->value;
2107
                }
2108
            } else {
2109
                $customcoursename = null;
2110
            }
1297 ariadna 2111
        }
2112
 
1298 ariadna 2113
        return $output;
2114
    }
2115
 
2116
    /**
2117
     * Get the course pattern datauri to show on a course card.
2118
     *
2119
     * The datauri is an encoded svg that can be passed as a url.
2120
     * @param int $id Id to use when generating the pattern
2121
     * @return string datauri
2122
     */
2123
    public function get_generated_image_for_id($id)
2124
    {
2125
        global $CFG;
2126
 
2127
        $theme = \theme_config::load('universe');
2128
        // Add custom course cover.
2129
        $customcover = $theme->setting_file_url('defaultcourseimg', 'defaultcourseimg');
2130
 
2131
        if (!empty(($customcover))) {
2132
            $urlreplace = preg_replace('|^https?://|i', '//', $CFG->wwwroot);
2133
            $customcover = str_replace($urlreplace, '', $customcover);
2134
            $txt = new moodle_url($customcover);
2135
            return strval($txt);
2136
        } else {
2137
            $color = $this->get_generated_color_for_id($id);
2138
            $pattern = new \core_geopattern();
2139
            $pattern->setColor($color);
2140
            $pattern->patternbyid($id);
2141
            return $pattern->datauri();
1297 ariadna 2142
        }
1298 ariadna 2143
    }
1297 ariadna 2144
 
1298 ariadna 2145
    public function moremenu_group_item()
2146
    {
2147
        global $CFG, $COURSE;
2148
 
2149
        $theme = \theme_config::load('universe');
2150
        $courseid = $COURSE->id;
2151
        $sitehomeurl = new moodle_url('/');
2152
 
2153
        if ($this->page->theme->settings->secnavgroupitem == 1) {
2154
            if (has_capability('moodle/course:managegroups', \context_course::instance($COURSE->id))) {
2155
                $html = $sitehomeurl . "group/index.php?id=" . $courseid;
2156
                return $html;
2157
            }
1297 ariadna 2158
        }
1298 ariadna 2159
    }
1297 ariadna 2160
 
1298 ariadna 2161
    public function moremenu_custom_items()
2162
    {
2163
        global $CFG, $COURSE, $USER;
2164
 
2165
        $theme = \theme_config::load('universe');
2166
        $html = '';
2167
        $secnavcount = theme_universe_get_setting('secnavitemscount');
2168
 
2169
        // Get current user role ID.
2170
        $context = context_course::instance($COURSE->id);
2171
        $roles = get_user_roles($context, $USER->id, true);
2172
        $role = 999;
2173
        $roleid = 999;
2174
        $role = key($roles);
2175
        if ($role != null) {
2176
            $roleid = $roles[$role]->roleid;
1297 ariadna 2177
        }
2178
 
1298 ariadna 2179
        // End.
2180
 
2181
        if ($this->page->theme->settings->secnavitems == 1) {
2182
 
2183
            $secnav = new stdClass();
2184
            for ($i = 1; $i <= $secnavcount; $i++) {
2185
                $secnav->title = theme_universe_get_setting("secnavcustomnavlabel" . $i);
2186
 
2187
                $url = theme_universe_get_setting("secnavcustomnavurl" . $i);
2188
                $courseid = $COURSE->id;
2189
                $newurl = str_replace("{{courseID}}", $courseid, $url);
2190
 
2191
                // User role restriction.
2192
                $selectrole = theme_universe_get_setting("secnavuserroles" . $i);
2193
 
2194
                if ($roleid == $selectrole) {
2195
                    $secnav->url = $newurl;
2196
                    $html .= $this->render_from_template('theme_universe/custom_sec_nav_item', $secnav);
2197
                }
2198
                if ($roleid != $selectrole) {
2199
                    $secnav->url = $newurl;
2200
                }
2201
                if ($selectrole == 0) {
2202
                    $secnav->url = $newurl;
2203
                    $html .= $this->render_from_template('theme_universe/custom_sec_nav_item', $secnav);
2204
                }
2205
                // End.
2206
 
2207
            }
2208
        }
2209
        return $html;
1297 ariadna 2210
    }
1299 ariadna 2211
 
2212
    public function render_statics_blocks($userid = null)
2213
    {
2214
        global $USER;
2215
 
2216
        if (!$userid) {
2217
            $userid = $USER->id;
2218
        }
2219
 
2220
        // Instanciamos StaticsBlocks para renderizar los bloques
2221
        $statics_blocks = new \StaticsBlocks(
2222
            'side-pre',
2223
            ['messageteacher', 'comments', 'cesa_course_rating', 'cesa_notes']
2224
        );
2225
 
2226
        $blocks = $statics_blocks->renderBlocks();
2227
 
2228
        return $blocks;
2229
    }
1291 ariadna 2230
}