Passed
Push — master ( 068028...bea80d )
by Julito
08:43
created

Display::getMdiIcon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\ExtraField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ExtraField. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
8
use Chamilo\CoreBundle\Framework\Container;
9
use ChamiloSession as Session;
10
use Symfony\Component\HttpFoundation\Response;
11
12
/**
13
 * Class Display
14
 * Contains several public functions dealing with the display of
15
 * table data, messages, help topics, ...
16
 *
17
 * Include/require it in your code to use its public functionality.
18
 * There are also several display public functions in the main api library.
19
 *
20
 * All public functions static public functions inside a class called Display,
21
 * so you use them like this: e.g.
22
 * Display::return_message($message)
23
 */
24
class Display
25
{
26
    /** @var Template */
27
    public static $global_template;
28
    public static $preview_style = null;
29
    public static $legacyTemplate;
30
31
    public function __construct()
32
    {
33
    }
34
35
    /**
36
     * @return array
37
     */
38
    public static function toolList()
39
    {
40
        return [
41
            'group',
42
            'work',
43
            'glossary',
44
            'forum',
45
            'course_description',
46
            'gradebook',
47
            'attendance',
48
            'course_progress',
49
            'notebook',
50
        ];
51
    }
52
53
    /**
54
     * Displays the page header.
55
     *
56
     * @param string The name of the page (will be showed in the page title)
57
     * @param string Optional help file name
58
     * @param string $page_header
59
     */
60
    public static function display_header(
61
        $tool_name = '',
62
        $help = null,
63
        $page_header = null
64
    ) {
65
        global $interbreadcrumb;
66
        $interbreadcrumb[] = ['url' => '#', 'name' => $tool_name];
67
68
        ob_start();
69
70
        return true;
71
    }
72
73
    /**
74
     * Displays the reduced page header (without banner).
75
     */
76
    public static function display_reduced_header()
77
    {
78
        ob_start();
79
        self::$legacyTemplate = '@ChamiloCore/Layout/no_layout.html.twig';
80
81
        return true;
82
83
        global $show_learnpath, $tool_name;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
84
        self::$global_template = new Template(
85
            $tool_name,
86
            false,
87
            false,
88
            $show_learnpath
89
        );
90
    }
91
92
    /**
93
     * Display no header.
94
     */
95
    public static function display_no_header()
96
    {
97
        global $tool_name, $show_learnpath;
98
        self::$global_template = new Template(
99
            $tool_name,
100
            false,
101
            false,
102
            $show_learnpath
103
        );
104
    }
105
106
    /**
107
     * Display the page footer.
108
     */
109
    public static function display_footer()
110
    {
111
        $contents = ob_get_contents();
112
        if (ob_get_length()) {
113
            ob_end_clean();
114
        }
115
        $tpl = '@ChamiloCore/Layout/layout_one_col.html.twig';
116
        if (!empty(self::$legacyTemplate)) {
117
            $tpl = self::$legacyTemplate;
118
        }
119
        $response = new Response();
120
        $params['content'] = $contents;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
121
        global $interbreadcrumb, $htmlHeadXtra;
122
123
        $courseInfo = api_get_course_info();
124
        if (!empty($courseInfo)) {
125
            $url = $courseInfo['course_public_url'];
126
            $sessionId = api_get_session_id();
127
            if (!empty($sessionId)) {
128
                $url .= '?sid='.$sessionId;
129
            }
130
131
            if (!empty($interbreadcrumb)) {
132
                array_unshift(
133
                    $interbreadcrumb,
134
                    ['name' => $courseInfo['title'], 'url' => $url]
135
                );
136
            }
137
        }
138
139
        if (empty($interbreadcrumb)) {
140
            $interbreadcrumb = [];
141
        }
142
143
        $params['legacy_javascript'] = $htmlHeadXtra;
144
        $params['legacy_breadcrumb'] = json_encode($interbreadcrumb);
145
146
        Template::setVueParams($params);
147
        $content = Container::getTwig()->render($tpl, $params);
148
        $response->setContent($content);
149
        $response->send();
150
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
151
    }
152
153
    /**
154
     * Display the page footer.
155
     */
156
    public static function display_reduced_footer()
157
    {
158
        return self::display_footer();
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::display_footer() targeting Display::display_footer() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
159
160
        $contents = ob_get_contents();
0 ignored issues
show
Unused Code introduced by
$contents = ob_get_contents() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
161
        if (ob_get_length()) {
162
            ob_end_clean();
163
        }
164
        $tpl = '@ChamiloCore/Layout/no_layout.html.twig';
165
        if (!empty(self::$legacyTemplate)) {
166
            $tpl = self::$legacyTemplate;
167
        }
168
        $response = new Response();
169
        $params['content'] = $contents;
170
        global $interbreadcrumb, $htmlHeadXtra;
171
        $params['legacy_javascript'] = $htmlHeadXtra;
172
        $params['legacy_breadcrumb'] = $interbreadcrumb;
173
174
        $content = Container::getTwig()->render($tpl, $params);
175
        $response->setContent($content);
176
        $response->send();
177
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
178
    }
179
180
    /**
181
     * Displays the tool introduction of a tool.
182
     *
183
     * @author Patrick Cool <[email protected]>, Ghent University
184
     *
185
     * @param string $tool          these are the constants that are used for indicating the tools
186
     * @param array  $editor_config Optional configuration settings for the online editor.
187
     *                              return: $tool return a string array list with the "define" in main_api.lib
188
     *
189
     * @return string html code for adding an introduction
190
     */
191
    public static function display_introduction_section(
192
        $tool,
193
        $editor_config = null
194
    ) {
195
        // @todo replace introduction section with a vue page.
196
        return;
197
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Unused Code introduced by
echo self::return_introd...($tool, $editor_config) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
198
    }
199
200
    /**
201
     * @param string $tool
202
     * @param array  $editor_config
203
     */
204
    public static function return_introduction_section(
205
        $tool,
206
        $editor_config = null
207
    ) {
208
        $moduleId = $tool;
209
        if ('true' === api_get_setting('enable_tool_introduction') || TOOL_COURSE_HOMEPAGE == $tool) {
210
            $introduction_section = null;
211
            require api_get_path(SYS_CODE_PATH).'inc/introductionSection.inc.php';
212
213
            return $introduction_section;
214
        }
215
    }
216
217
    /**
218
     * Displays a table.
219
     *
220
     * @param array  $header          Titles for the table header
221
     *                                each item in this array can contain 3 values
222
     *                                - 1st element: the column title
223
     *                                - 2nd element: true or false (column sortable?)
224
     *                                - 3th element: additional attributes for
225
     *                                th-tag (eg for column-width)
226
     *                                - 4the element: additional attributes for the td-tags
227
     * @param array  $content         2D-array with the tables content
228
     * @param array  $sorting_options Keys are:
229
     *                                'column' = The column to use as sort-key
230
     *                                'direction' = SORT_ASC or SORT_DESC
231
     * @param array  $paging_options  Keys are:
232
     *                                'per_page_default' = items per page when switching from
233
     *                                full-    list to per-page-view
234
     *                                'per_page' = number of items to show per page
235
     *                                'page_nr' = The page to display
236
     * @param array  $query_vars      Additional variables to add in the query-string
237
     * @param array  $form_actions
238
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
239
     * @param string $tableName
240
     * @param string $tableId
241
     *
242
     * @author [email protected]
243
     */
244
    public static function display_sortable_table(
245
        $header,
246
        $content,
247
        $sorting_options = [],
248
        $paging_options = [],
249
        $query_vars = null,
250
        $form_actions = [],
251
        $style = 'table',
252
        $tableName = 'tablename',
253
        $tableId = ''
254
    ) {
255
        $column = $sorting_options['column'] ?? 0;
256
        $default_items_per_page = $paging_options['per_page'] ?? 20;
257
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
258
        if (is_array($query_vars)) {
259
            $table->set_additional_parameters($query_vars);
260
        }
261
        if ('table' === $style) {
262
            if (is_array($header) && count($header) > 0) {
263
                foreach ($header as $index => $header_item) {
264
                    $table->set_header(
265
                        $index,
266
                        isset($header_item[0]) ? $header_item[0] : null,
267
                        isset($header_item[1]) ? $header_item[1] : null,
268
                        isset($header_item[2]) ? $header_item[2] : null,
269
                        isset($header_item[3]) ? $header_item[3] : null
270
                    );
271
                }
272
            }
273
            $table->set_form_actions($form_actions);
274
            $table->display();
275
        } else {
276
            $table->display_grid();
277
        }
278
    }
279
280
    /**
281
     * Returns an HTML table with sortable column (through complete page refresh).
282
     *
283
     * @param array  $header
284
     * @param array  $content         Array of row arrays
285
     * @param array  $sorting_options
286
     * @param array  $paging_options
287
     * @param array  $query_vars
288
     * @param array  $form_actions
289
     * @param string $style
290
     *
291
     * @return string HTML string for array
292
     */
293
    public static function return_sortable_table(
294
        $header,
295
        $content,
296
        $sorting_options = [],
297
        $paging_options = [],
298
        $query_vars = null,
299
        $form_actions = [],
300
        $style = 'table'
301
    ) {
302
        ob_start();
303
        self::display_sortable_table(
304
            $header,
305
            $content,
306
            $sorting_options,
307
            $paging_options,
308
            $query_vars,
309
            $form_actions,
310
            $style
311
        );
312
        $content = ob_get_contents();
313
        ob_end_clean();
314
315
        return $content;
316
    }
317
318
    /**
319
     * Shows a nice grid.
320
     *
321
     * @param string grid name (important to create css)
322
     * @param array header content
323
     * @param array array with the information to show
324
     * @param array $paging_options Keys are:
325
     *                              'per_page_default' = items per page when switching from
326
     *                              full-    list to per-page-view
327
     *                              'per_page' = number of items to show per page
328
     *                              'page_nr' = The page to display
329
     *                              'hide_navigation' =  true to hide the navigation
330
     * @param array $query_vars     Additional variables to add in the query-string
331
     * @param mixed An array with bool values to know which columns show.
332
     * i.e: $visibility_options= array(true, false) we will only show the first column
333
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
334
     */
335
    public static function display_sortable_grid(
336
        $name,
337
        $header,
338
        $content,
339
        $paging_options = [],
340
        $query_vars = null,
341
        $form_actions = [],
342
        $visibility_options = true,
343
        $sort_data = true,
344
        $grid_class = []
345
    ) {
346
        echo self::return_sortable_grid(
347
            $name,
348
            $header,
349
            $content,
350
            $paging_options,
351
            $query_vars,
352
            $form_actions,
353
            $visibility_options,
354
            $sort_data,
355
            $grid_class
356
        );
357
    }
358
359
    /**
360
     * Gets a nice grid in html string.
361
     *
362
     * @param string grid name (important to create css)
363
     * @param array header content
364
     * @param array array with the information to show
365
     * @param array $paging_options Keys are:
366
     *                              'per_page_default' = items per page when switching from
367
     *                              full-    list to per-page-view
368
     *                              'per_page' = number of items to show per page
369
     *                              'page_nr' = The page to display
370
     *                              'hide_navigation' =  true to hide the navigation
371
     * @param array $query_vars     Additional variables to add in the query-string
372
     * @param mixed An array with bool values to know which columns show. i.e:
373
     *  $visibility_options= array(true, false) we will only show the first column
374
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
375
     * @param bool  true for sorting data or false otherwise
376
     * @param array grid classes
377
     *
378
     * @return string html grid
379
     */
380
    public static function return_sortable_grid(
381
        $name,
382
        $header,
383
        $content,
384
        $paging_options = [],
385
        $query_vars = null,
386
        $form_actions = [],
387
        $visibility_options = true,
388
        $sort_data = true,
389
        $grid_class = [],
390
        $elementCount = 0
391
    ) {
392
        $column = 0;
393
        $default_items_per_page = $paging_options['per_page'] ?? 20;
394
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
395
        $table->total_number_of_items = (int) $elementCount;
396
        if (is_array($query_vars)) {
397
            $table->set_additional_parameters($query_vars);
398
        }
399
400
        return $table->display_simple_grid(
401
            $visibility_options,
402
            $paging_options['hide_navigation'],
403
            $default_items_per_page,
404
            $sort_data,
405
            $grid_class
406
        );
407
    }
408
409
    /**
410
     * Displays a table with a special configuration.
411
     *
412
     * @param array $header          Titles for the table header
413
     *                               each item in this array can contain 3 values
414
     *                               - 1st element: the column title
415
     *                               - 2nd element: true or false (column sortable?)
416
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
417
     *                               - 4the element: additional attributes for the td-tags
418
     * @param array $content         2D-array with the tables content
419
     * @param array $sorting_options Keys are:
420
     *                               'column' = The column to use as sort-key
421
     *                               'direction' = SORT_ASC or SORT_DESC
422
     * @param array $paging_options  Keys are:
423
     *                               'per_page_default' = items per page when switching from full list to per-page-view
424
     *                               'per_page' = number of items to show per page
425
     *                               'page_nr' = The page to display
426
     * @param array $query_vars      Additional variables to add in the query-string
427
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
428
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
429
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
430
     * @param array $form_actions    Set optional forms actions
431
     *
432
     * @author Julio Montoya
433
     */
434
    public static function display_sortable_config_table(
435
        $table_name,
436
        $header,
437
        $content,
438
        $sorting_options = [],
439
        $paging_options = [],
440
        $query_vars = null,
441
        $column_show = [],
442
        $column_order = [],
443
        $form_actions = []
444
    ) {
445
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
446
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
447
448
        $table = new SortableTableFromArrayConfig(
449
            $content,
450
            $column,
451
            $default_items_per_page,
452
            $table_name,
453
            $column_show,
454
            $column_order
455
        );
456
457
        if (is_array($query_vars)) {
458
            $table->set_additional_parameters($query_vars);
459
        }
460
        // Show or hide the columns header
461
        if (is_array($column_show)) {
462
            for ($i = 0; $i < count($column_show); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
463
                if (!empty($column_show[$i])) {
464
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
465
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
466
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
467
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
468
                    $table->set_header($i, $val0, $val1, $val2, $val3);
469
                }
470
            }
471
        }
472
        $table->set_form_actions($form_actions);
473
        $table->display();
474
    }
475
476
    /**
477
     * Returns a div html string with.
478
     *
479
     * @param string $message
480
     * @param string $type    Example: confirm, normal, warning, error
481
     * @param bool   $filter  Whether to XSS-filter or not
482
     *
483
     * @return string Message wrapped into an HTML div
484
     */
485
    public static function return_message($message, $type = 'normal', $filter = true)
486
    {
487
        if (empty($message)) {
488
            return '';
489
        }
490
491
        if ($filter) {
492
            $message = api_htmlentities(
493
                $message,
494
                ENT_QUOTES,
495
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
496
            );
497
        }
498
499
        $class = '';
500
        switch ($type) {
501
            case 'warning':
502
                $class .= 'alert alert-warning';
503
                break;
504
            case 'error':
505
                $class .= 'alert alert-danger';
506
                break;
507
            case 'confirmation':
508
            case 'confirm':
509
            case 'success':
510
                $class .= 'alert alert-success';
511
                break;
512
            case 'normal':
513
            case 'info':
514
            default:
515
                $class .= 'alert alert-info';
516
        }
517
518
        return self::div($message, ['class' => $class]);
519
    }
520
521
    /**
522
     * Returns an encrypted mailto hyperlink.
523
     *
524
     * @param string  e-mail
0 ignored issues
show
Documentation Bug introduced by
The doc comment e-mail at position 0 could not be parsed: Unknown type name 'e-mail' at position 0 in e-mail.
Loading history...
525
     * @param string  clickable text
526
     * @param string  optional, class from stylesheet
527
     * @param bool $addExtraContent
528
     *
529
     * @return string encrypted mailto hyperlink
530
     */
531
    public static function encrypted_mailto_link(
532
        $email,
533
        $clickable_text = null,
534
        $style_class = '',
535
        $addExtraContent = false
536
    ) {
537
        if (is_null($clickable_text)) {
538
            $clickable_text = $email;
539
        }
540
541
        // "mailto:" already present?
542
        if ('mailto:' !== substr($email, 0, 7)) {
543
            $email = 'mailto:'.$email;
544
        }
545
546
        // Class (stylesheet) defined?
547
        if ('' !== $style_class) {
548
            $style_class = ' class="'.$style_class.'"';
549
        }
550
551
        // Encrypt email
552
        $hmail = '';
553
        for ($i = 0; $i < strlen($email); $i++) {
554
            $hmail .= '&#'.ord($email[$i]).';';
555
        }
556
557
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
558
559
        if ($value) {
560
            if ('false' === api_get_setting('allow_email_editor')) {
561
                $hmail .= '?';
562
            }
563
564
            if (!api_is_anonymous()) {
565
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS(api_get_setting('siteName')) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

565
                $hmail .= '&subject='./** @scrutinizer ignore-type */ Security::remove_XSS(api_get_setting('siteName'));
Loading history...
566
            }
567
            if ($addExtraContent) {
568
                $content = '';
569
                if (!api_is_anonymous()) {
570
                    $userInfo = api_get_user_info();
571
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
572
573
                    $courseInfo = api_get_course_info();
574
                    if (!empty($courseInfo)) {
575
                        $content .= get_lang('Course').': ';
576
                        $content .= $courseInfo['name'];
577
                        $sessionInfo = api_get_session_info(api_get_session_id());
578
                        if (!empty($sessionInfo)) {
579
                            $content .= ' '.$sessionInfo['name'].' <br />';
580
                        }
581
                    }
582
                }
583
                $hmail .= '&body='.rawurlencode($content);
584
            }
585
        }
586
587
        $hclickable_text = '';
588
        // Encrypt clickable text if @ is present
589
        if (strpos($clickable_text, '@')) {
590
            for ($i = 0; $i < strlen($clickable_text); $i++) {
591
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
592
            }
593
        } else {
594
            $hclickable_text = @htmlspecialchars(
595
                $clickable_text,
596
                ENT_QUOTES,
597
                api_get_system_encoding()
598
            );
599
        }
600
        // Return encrypted mailto hyperlink
601
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
602
    }
603
604
    /**
605
     * Returns an mailto icon hyperlink.
606
     *
607
     * @param string  e-mail
0 ignored issues
show
Documentation Bug introduced by
The doc comment e-mail at position 0 could not be parsed: Unknown type name 'e-mail' at position 0 in e-mail.
Loading history...
608
     * @param string  icon source file from the icon lib
609
     * @param int  icon size from icon lib
610
     * @param string  optional, class from stylesheet
611
     *
612
     * @return string encrypted mailto hyperlink
613
     */
614
    public static function icon_mailto_link(
615
        $email,
616
        $icon_file = "mail.png",
617
        $icon_size = 22,
618
        $style_class = ''
619
    ) {
620
        // "mailto:" already present?
621
        if ('mailto:' != substr($email, 0, 7)) {
622
            $email = 'mailto:'.$email;
623
        }
624
        // Class (stylesheet) defined?
625
        if ('' != $style_class) {
626
            $style_class = ' class="'.$style_class.'"';
627
        }
628
        // Encrypt email
629
        $hmail = '';
630
        for ($i = 0; $i < strlen($email); $i++) {
631
            $hmail .= '&#'.ord($email[
632
            $i]).';';
633
        }
634
        // icon html code
635
        $icon_html_source = self::return_icon(
636
            $icon_file,
637
            $hmail,
638
            '',
639
            $icon_size
640
        );
641
        // Return encrypted mailto hyperlink
642
643
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
644
    }
645
646
    /**
647
     * Prints an <option>-list with all letters (A-Z).
648
     *
649
     * @todo This is English language specific implementation.
650
     * It should be adapted for the other languages.
651
     *
652
     * @return string
653
     */
654
    public static function get_alphabet_options($selectedLetter = '')
655
    {
656
        $result = '';
657
        for ($i = 65; $i <= 90; $i++) {
658
            $letter = chr($i);
659
            $result .= '<option value="'.$letter.'"';
660
            if ($selectedLetter == $letter) {
661
                $result .= ' selected="selected"';
662
            }
663
            $result .= '>'.$letter.'</option>';
664
        }
665
666
        return $result;
667
    }
668
669
    /**
670
     * Get the options withing a select box within the given values.
671
     *
672
     * @param int   Min value
673
     * @param int   Max value
674
     * @param int   Default value
675
     *
676
     * @return string HTML select options
677
     */
678
    public static function get_numeric_options($min, $max, $selected_num = 0)
679
    {
680
        $result = '';
681
        for ($i = $min; $i <= $max; $i++) {
682
            $result .= '<option value="'.$i.'"';
683
            if (is_int($selected_num)) {
684
                if ($selected_num == $i) {
685
                    $result .= ' selected="selected"';
686
                }
687
            }
688
            $result .= '>'.$i.'</option>';
689
        }
690
691
        return $result;
692
    }
693
694
    /**
695
     * This public function displays an icon.
696
     *
697
     * @param string   The filename of the file (in the main/img/ folder
698
     * @param string   The alt text (probably a language variable)
699
     * @param array    additional attributes (for instance height, width, onclick, ...)
700
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
701
     */
702
    public static function display_icon(
703
        $image,
704
        $alt_text = '',
705
        $additional_attributes = [],
706
        $size = null
707
    ) {
708
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
709
    }
710
711
    /**
712
     * Gets the path of an icon.
713
     *
714
     * @param string $icon
715
     * @param int    $size
716
     *
717
     * @return string
718
     */
719
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
720
    {
721
        return self::return_icon($icon, null, null, $size, null, true, false);
722
    }
723
724
    /**
725
     * This public function returns the htmlcode for an icon.
726
     *
727
     * @param string   The filename of the file (in the main/img/ folder
728
     * @param string   The alt text (probably a language variable)
729
     * @param array    Additional attributes (for instance height, width, onclick, ...)
730
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
731
     *
732
     * @return string An HTML string of the right <img> tag
733
     *
734
     * @author Patrick Cool <[email protected]>, Ghent University 2006
735
     * @author Julio Montoya 2010 Function improved, adding image constants
736
     * @author Yannick Warnier 2011 Added size handler
737
     *
738
     * @version Feb 2011
739
     */
740
    public static function return_icon(
741
        $image,
742
        $alt_text = '',
743
        $additional_attributes = [],
744
        $size = ICON_SIZE_SMALL,
745
        $show_text = true,
746
        $return_only_path = false,
747
        $loadThemeIcon = true
748
    ) {
749
        $code_path = api_get_path(SYS_PUBLIC_PATH);
750
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
751
        // The following path is checked to see if the file exist. It's
752
        // important to use the public path (i.e. web/css/) rather than the
753
        // internal path (/app/Resource/public/css/) because the path used
754
        // in the end must be the public path
755
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
756
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
757
758
        // Avoid issues with illegal string offset for legacy calls to this
759
        // method with an empty string rather than null or an empty array
760
        if (empty($additional_attributes)) {
761
            $additional_attributes = [];
762
        }
763
764
        $image = trim($image);
765
766
        if (isset($size)) {
767
            $size = (int) $size;
768
        } else {
769
            $size = ICON_SIZE_SMALL;
770
        }
771
772
        $size_extra = $size.'/';
773
        $icon = $w_code_path.'img/'.$image;
774
        $theme = 'themes/chamilo/icons/';
775
776
        if ($loadThemeIcon) {
777
            // @todo with chamilo 2 code
778
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
779
            if (is_file($alternateCssPath.$theme.$image)) {
780
                $icon = $alternateWebCssPath.$theme.$image;
781
            }
782
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
783
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
784
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
785
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
786
                //Checking the main/img/icons/XXX/ folder
787
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
788
            }
789
        } else {
790
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
791
                // Checking the main/img/icons/XXX/ folder
792
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
793
            }
794
        }
795
796
        // Special code to enable SVG - refs #7359 - Needs more work
797
        // The code below does something else to "test out" SVG: for each icon,
798
        // it checks if there is an SVG version. If so, it uses it.
799
        // When moving this to production, the return_icon() calls should
800
        // ask for the SVG version directly
801
        $svgIcons = api_get_setting('icons_mode_svg');
802
        if ('true' == $svgIcons && false == $return_only_path) {
803
            $svgImage = substr($image, 0, -3).'svg';
804
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
805
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
806
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
807
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
808
            }
809
810
            if (empty($additional_attributes['height'])) {
811
                $additional_attributes['height'] = $size;
812
            }
813
            if (empty($additional_attributes['width'])) {
814
                $additional_attributes['width'] = $size;
815
            }
816
        }
817
818
        if ($return_only_path) {
819
            return $icon;
820
        }
821
822
        $img = self::img($icon, $alt_text, $additional_attributes);
823
        if (SHOW_TEXT_NEAR_ICONS == true && !empty($alt_text)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
824
            if ($show_text) {
825
                $img = "$img $alt_text";
826
            }
827
        }
828
829
        return $img;
830
    }
831
832
    /**
833
     * Returns the htmlcode for an image.
834
     *
835
     * @param string $image_path            the filename of the file (in the main/img/ folder
836
     * @param string $alt_text              the alt text (probably a language variable)
837
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
838
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
839
     *
840
     * @return string
841
     *
842
     * @author Julio Montoya 2010
843
     */
844
    public static function img(
845
        $image_path,
846
        $alt_text = '',
847
        $additional_attributes = null,
848
        $filterPath = true
849
    ) {
850
        if (empty($image_path)) {
851
            return '';
852
        }
853
        // Sanitizing the parameter $image_path
854
        if ($filterPath) {
855
            $image_path = Security::filter_img_path($image_path);
856
        }
857
858
        // alt text = the image name if there is none provided (for XHTML compliance)
859
        if ('' == $alt_text) {
860
            $alt_text = basename($image_path);
861
        }
862
863
        if (empty($additional_attributes)) {
864
            $additional_attributes = [];
865
        }
866
867
        $additional_attributes['src'] = $image_path;
868
869
        if (empty($additional_attributes['alt'])) {
870
            $additional_attributes['alt'] = $alt_text;
871
        }
872
        if (empty($additional_attributes['title'])) {
873
            $additional_attributes['title'] = $alt_text;
874
        }
875
876
        return self::tag('img', '', $additional_attributes);
877
    }
878
879
    /**
880
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
881
     *
882
     * @param string $tag                   the tag name
883
     * @param string $content               the tag's content
884
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
885
     *
886
     * @return string
887
     *
888
     * @author Julio Montoya 2010
889
     */
890
    public static function tag($tag, $content, $additional_attributes = [])
891
    {
892
        $attribute_list = '';
893
        // Managing the additional attributes
894
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
895
            $attribute_list = '';
896
            foreach ($additional_attributes as $key => &$value) {
897
                $attribute_list .= $key.'="'.$value.'" ';
898
            }
899
        }
900
        //some tags don't have this </XXX>
901
        if (in_array($tag, ['img', 'input', 'br'])) {
902
            $return_value = '<'.$tag.' '.$attribute_list.' />';
903
        } else {
904
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
905
        }
906
907
        return $return_value;
908
    }
909
910
    /**
911
     * Creates a URL anchor.
912
     *
913
     * @param string $name
914
     * @param string $url
915
     * @param array  $attributes
916
     *
917
     * @return string
918
     */
919
    public static function url($name, $url, $attributes = [])
920
    {
921
        if (!empty($url)) {
922
            $url = preg_replace('#&amp;#', '&', $url);
923
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
924
            $attributes['href'] = $url;
925
        }
926
927
        return self::tag('a', $name, $attributes);
928
    }
929
930
    /**
931
     * Creates a div tag.
932
     *
933
     * @param string $content
934
     * @param array  $attributes
935
     *
936
     * @return string
937
     */
938
    public static function div($content, $attributes = [])
939
    {
940
        return self::tag('div', $content, $attributes);
941
    }
942
943
    /**
944
     * Creates a span tag.
945
     */
946
    public static function span($content, $attributes = [])
947
    {
948
        return self::tag('span', $content, $attributes);
949
    }
950
951
    /**
952
     * Displays an HTML input tag.
953
     */
954
    public static function input($type, $name, $value, $attributes = [])
955
    {
956
        if (isset($type)) {
957
            $attributes['type'] = $type;
958
        }
959
        if (isset($name)) {
960
            $attributes['name'] = $name;
961
        }
962
        if (isset($value)) {
963
            $attributes['value'] = $value;
964
        }
965
966
        return self::tag('input', '', $attributes);
967
    }
968
969
    /**
970
     * @param $name
971
     * @param $value
972
     * @param array $attributes
973
     *
974
     * @return string
975
     */
976
    public static function button($name, $value, $attributes = [])
977
    {
978
        if (!empty($name)) {
979
            $attributes['name'] = $name;
980
        }
981
982
        return self::tag('button', $value, $attributes);
983
    }
984
985
    /**
986
     * Displays an HTML select tag.
987
     *
988
     * @param string $name
989
     * @param array  $values
990
     * @param int    $default
991
     * @param array  $extra_attributes
992
     * @param bool   $show_blank_item
993
     * @param string $blank_item_text
994
     *
995
     * @return string
996
     */
997
    public static function select(
998
        $name,
999
        $values,
1000
        $default = -1,
1001
        $extra_attributes = [],
1002
        $show_blank_item = true,
1003
        $blank_item_text = ''
1004
    ) {
1005
        $html = '';
1006
        $extra = '';
1007
        $default_id = 'id="'.$name.'" ';
1008
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1009
        foreach ($extra_attributes as $key => $parameter) {
1010
            if ('id' == $key) {
1011
                $default_id = '';
1012
            }
1013
            $extra .= $key.'="'.$parameter.'" ';
1014
        }
1015
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1016
1017
        if ($show_blank_item) {
1018
            if (empty($blank_item_text)) {
1019
                $blank_item_text = get_lang('Select');
1020
            } else {
1021
                $blank_item_text = Security::remove_XSS($blank_item_text);
1022
            }
1023
            $html .= self::tag(
1024
                'option',
1025
                '-- '.$blank_item_text.' --',
0 ignored issues
show
Bug introduced by
Are you sure $blank_item_text of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1025
                '-- './** @scrutinizer ignore-type */ $blank_item_text.' --',
Loading history...
1026
                ['value' => '-1']
1027
            );
1028
        }
1029
        if ($values) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1030
            foreach ($values as $key => $value) {
1031
                if (is_array($value) && isset($value['name'])) {
1032
                    $value = $value['name'];
1033
                }
1034
                $html .= '<option value="'.$key.'"';
1035
1036
                if (is_array($default)) {
1037
                    foreach ($default as $item) {
1038
                        if ($item == $key) {
1039
                            $html .= ' selected="selected"';
1040
                            break;
1041
                        }
1042
                    }
1043
                } else {
1044
                    if ($default == $key) {
1045
                        $html .= ' selected="selected"';
1046
                    }
1047
                }
1048
1049
                $html .= '>'.$value.'</option>';
1050
            }
1051
        }
1052
        $html .= '</select>';
1053
1054
        return $html;
1055
    }
1056
1057
    /**
1058
     * Creates a tab menu
1059
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1060
     * in the $htmlHeadXtra variable before the display_header
1061
     * Add this script.
1062
     *
1063
     * @param array  $headers       list of the tab titles
1064
     * @param array  $items
1065
     * @param string $id            id of the container of the tab in the example "tabs"
1066
     * @param array  $attributes    for the ul
1067
     * @param array  $ul_attributes
1068
     * @param string $selected
1069
     *
1070
     * @return string
1071
     */
1072
    public static function tabs(
1073
        $headers,
1074
        $items,
1075
        $id = 'tabs',
1076
        $attributes = [],
1077
        $ul_attributes = [],
1078
        $selected = ''
1079
    ) {
1080
        if (empty($headers) || 0 === count($headers)) {
1081
            return '';
1082
        }
1083
1084
        $lis = '';
1085
        $i = 1;
1086
        foreach ($headers as $item) {
1087
            $active = '';
1088
            if (1 == $i) {
1089
                $active = ' active';
1090
            }
1091
1092
            if (!empty($selected)) {
1093
                $active = '';
1094
                if ($selected == $i) {
1095
                    $active = ' active';
1096
                }
1097
            }
1098
1099
            $item = self::tag(
1100
                'a',
1101
                $item,
1102
                [
1103
                    //'href' => '#'.$id.'-'.$i,
1104
                    'href' => 'javascript:void(0)',
1105
                    'class' => 'nav-item nav-link '.$active,
1106
                    '@click' => "openTab =  $i",
1107
                    'id' => $id.$i.'-tab',
1108
                    'data-toggle' => 'tab',
1109
                    'role' => 'tab',
1110
                    'aria-controls' => $id.'-'.$i,
1111
                    'aria-selected' => $selected,
1112
                ]
1113
            );
1114
            $lis .= $item;
1115
            $i++;
1116
        }
1117
1118
        $ul = self::tag(
1119
            'nav',
1120
            $lis,
1121
            [
1122
                'id' => 'nav_'.$id,
1123
                'class' => 'nav nav-tabs',
1124
                'role' => 'tablist',
1125
            ]
1126
        );
1127
1128
        $i = 1;
1129
        $divs = '';
1130
        foreach ($items as $content) {
1131
            $active = '';
1132
            if (1 == $i) {
1133
                $active = ' show active';
1134
            }
1135
1136
            if (!empty($selected)) {
1137
                $active = '';
1138
                if ($selected == $i) {
1139
                    $active = ' show active';
1140
                }
1141
            }
1142
1143
            $divs .= self::tag(
1144
                'div',
1145
                $content,
1146
                [
1147
                    'id' => $id.'-'.$i,
1148
                    'x-show' => "openTab === $i",
1149
                    //'class' => 'tab-pane fade '.$active,
1150
                    //'role' => 'tabpanel',
1151
                    //'aria-labelledby' => $id.$i.'-tab',
1152
                ]
1153
            );
1154
            $i++;
1155
        }
1156
1157
        $attributes['id'] = ''.$id;
1158
        $attributes['class'] = 'tab_wrapper ';
1159
        $attributes['x-data'] = ' { openTab: 1 } ';
1160
1161
        return self::tag(
1162
            'div',
1163
            $ul.
1164
            $divs,
1165
            $attributes
1166
        );
1167
    }
1168
1169
    /**
1170
     * @param $headers
1171
     * @param null $selected
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $selected is correct as it would always require null to be passed?
Loading history...
1172
     *
1173
     * @return string
1174
     */
1175
    public static function tabsOnlyLink($headers, $selected = null)
1176
    {
1177
        $id = uniqid('tabs_');
1178
        $i = 1;
1179
        $list = '';
1180
        foreach ($headers as $item) {
1181
            $class = null;
1182
            if ($i == $selected) {
1183
                $class = 'active';
1184
            }
1185
            $item = self::tag(
1186
                'a',
1187
                $item['content'],
1188
                [
1189
                    'id' => $id.'-'.$i,
1190
                    'href' => $item['url'],
1191
                    'class' => 'btn '.$class,
1192
                ]
1193
            );
1194
            $list .= $item;
1195
            $i++;
1196
        }
1197
1198
        return self::toolbarAction($id, [$list]);
1199
    }
1200
1201
    /**
1202
     * In order to display a grid using jqgrid you have to:.
1203
     *
1204
     * @example
1205
     * After your Display::display_header function you have to add the nex javascript code:
1206
     * <script>
1207
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1208
     *   // for more information of this function check the grid_js() function
1209
     * </script>
1210
     * //Then you have to call the grid_html
1211
     * echo Display::grid_html('my_grid_name');
1212
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1213
     *
1214
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1215
     *
1216
     * @return string html
1217
     */
1218
    public static function grid_html($div_id)
1219
    {
1220
        $table = self::tag('table', '', ['id' => $div_id]);
1221
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1222
1223
        return $table;
1224
    }
1225
1226
    /**
1227
     * This is a wrapper to use the jqgrid in Chamilo.
1228
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1229
     * This function need to be in the ready jquery function
1230
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1231
     * In order to work this function needs the Display::grid_html function with the same div id.
1232
     *
1233
     * @param string $div_id       div id
1234
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1235
     * @param array  $column_names Visible columns (you should use get_lang).
1236
     *                             An array in which we place the names of the columns.
1237
     *                             This is the text that appears in the head of the grid (Header layer).
1238
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1239
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1240
     *                             This is the most important part of the grid.
1241
     *                             For a full description of all valid values see colModel API. See the url above.
1242
     * @param array  $extra_params extra parameters
1243
     * @param array  $data         data that will be loaded
1244
     * @param string $formatter    A string that will be appended to the JSON returned
1245
     * @param bool   $fixed_width  not implemented yet
1246
     *
1247
     * @return string the js code
1248
     */
1249
    public static function grid_js(
1250
        $div_id,
1251
        $url,
1252
        $column_names,
1253
        $column_model,
1254
        $extra_params,
1255
        $data = [],
1256
        $formatter = '',
1257
        $fixed_width = false
1258
    ) {
1259
        $obj = new stdClass();
1260
        $obj->first = 'first';
1261
1262
        if (!empty($url)) {
1263
            $obj->url = $url;
1264
        }
1265
1266
        // Needed it in order to render the links/html in the grid
1267
        foreach ($column_model as &$columnModel) {
1268
            if (!isset($columnModel['formatter'])) {
1269
                $columnModel['formatter'] = '';
1270
            }
1271
        }
1272
1273
        //This line should only be used/modified in case of having characters
1274
        // encoding problems - see #6159
1275
        //$column_names = array_map("utf8_encode", $column_names);
1276
        $obj->colNames = $column_names;
1277
        $obj->colModel = $column_model;
1278
        $obj->pager = '#'.$div_id.'_pager';
1279
        $obj->datatype = 'json';
1280
        $obj->viewrecords = 'true';
1281
        $obj->guiStyle = 'bootstrap4';
1282
        $obj->iconSet = 'fontAwesomeSolid';
1283
        $all_value = 10000000;
1284
1285
        // Sets how many records we want to view in the grid
1286
        $obj->rowNum = 20;
1287
1288
        // Default row quantity
1289
        if (!isset($extra_params['rowList'])) {
1290
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1291
            $rowList = api_get_configuration_value('table_row_list');
1292
            if (!empty($rowList) && isset($rowList['options'])) {
1293
                $rowList = $rowList['options'];
1294
                $rowList[] = $all_value;
1295
            }
1296
            $extra_params['rowList'] = $rowList;
1297
        }
1298
1299
        $defaultRow = api_get_configuration_value('table_default_row');
1300
        if (!empty($defaultRow)) {
1301
            $obj->rowNum = (int) $defaultRow;
1302
        }
1303
1304
        $json = '';
1305
        if (!empty($extra_params['datatype'])) {
1306
            $obj->datatype = $extra_params['datatype'];
1307
        }
1308
1309
        // Row even odd style.
1310
        $obj->altRows = true;
1311
        if (!empty($extra_params['altRows'])) {
1312
            $obj->altRows = $extra_params['altRows'];
1313
        }
1314
1315
        if (!empty($extra_params['sortname'])) {
1316
            $obj->sortname = $extra_params['sortname'];
1317
        }
1318
1319
        if (!empty($extra_params['sortorder'])) {
1320
            $obj->sortorder = $extra_params['sortorder'];
1321
        }
1322
1323
        if (!empty($extra_params['rowList'])) {
1324
            $obj->rowList = $extra_params['rowList'];
1325
        }
1326
1327
        if (!empty($extra_params['rowNum'])) {
1328
            $obj->rowNum = $extra_params['rowNum'];
1329
        } else {
1330
            // Try to load max rows from Session
1331
            $urlInfo = parse_url($url);
1332
            if (isset($urlInfo['query'])) {
1333
                parse_str($urlInfo['query'], $query);
1334
                if (isset($query['a'])) {
1335
                    $action = $query['a'];
1336
                    // This value is set in model.ajax.php
1337
                    $savedRows = Session::read('max_rows_'.$action);
1338
                    if (!empty($savedRows)) {
1339
                        $obj->rowNum = $savedRows;
1340
                    }
1341
                }
1342
            }
1343
        }
1344
1345
        if (!empty($extra_params['viewrecords'])) {
1346
            $obj->viewrecords = $extra_params['viewrecords'];
1347
        }
1348
1349
        $beforeSelectRow = null;
1350
        if (isset($extra_params['beforeSelectRow'])) {
1351
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1352
            unset($extra_params['beforeSelectRow']);
1353
        }
1354
1355
        $beforeProcessing = '';
1356
        if (isset($extra_params['beforeProcessing'])) {
1357
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1358
            unset($extra_params['beforeProcessing']);
1359
        }
1360
1361
        $beforeRequest = '';
1362
        if (isset($extra_params['beforeRequest'])) {
1363
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1364
            unset($extra_params['beforeRequest']);
1365
        }
1366
1367
        $gridComplete = '';
1368
        if (isset($extra_params['gridComplete'])) {
1369
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1370
            unset($extra_params['gridComplete']);
1371
        }
1372
1373
        // Adding extra params
1374
        if (!empty($extra_params)) {
1375
            foreach ($extra_params as $key => $element) {
1376
                // the groupHeaders key gets a special treatment
1377
                if ('groupHeaders' != $key) {
1378
                    $obj->$key = $element;
1379
                }
1380
            }
1381
        }
1382
1383
        // Adding static data.
1384
        if (!empty($data)) {
1385
            $data_var = $div_id.'_data';
1386
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1387
            $obj->data = $data_var;
1388
            $obj->datatype = 'local';
1389
            $json .= "\n";
1390
        }
1391
1392
        $obj->end = 'end';
1393
1394
        $json_encode = json_encode($obj);
1395
1396
        if (!empty($data)) {
1397
            //Converts the "data":"js_variable" to "data":js_variable,
1398
            // otherwise it will not work
1399
            $json_encode = str_replace('"data":"'.$data_var.'"', '"data":'.$data_var.'', $json_encode);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data_var does not seem to be defined for all execution paths leading up to this point.
Loading history...
1400
        }
1401
1402
        // Fixing true/false js values that doesn't need the ""
1403
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1404
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1405
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1406
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1407
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1408
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1409
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1410
1411
        if (api_get_configuration_value('allow_compilatio_tool') &&
1412
            (false !== strpos($_SERVER['REQUEST_URI'], 'work/work.php') ||
1413
             false != strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php')
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($_SERVER['REQUEST...ork/work_list_all.php') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1414
            )
1415
        ) {
1416
            $json_encode = str_replace('"function () { compilatioInit() }"',
1417
                'function () { compilatioInit() }',
1418
                $json_encode
1419
            );
1420
        }
1421
        // Creating the jqgrid element.
1422
        $json .= '$("#'.$div_id.'").jqGrid({';
1423
        //$json .= $beforeSelectRow;
1424
        $json .= $gridComplete;
1425
        $json .= $beforeProcessing;
1426
        $json .= $beforeRequest;
1427
        $json .= $json_encode;
1428
        $json .= '});';
1429
1430
        // Grouping headers option
1431
        if (isset($extra_params['groupHeaders'])) {
1432
            $groups = '';
1433
            foreach ($extra_params['groupHeaders'] as $group) {
1434
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1435
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1436
            }
1437
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1438
                "useColSpanStyle" : false,
1439
                "groupHeaders"    : [
1440
                    '.$groups.'
1441
                ]
1442
            });';
1443
        }
1444
1445
        $all_text = addslashes(get_lang('All'));
1446
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1447
        $json .= "\n";
1448
        // Adding edit/delete icons.
1449
        $json .= $formatter;
1450
1451
        return $json;
1452
    }
1453
1454
    /**
1455
     * @param array $headers
1456
     * @param array $rows
1457
     * @param array $attributes
1458
     *
1459
     * @return string
1460
     */
1461
    public static function table($headers, $rows, $attributes = [])
1462
    {
1463
        if (empty($attributes)) {
1464
            $attributes['class'] = 'data_table';
1465
        }
1466
        $table = new HTML_Table($attributes);
1467
        $row = 0;
1468
        $column = 0;
1469
1470
        // Course headers
1471
        if (!empty($headers)) {
1472
            foreach ($headers as $item) {
1473
                $table->setHeaderContents($row, $column, $item);
1474
                $column++;
1475
            }
1476
            $row = 1;
1477
            $column = 0;
1478
        }
1479
1480
        if (!empty($rows)) {
1481
            foreach ($rows as $content) {
1482
                $table->setCellContents($row, $column, $content);
1483
                $row++;
1484
            }
1485
        }
1486
1487
        return $table->toHtml();
1488
    }
1489
1490
    /**
1491
     * Returns the "what's new" icon notifications.
1492
     *
1493
     * The general logic of this function is to track the last time the user
1494
     * entered the course and compare to what has changed inside this course
1495
     * since then, based on the item_property table inside this course. Note that,
1496
     * if the user never entered the course before, he will not see notification
1497
     * icons. This function takes session ID into account (if any) and only shows
1498
     * the corresponding notifications.
1499
     *
1500
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1501
     * @param bool  $loadAjax
1502
     *
1503
     * @return string The HTML link to be shown next to the course
1504
     */
1505
    public static function show_notification($courseInfo, $loadAjax = true)
1506
    {
1507
        // @todo
1508
        return '';
1509
    }
1510
1511
    /**
1512
     * Get the session box details as an array.
1513
     *
1514
     * @todo check session visibility.
1515
     *
1516
     * @param int $session_id
1517
     *
1518
     * @return array Empty array or session array
1519
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1520
     */
1521
    public static function getSessionTitleBox($session_id)
1522
    {
1523
        $session_info = api_get_session_info($session_id);
1524
        $coachInfo = [];
1525
        if (!empty($session_info['id_coach'])) {
1526
            $coachInfo = api_get_user_info($session_info['id_coach']);
1527
        }
1528
1529
        $session = [];
1530
        $session['category_id'] = $session_info['session_category_id'];
1531
        $session['title'] = $session_info['name'];
1532
        $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1533
        $session['dates'] = '';
1534
        $session['coach'] = '';
1535
        if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1536
            $session['coach'] = get_lang('General coach').': '.$coachInfo['complete_name'];
1537
        }
1538
        $active = false;
1539
        if (('0000-00-00 00:00:00' === $session_info['access_end_date'] &&
1540
            '0000-00-00 00:00:00' === $session_info['access_start_date']) ||
1541
            (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1542
        ) {
1543
            if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1544
                $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1545
                $session['duration'] = $daysLeft >= 0
1546
                    ? sprintf(get_lang('This session has a maximum duration. Only %s days to go.'), $daysLeft)
1547
                    : get_lang('You are already registered but your allowed access time has expired.');
1548
            }
1549
            $active = true;
1550
        } else {
1551
            $dates = SessionManager::parseSessionDates($session_info, true);
1552
            $session['dates'] = $dates['access'];
1553
            if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1554
                $session['coach'] = $coachInfo['complete_name'];
1555
            }
1556
            //$active = $date_start <= $now && $date_end >= $now;
1557
        }
1558
        $session['active'] = $active;
1559
        $session['session_category_id'] = $session_info['session_category_id'];
1560
        $session['visibility'] = $session_info['visibility'];
1561
        $session['num_users'] = $session_info['nbr_users'];
1562
        $session['num_courses'] = $session_info['nbr_courses'];
1563
        $session['description'] = $session_info['description'];
1564
        $session['show_description'] = $session_info['show_description'];
1565
        //$session['image'] = SessionManager::getSessionImage($session_info['id']);
1566
        $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1567
1568
        $entityManager = Database::getManager();
1569
        $fieldValuesRepo = $entityManager->getRepository(ExtraFieldValues::class);
1570
        $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1571
            ExtraField::SESSION_FIELD_TYPE,
1572
            $session_id
1573
        );
1574
1575
        $session['extra_fields'] = [];
1576
        /** @var ExtraFieldValues $value */
1577
        foreach ($extraFieldValues as $value) {
1578
            if (empty($value)) {
1579
                continue;
1580
            }
1581
            $session['extra_fields'][] = [
1582
                'field' => [
1583
                    'variable' => $value->getField()->getVariable(),
1584
                    'display_text' => $value->getField()->getDisplayText(),
1585
                ],
1586
                'value' => $value->getValue(),
1587
            ];
1588
        }
1589
1590
        return $session;
1591
    }
1592
1593
    /**
1594
     * Return the five star HTML.
1595
     *
1596
     * @param string $id              of the rating ul element
1597
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1598
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1599
     * @param bool   $add_div_wrapper add a div wrapper
1600
     *
1601
     * @return string
1602
     */
1603
    public static function return_rating_system(
1604
        $id,
1605
        $url,
1606
        $point_info = [],
1607
        $add_div_wrapper = true
1608
    ) {
1609
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1610
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1611
1612
        if (!empty($percentage)) {
1613
            $percentage = $percentage * 125 / 100;
1614
        }
1615
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1616
        $star_label = sprintf(get_lang('%s stars out of 5'), $point_info['point_average_star']);
1617
1618
        $html = '<section class="rating-widget">';
1619
        $html .= '<div class="rating-stars"><ul id="stars">';
1620
        $html .= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1621
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1622
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1623
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1624
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1625
        ';
1626
        $html .= '</ul></div>';
1627
        $html .= '</section>';
1628
        $labels = [];
1629
1630
        $labels[] = 1 == $number_of_users_who_voted ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1631
        $labels[] = 1 == $accesses ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1632
        $labels[] = $point_info['user_vote'] ? get_lang('Your vote').' ['.$point_info['user_vote'].']' : get_lang('Your vote').' [?] ';
1633
1634
        if (!$add_div_wrapper && api_is_anonymous()) {
1635
            $labels[] = self::tag('span', get_lang('Login to vote'), ['class' => 'error']);
1636
        }
1637
1638
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1639
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1640
1641
        if ($add_div_wrapper) {
1642
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1643
        }
1644
1645
        return $html;
1646
    }
1647
1648
    /**
1649
     * @param string $title
1650
     * @param string $second_title
1651
     * @param string $size
1652
     * @param bool   $filter
1653
     *
1654
     * @return string
1655
     */
1656
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1657
    {
1658
        if ($filter) {
1659
            $title = Security::remove_XSS($title);
1660
        }
1661
1662
        if (!empty($second_title)) {
1663
            if ($filter) {
1664
                $second_title = Security::remove_XSS($second_title);
1665
            }
1666
            $title .= "<small> $second_title</small>";
1667
        }
1668
1669
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
0 ignored issues
show
Bug introduced by
Are you sure $title of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1669
        return '<'.$size.' class="page-header">'./** @scrutinizer ignore-type */ $title.'</'.$size.'>';
Loading history...
1670
    }
1671
1672
    public static function page_header_and_translate($title, $second_title = null)
1673
    {
1674
        $title = get_lang($title);
1675
1676
        return self::page_header($title, $second_title);
1677
    }
1678
1679
    public static function page_subheader_and_translate($title, $second_title = null)
1680
    {
1681
        $title = get_lang($title);
1682
1683
        return self::page_subheader($title, $second_title);
1684
    }
1685
1686
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1687
    {
1688
        if (!empty($second_title)) {
1689
            $second_title = Security::remove_XSS($second_title);
1690
            $title .= "<small> $second_title<small>";
1691
        }
1692
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1693
1694
        return $subTitle;
1695
    }
1696
1697
    public static function page_subheader2($title, $second_title = null)
1698
    {
1699
        return self::page_header($title, $second_title, 'h4');
1700
    }
1701
1702
    public static function page_subheader3($title, $second_title = null)
1703
    {
1704
        return self::page_header($title, $second_title, 'h5');
1705
    }
1706
1707
    /**
1708
     * @param array $list
1709
     *
1710
     * @return string|null
1711
     */
1712
    public static function description($list)
1713
    {
1714
        $html = null;
1715
        if (!empty($list)) {
1716
            $html = '<dl class="dl-horizontal">';
1717
            foreach ($list as $item) {
1718
                $html .= '<dt>'.$item['title'].'</dt>';
1719
                $html .= '<dd>'.$item['content'].'</dd>';
1720
            }
1721
            $html .= '</dl>';
1722
        }
1723
1724
        return $html;
1725
    }
1726
1727
    /**
1728
     * @param int    $percentage      int value between 0 and 100
1729
     * @param bool   $show_percentage
1730
     * @param string $extra_info
1731
     * @param string $class           danger/success/infowarning
1732
     *
1733
     * @return string
1734
     */
1735
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1736
    {
1737
        $percentage = (int) $percentage;
1738
        $class = empty($class) ? '' : "progress-bar-$class";
1739
1740
        $div = '<div class="progress">
1741
                <div
1742
                    class="progress-bar progress-bar-striped '.$class.'"
1743
                    role="progressbar"
1744
                    aria-valuenow="'.$percentage.'"
1745
                    aria-valuemin="0"
1746
                    aria-valuemax="100"
1747
                    style="width: '.$percentage.'%;"
1748
                >';
1749
        if ($show_percentage) {
1750
            $div .= $percentage.'%';
1751
        } else {
1752
            if (!empty($extra_info)) {
1753
                $div .= $extra_info;
1754
            }
1755
        }
1756
        $div .= '</div></div>';
1757
1758
        return $div;
1759
    }
1760
1761
    /**
1762
     * @param string $count
1763
     * @param string $type
1764
     *
1765
     * @return string|null
1766
     */
1767
    public static function badge($count, $type = 'warning')
1768
    {
1769
        $class = '';
1770
1771
        switch ($type) {
1772
            case 'success':
1773
                $class = 'bg-success';
1774
                break;
1775
            case 'warning':
1776
                $class = 'bg-warning text-dark';
1777
                break;
1778
            case 'important':
1779
                $class = 'bg-important';
1780
                break;
1781
            case 'info':
1782
                $class = 'bg-info';
1783
                break;
1784
            case 'inverse':
1785
                $class = 'bg-inverse';
1786
                break;
1787
        }
1788
1789
        if (!empty($count)) {
1790
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1791
        }
1792
1793
        return null;
1794
    }
1795
1796
    /**
1797
     * @param array $badge_list
1798
     *
1799
     * @return string
1800
     */
1801
    public static function badge_group($badge_list)
1802
    {
1803
        $html = '<div class="badge-group">';
1804
        foreach ($badge_list as $badge) {
1805
            $html .= $badge;
1806
        }
1807
        $html .= '</div>';
1808
1809
        return $html;
1810
    }
1811
1812
    /**
1813
     * @param string $content
1814
     * @param string $type
1815
     *
1816
     * @return string
1817
     */
1818
    public static function label($content, $type = 'default')
1819
    {
1820
        switch ($type) {
1821
            case 'success':
1822
                $class = 'success';
1823
                break;
1824
            case 'warning':
1825
                $class = 'warning text-dark';
1826
                break;
1827
            case 'important':
1828
            case 'danger':
1829
                $class = 'danger';
1830
                break;
1831
            case 'info':
1832
                $class = 'info';
1833
                break;
1834
            case 'primary':
1835
                $class = 'primary';
1836
                break;
1837
            default:
1838
                $class = 'secondary';
1839
                break;
1840
        }
1841
1842
        $html = '';
1843
        if (!empty($content)) {
1844
            $html = '<span class="badge bg-'.$class.'">';
1845
            $html .= $content;
1846
            $html .= '</span>';
1847
        }
1848
1849
        return $html;
1850
    }
1851
1852
    /**
1853
     * @param array  $items
1854
     * @param string $class
1855
     */
1856
    public static function actions($items, $class = 'new_actions'): string
1857
    {
1858
        if (empty($items)) {
1859
            return '';
1860
        }
1861
        $links = '';
1862
        foreach ($items as $value) {
1863
            /*$class = '';
1864
            if (isset($value['active']) && $value['active']) {
1865
                $class = 'class ="active"';
1866
            }
1867
1868
            if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
1869
                $class = 'class ="active"';
1870
            }
1871
            $html .= "<li $class >";*/
1872
1873
            $attributes = $value['url_attributes'] ?? [];
1874
            $links .= self::url($value['content'], $value['url'], $attributes);
1875
        }
1876
1877
        return self::toolbarAction(uniqid('toolbar', false), [$links]);
1878
    }
1879
1880
    /**
1881
     * Prints a tooltip.
1882
     *
1883
     * @param string $text
1884
     * @param string $tip
1885
     *
1886
     * @return string
1887
     */
1888
    public static function tip($text, $tip)
1889
    {
1890
        if (empty($tip)) {
1891
            return $text;
1892
        }
1893
1894
        return self::span(
1895
            $text,
1896
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
1897
        );
1898
    }
1899
1900
    /**
1901
     * @param array  $items
1902
     * @param string $type
1903
     * @param null   $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
1904
     *
1905
     * @return string|null
1906
     */
1907
    public static function generate_accordion($items, $type = 'jquery', $id = null)
1908
    {
1909
        $html = null;
1910
        if (!empty($items)) {
1911
            if (empty($id)) {
1912
                $id = api_get_unique_id();
1913
            }
1914
            if ('jquery' == $type) {
1915
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
1916
            } else {
1917
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
1918
            }
1919
1920
            $count = 1;
1921
            foreach ($items as $item) {
1922
                $html .= '<div class="accordion-my-group">';
1923
                $html .= '<div class="accordion-heading">
1924
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
1925
                            '.$item['title'].'
1926
                            </a>
1927
                          </div>';
1928
1929
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
1930
                $html .= '<div class="accordion-my-inner">
1931
                            '.$item['content'].'
1932
                            </div>
1933
                          </div>';
1934
            }
1935
            $html .= '</div>';
1936
        }
1937
1938
        return $html;
1939
    }
1940
1941
    /**
1942
     * @param array $buttons
1943
     *
1944
     * @return string
1945
     */
1946
    public static function groupButton($buttons)
1947
    {
1948
        $html = '<div class="btn-group" role="group">';
1949
        foreach ($buttons as $button) {
1950
            $html .= $button;
1951
        }
1952
        $html .= '</div>';
1953
1954
        return $html;
1955
    }
1956
1957
    /**
1958
     * @todo use twig
1959
     *
1960
     * @param string $title
1961
     * @param array  $elements
1962
     * @param bool   $alignToRight
1963
     *
1964
     * @return string
1965
     */
1966
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
1967
    {
1968
        $id = uniqid('dropdown', false);
1969
        $html = '
1970
        <div class="dropdown inline-block relative">
1971
            <button
1972
                id="'.$id.'"
1973
                type="button"
1974
                class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
1975
                aria-expanded="false"
1976
                aria-haspopup="true"
1977
            >
1978
              '.$title.'
1979
              <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
1980
                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
1981
              </svg>
1982
            </button>
1983
            <div
1984
                id="'.$id.'_menu"
1985
                class=" dropdown-menu hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
1986
                role="menu"
1987
                aria-orientation="vertical"
1988
                aria-labelledby="menu-button"
1989
                tabindex="-1"
1990
            >
1991
            <div class="py-1" role="none">';
1992
        foreach ($elements as $item) {
1993
            $html .= self::url(
1994
                    $item['title'],
1995
                    $item['href'],
1996
                    [
1997
                        'class' => 'text-gray-700 block px-4 py-2 text-sm',
1998
                        'role' => 'menuitem',
1999
                        'onclick' => $item['onclick'] ?? '',
2000
                        'data-action' => $item['data-action'] ?? '',
2001
                    ]
2002
                );
2003
        }
2004
        $html .= '
2005
            </div>
2006
            </div>
2007
            </div>
2008
            <script>
2009
             document.addEventListener("DOMContentLoaded", function() {
2010
                const button = document.querySelector("#'.$id.'");
2011
                    button.addEventListener("click", (e) => {
2012
                    let menu = document.querySelector("#'.$id.'_menu");
2013
                    if (menu.classList.contains("hidden")) {
2014
                        menu.classList.remove("hidden");
2015
                    } else {
2016
                        menu.classList.add("hidden");
2017
                    }
2018
                });
2019
            });
2020
            </script>';
2021
2022
        return $html;
2023
    }
2024
2025
    /**
2026
     * @param string $file
2027
     * @param array  $params
2028
     *
2029
     * @return string|null
2030
     */
2031
    public static function getMediaPlayer($file, $params = [])
2032
    {
2033
        $fileInfo = pathinfo($file);
2034
2035
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2036
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2037
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2038
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2039
2040
        switch ($fileInfo['extension']) {
2041
            case 'mp3':
2042
            case 'webm':
2043
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2044
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2045
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2046
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2047
                          </object>';
2048
                $html .= '</audio>';
2049
2050
                return $html;
2051
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2052
            case 'wav':
2053
            case 'ogg':
2054
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2055
2056
                return $html;
2057
                break;
2058
        }
2059
2060
        return null;
2061
    }
2062
2063
    /**
2064
     * @param int    $nextValue
2065
     * @param array  $list
2066
     * @param int    $current
2067
     * @param int    $fixedValue
2068
     * @param array  $conditions
2069
     * @param string $link
2070
     * @param bool   $isMedia
2071
     * @param bool   $addHeaders
2072
     * @param array  $linkAttributes
2073
     *
2074
     * @return string
2075
     */
2076
    public static function progressPaginationBar(
2077
        $nextValue,
2078
        $list,
2079
        $current,
2080
        $fixedValue = null,
2081
        $conditions = [],
2082
        $link = null,
2083
        $isMedia = false,
2084
        $addHeaders = true,
2085
        $linkAttributes = []
2086
    ) {
2087
        if ($addHeaders) {
2088
            $pagination_size = 'pagination-mini';
2089
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2090
        } else {
2091
            $html = null;
2092
        }
2093
        $affectAllItems = false;
2094
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2095
            $affectAllItems = true;
2096
        }
2097
        $localCounter = 0;
2098
        foreach ($list as $itemId) {
2099
            $isCurrent = false;
2100
            if ($affectAllItems) {
2101
                $isCurrent = true;
2102
            } else {
2103
                if (!$isMedia) {
2104
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2105
                }
2106
            }
2107
            $html .= self::parsePaginationItem(
2108
                $itemId,
2109
                $isCurrent,
2110
                $conditions,
2111
                $link,
2112
                $nextValue,
2113
                $isMedia,
2114
                $localCounter,
2115
                $fixedValue,
2116
                $linkAttributes
2117
            );
2118
            $localCounter++;
2119
        }
2120
        if ($addHeaders) {
2121
            $html .= '</ul></div>';
2122
        }
2123
2124
        return $html;
2125
    }
2126
2127
    /**
2128
     * @param int    $itemId
2129
     * @param bool   $isCurrent
2130
     * @param array  $conditions
2131
     * @param string $link
2132
     * @param int    $nextValue
2133
     * @param bool   $isMedia
2134
     * @param int    $localCounter
2135
     * @param int    $fixedValue
2136
     * @param array  $linkAttributes
2137
     *
2138
     * @return string
2139
     */
2140
    public static function parsePaginationItem(
2141
        $itemId,
2142
        $isCurrent,
2143
        $conditions,
2144
        $link,
2145
        $nextValue = 0,
2146
        $isMedia = false,
2147
        $localCounter = null,
2148
        $fixedValue = null,
2149
        $linkAttributes = []
2150
    ) {
2151
        $defaultClass = 'before';
2152
        $class = $defaultClass;
2153
        foreach ($conditions as $condition) {
2154
            $array = isset($condition['items']) ? $condition['items'] : [];
2155
            $class_to_applied = $condition['class'];
2156
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2157
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2158
            switch ($type) {
2159
                case 'positive':
2160
                    if (in_array($itemId, $array)) {
2161
                        if ('overwrite' == $mode) {
2162
                            $class = " $defaultClass $class_to_applied";
2163
                        } else {
2164
                            $class .= " $class_to_applied";
2165
                        }
2166
                    }
2167
                    break;
2168
                case 'negative':
2169
                    if (!in_array($itemId, $array)) {
2170
                        if ('overwrite' == $mode) {
2171
                            $class = " $defaultClass $class_to_applied";
2172
                        } else {
2173
                            $class .= " $class_to_applied";
2174
                        }
2175
                    }
2176
                    break;
2177
            }
2178
        }
2179
        if ($isCurrent) {
2180
            $class = 'before current';
2181
        }
2182
        if ($isMedia && $isCurrent) {
2183
            $class = 'before current';
2184
        }
2185
        if (empty($link)) {
2186
            $link_to_show = '#';
2187
        } else {
2188
            $link_to_show = $link.($nextValue + $localCounter);
2189
        }
2190
        $label = $nextValue + $localCounter + 1;
2191
        if ($isMedia) {
2192
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2193
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2194
        }
2195
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2196
2197
        return '<li class = "'.$class.'">'.$link.'</li>';
2198
    }
2199
2200
    /**
2201
     * @param int $current
2202
     * @param int $total
2203
     *
2204
     * @return string
2205
     */
2206
    public static function paginationIndicator($current, $total)
2207
    {
2208
        $html = null;
2209
        if (!empty($current) && !empty($total)) {
2210
            $label = sprintf(get_lang('%s of %s'), $current, $total);
2211
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2212
        }
2213
2214
        return $html;
2215
    }
2216
2217
    /**
2218
     * @param $url
2219
     * @param $currentPage
2220
     * @param $pagesCount
2221
     * @param $totalItems
2222
     *
2223
     * @return string
2224
     */
2225
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2226
    {
2227
        $pagination = '';
2228
        if ($totalItems > 1 && $pagesCount > 1) {
2229
            $pagination .= '<ul class="pagination">';
2230
            for ($i = 0; $i < $pagesCount; $i++) {
2231
                $newPage = $i + 1;
2232
                if ($currentPage == $newPage) {
2233
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2234
                } else {
2235
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2236
                }
2237
            }
2238
            $pagination .= '</ul>';
2239
        }
2240
2241
        return $pagination;
2242
    }
2243
2244
    /**
2245
     * Adds a legacy message in the queue.
2246
     *
2247
     * @param string $message
2248
     */
2249
    public static function addFlash($message)
2250
    {
2251
        // Detect type of message.
2252
        $parts = preg_match('/alert-([a-z]*)/', $message, $matches);
2253
        $type = 'primary';
2254
        if ($parts && isset($matches[1]) && $matches[1]) {
2255
            $type = $matches[1];
2256
        }
2257
        // Detect legacy content of message.
2258
        $result = preg_match('/<div(.*?)\>(.*?)\<\/div>/s', $message, $matches);
2259
        if ($result && isset($matches[2])) {
2260
            Container::getSession()->getFlashBag()->add($type, $matches[2]);
2261
        }
2262
    }
2263
2264
    /**
2265
     * Get the profile edition link for a user.
2266
     *
2267
     * @param int  $userId  The user id
2268
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2269
     *
2270
     * @return string The link
2271
     */
2272
    public static function getProfileEditionLink($userId, $asAdmin = false)
2273
    {
2274
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2275
        if ($asAdmin) {
2276
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2277
        }
2278
2279
        return $editProfileUrl;
2280
    }
2281
2282
    /**
2283
     * Get the vCard for a user.
2284
     *
2285
     * @param int $userId The user id
2286
     *
2287
     * @return string *.*vcf file
2288
     */
2289
    public static function getVCardUserLink($userId)
2290
    {
2291
        return api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2292
    }
2293
2294
    /**
2295
     * @param string $content
2296
     * @param string $title
2297
     * @param string $footer
2298
     * @param string $type        primary|success|info|warning|danger
2299
     * @param string $extra
2300
     * @param string $id
2301
     * @param string $customColor
2302
     * @param string $rightAction
2303
     *
2304
     * @return string
2305
     */
2306
    public static function panel(
2307
        $content,
2308
        $title = '',
2309
        $footer = '',
2310
        $type = 'default',
2311
        $extra = '',
2312
        $id = '',
2313
        $customColor = '',
2314
        $rightAction = ''
2315
    ) {
2316
        $headerStyle = '';
2317
        if (!empty($customColor)) {
2318
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2319
        }
2320
2321
        if (!empty($rightAction)) {
2322
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2323
        }
2324
2325
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2326
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2327
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2328
        $style = !in_array($type, $typeList) ? 'default' : $type;
2329
2330
        if (!empty($id)) {
2331
            $id = " id='$id'";
2332
        }
2333
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2334
2335
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2336
2337
        return '
2338
            <div '.$id.' class="card">
2339
                '.$panel.'
2340
            </div>'
2341
        ;
2342
    }
2343
2344
    /**
2345
     * @param string $content
2346
     */
2347
    public static function contentPanel($content): string
2348
    {
2349
        if (empty($content)) {
2350
            return '';
2351
        }
2352
2353
        return '<div class="card-text">'.$content.'</div>';
2354
    }
2355
2356
    /**
2357
     * Get the button HTML with an Awesome Font icon.
2358
     *
2359
     * @param string $text        The button content
2360
     * @param string $url         The url to button
2361
     * @param string $icon        The Awesome Font class for icon
2362
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2363
     * @param array  $attributes  The additional attributes
2364
     * @param bool   $includeText
2365
     *
2366
     * @return string The button HTML
2367
     */
2368
    public static function toolbarButton(
2369
        $text,
2370
        $url,
2371
        $icon = 'check',
2372
        $type = null,
2373
        array $attributes = [],
2374
        $includeText = true
2375
    ) {
2376
        $buttonClass = "btn btn-outline-secondary";
2377
        if (!empty($type)) {
2378
            $buttonClass = "btn btn-$type";
2379
        }
2380
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2381
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2382
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2383
2384
        if (!$includeText) {
2385
            $text = '<span class="sr-only">'.$text.'</span>';
2386
        }
2387
2388
        return self::url("$icon $text", $url, $attributes);
2389
    }
2390
2391
    public static function toolbarAction(string $id, array $contentList): string
2392
    {
2393
        $contentList = array_filter($contentList);
2394
2395
        if (empty($contentList)) {
2396
            return '';
2397
        }
2398
2399
        $col = count($contentList);
2400
        $html = ' <div id="'.$id.'" class="q-card p-2 mb-4">';
2401
        $html .= ' <div class="flex justify-between '.$col.'">';
2402
        foreach ($contentList as $item) {
2403
            $html .= '<div class="flex p-2 gap-2 ">'.$item.'</div>';
2404
        }
2405
        $html .= '</div>';
2406
        $html .= '</div>';
2407
2408
        return $html;
2409
    }
2410
2411
    public static function getMdiIcon($name)
2412
    {
2413
        return '<i class="mdi-'.$name.' mdi v-icon notranslate v-icon--size-default" aria-hidden="true" medium=""></i>';
2414
    }
2415
2416
    /**
2417
     * Get a HTML code for a icon by Font Awesome.
2418
     *
2419
     * @param string     $name            The icon name. Example: "mail-reply"
2420
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2421
     * @param bool       $fixWidth        Optional. Whether add the fw class
2422
     * @param string     $additionalClass Optional. Additional class
2423
     *
2424
     * @return string
2425
     */
2426
    public static function returnFontAwesomeIcon(
2427
        $name,
2428
        $size = '',
2429
        $fixWidth = false,
2430
        $additionalClass = ''
2431
    ) {
2432
        $className = "mdi mdi-$name";
2433
2434
        if ($fixWidth) {
2435
            $className .= ' fa-fw';
2436
        }
2437
2438
        switch ($size) {
2439
            case 'xs':
2440
            case 'sm':
2441
            case 'lg':
2442
                $className .= " fa-{$size}";
2443
                break;
2444
            case 2:
2445
            case 3:
2446
            case 4:
2447
            case 5:
2448
                $className .= " fa-{$size}x";
2449
                break;
2450
        }
2451
2452
        if (!empty($additionalClass)) {
2453
            $className .= " $additionalClass";
2454
        }
2455
2456
        $icon = self::tag('em', null, ['class' => $className]);
2457
2458
        return "$icon ";
2459
    }
2460
2461
    /**
2462
     * @param string     $title
2463
     * @param string     $content
2464
     * @param null       $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
2465
     * @param array      $params
2466
     * @param null       $idAccordion
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $idAccordion is correct as it would always require null to be passed?
Loading history...
2467
     * @param null       $idCollapse
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $idCollapse is correct as it would always require null to be passed?
Loading history...
2468
     * @param bool|true  $open
2469
     * @param bool|false $fullClickable
2470
     *
2471
     * @return string
2472
     *
2473
     * @todo rework function to easy use
2474
     */
2475
    public static function panelCollapse(
2476
        $title,
2477
        $content,
2478
        $id = null,
2479
        $params = [],
2480
        $idAccordion = null,
2481
        $idCollapse = null,
2482
        $open = true,
2483
        $fullClickable = false
2484
    ) {
2485
        if (!empty($idAccordion)) {
2486
            $headerClass = '';
2487
            $headerClass .= $fullClickable ? 'center-block ' : '';
2488
            $headerClass .= $open ? '' : 'collapsed';
2489
            $contentClass = 'panel-collapse collapse ';
2490
            $contentClass .= $open ? 'in' : '';
2491
            $ariaExpanded = $open ? 'true' : 'false';
2492
2493
            $html = <<<HTML
2494
                <div class="card" id="$id">
2495
                    <div class="card-header">
2496
                        $title
2497
                    </div>
2498
                    <div class="card-body">$content</div>
2499
                </div>
2500
HTML;
2501
        } else {
2502
            if (!empty($id)) {
2503
                $params['id'] = $id;
2504
            }
2505
            $params['class'] = 'card';
2506
            $html = '';
2507
            if (!empty($title)) {
2508
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2509
            }
2510
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2511
            $html = self::div($html, $params);
2512
        }
2513
2514
        return $html;
2515
    }
2516
2517
    /**
2518
     * Returns the string "1 day ago" with a link showing the exact date time.
2519
     *
2520
     * @param string $dateTime in UTC or a DateTime in UTC
2521
     *
2522
     * @return string
2523
     */
2524
    public static function dateToStringAgoAndLongDate($dateTime)
2525
    {
2526
        if (empty($dateTime) || '0000-00-00 00:00:00' === $dateTime) {
2527
            return '';
2528
        }
2529
2530
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2531
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2532
        }
2533
2534
        return self::tip(
2535
            date_to_str_ago($dateTime),
2536
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2537
            //api_get_local_time($dateTime)
2538
        );
2539
    }
2540
2541
    /**
2542
     * @param array  $userInfo
2543
     * @param string $status
2544
     * @param string $toolbar
2545
     *
2546
     * @return string
2547
     */
2548
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2549
    {
2550
        if (empty($userInfo)) {
2551
            return '';
2552
        }
2553
2554
        if (!empty($status)) {
2555
            $status = '<div class="items-user-status">'.$status.'</div>';
2556
        }
2557
2558
        if (!empty($toolbar)) {
2559
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2560
        }
2561
2562
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">
2563
                    <img src="'.$userInfo['avatar'].'" class="rounded" />
2564
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>
2565
                    <div class="card-body">
2566
                       <div class="card-title">
2567
                       '.$status.'
2568
                       '.$toolbar.'
2569
                       </div>
2570
                    </div>
2571
                    <hr />
2572
              </div>';
2573
    }
2574
2575
    /**
2576
     * @param string $fileName
2577
     * @param string $fileUrl
2578
     *
2579
     * @return string
2580
     */
2581
    public static function fileHtmlGuesser($fileName, $fileUrl)
2582
    {
2583
        $data = pathinfo($fileName);
2584
2585
        //$content = self::url($data['basename'], $fileUrl);
2586
        $content = '';
2587
        switch ($data['extension']) {
2588
            case 'webm':
2589
            case 'mp4':
2590
            case 'ogg':
2591
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2592
                // Allows video to play when loading during an ajax call
2593
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2594
                break;
2595
            case 'jpg':
2596
            case 'jpeg':
2597
            case 'gif':
2598
            case 'png':
2599
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2600
                break;
2601
            default:
2602
                //$html = self::url($data['basename'], $fileUrl);
2603
                break;
2604
        }
2605
        //$html = self::url($content, $fileUrl, ['ajax']);
2606
2607
        return $content;
2608
    }
2609
2610
    /**
2611
     * @param string $frameName
2612
     *
2613
     * @return string
2614
     */
2615
    public static function getFrameReadyBlock($frameName)
2616
    {
2617
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2618
        $videoFeatures = [
2619
            'playpause',
2620
            'current',
2621
            'progress',
2622
            'duration',
2623
            'tracks',
2624
            'volume',
2625
            'fullscreen',
2626
            'vrview',
2627
            'markersrolls',
2628
        ];
2629
        $features = api_get_configuration_value('video_features');
2630
        $videoPluginsJS = [];
2631
        $videoPluginCSS = [];
2632
        if (!empty($features) && isset($features['features'])) {
2633
            foreach ($features['features'] as $feature) {
2634
                if ('vrview' === $feature) {
2635
                    continue;
2636
                }
2637
                $defaultFeatures[] = $feature;
2638
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.js";
2639
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.css";
2640
            }
2641
        }
2642
2643
        $videoPluginFiles = '';
2644
        foreach ($videoPluginsJS as $file) {
2645
            $videoPluginFiles .= '{type: "script", src: "'.$webPublicPath.'assets/'.$file.'"},';
2646
        }
2647
2648
        $videoPluginCssFiles = '';
2649
        foreach ($videoPluginCSS as $file) {
2650
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webPublicPath.'assets/'.$file.'"},';
2651
        }
2652
2653
        $translateHtml = '';
2654
        $translate = api_get_configuration_value('translate_html');
2655
        if ($translate) {
2656
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2657
        }
2658
2659
        $lpJs = api_get_path(WEB_PUBLIC_PATH).'build/lp.js';
2660
        // {type:"script", src:"'.api_get_jquery_ui_js_web_path().'"},
2661
        // {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/markersrolls/markersrolls.js"},
2662
        // {type:"script", src:"'.$webPublicPath.'build/libs/mathjax/MathJax.js?config=AM_HTMLorMML"},
2663
        $videoFeatures = implode("','", $videoFeatures);
2664
        $frameReady = '
2665
        $.frameReady(function() {
2666
             $(function () {
2667
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2668
                    pluginPath: "'.$webPublicPath.'assets/mediaelement/plugins/",
2669
                    features: [\''.$videoFeatures.'\'],
2670
                    success: function(mediaElement, originalNode, instance) {
2671
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2672
                    },
2673
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2674
                });
2675
            });
2676
        },
2677
        "'.$frameName.'",
2678
        [
2679
            {type:"script", src:"'.$lpJs.'", deps: [
2680
2681
            {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2682
2683
            {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/mediaelement-and-player.min.js",
2684
                deps: [
2685
                {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/vrview/vrview.js"},
2686
                '.$videoPluginFiles.'
2687
            ]},
2688
            '.$translateHtml.'
2689
            ]},
2690
            '.$videoPluginCssFiles.'
2691
        ]);';
2692
2693
        return $frameReady;
2694
    }
2695
2696
    /**
2697
     * @param string $image
2698
     * @param int    $size
2699
     *
2700
     * @return string
2701
     */
2702
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2703
    {
2704
        return self::return_icon($image, '', [], $size, false, true);
2705
    }
2706
2707
    /**
2708
     * @param string $image
2709
     * @param int    $size
2710
     * @param string $name
2711
     *
2712
     * @return string
2713
     */
2714
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
2715
    {
2716
        return self::return_icon($image, $name, [], $size);
2717
    }
2718
2719
    /**
2720
     * @param $id
2721
     *
2722
     * @return array|mixed
2723
     */
2724
    public static function randomColor($id)
2725
    {
2726
        static $colors = [];
2727
2728
        if (!empty($colors[$id])) {
2729
            return $colors[$id];
2730
        } else {
2731
            $color = substr(md5(time() * $id), 0, 6);
2732
            $c1 = hexdec(substr($color, 0, 2));
2733
            $c2 = hexdec(substr($color, 2, 2));
2734
            $c3 = hexdec(substr($color, 4, 2));
2735
            $luminosity = $c1 + $c2 + $c3;
2736
2737
            $type = '#000000';
2738
            if ($luminosity < (255 + 255 + 255) / 2) {
2739
                $type = '#FFFFFF';
2740
            }
2741
2742
            $result = [
2743
                'color' => '#'.$color,
2744
                'luminosity' => $type,
2745
            ];
2746
            $colors[$id] = $result;
2747
2748
            return $result; // example: #fc443a
2749
        }
2750
    }
2751
2752
    public static function noDataView(string $title, string $icon, string $buttonTitle, string $url): string
2753
    {
2754
        $content = '<div id="no-data-view">';
2755
        $content .= '<h3>'.$title.'</h3>';
2756
        $content .= $icon;
2757
        $content .= '<div class="controls">';
2758
        $content .= self::url(
2759
            '<em class="fa fa-plus"></em> '.$buttonTitle,
2760
            $url,
2761
            ['class' => 'btn btn-primary']
2762
        );
2763
        $content .= '</div>';
2764
        $content .= '</div>';
2765
2766
        return $content;
2767
    }
2768
2769
    public static function prose($contents)
2770
    {
2771
        return "
2772
            <div class=''>
2773
                <div class='prose prose-blue'>
2774
                $contents
2775
                </div>
2776
            </div>
2777
            ";
2778
    }
2779
}
2780