Passed
Push — master ( 2a9d43...0c1a02 )
by Julito
09:45
created

Display::return_message()   B

Complexity

Conditions 10
Paths 15

Size

Total Lines 36
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 24
nc 15
nop 3
dl 0
loc 36
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Framework\Container;
8
use ChamiloSession as Session;
9
use Symfony\Component\HttpFoundation\Response;
10
11
/**
12
 * Class Display
13
 * Contains several public functions dealing with the display of
14
 * table data, messages, help topics, ...
15
 *
16
 * Include/require it in your code to use its public functionality.
17
 * There are also several display public functions in the main api library.
18
 *
19
 * All public functions static public functions inside a class called Display,
20
 * so you use them like this: e.g.
21
 * Display::return_message($message)
22
 */
23
class Display
24
{
25
    /** @var Template */
26
    public static $global_template;
27
    public static $preview_style = null;
28
    public static $legacyTemplate;
29
30
    /**
31
     * Constructor.
32
     */
33
    public function __construct()
34
    {
35
    }
36
37
    /**
38
     * @return array
39
     */
40
    public static function toolList()
41
    {
42
        return [
43
            'group',
44
            'work',
45
            'glossary',
46
            'forum',
47
            'course_description',
48
            'gradebook',
49
            'attendance',
50
            'course_progress',
51
            'notebook',
52
        ];
53
    }
54
55
    /**
56
     * Displays the page header.
57
     *
58
     * @param string The name of the page (will be showed in the page title)
59
     * @param string Optional help file name
60
     * @param string $page_header
61
     */
62
    public static function display_header(
63
        $tool_name = '',
64
        $help = null,
0 ignored issues
show
Unused Code introduced by
The parameter $help is not used and could be removed. ( Ignorable by Annotation )

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

64
        /** @scrutinizer ignore-unused */ $help = null,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
65
        $page_header = null
0 ignored issues
show
Unused Code introduced by
The parameter $page_header is not used and could be removed. ( Ignorable by Annotation )

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

65
        /** @scrutinizer ignore-unused */ $page_header = null

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
66
    ) {
67
        global $interbreadcrumb;
68
        $interbreadcrumb[] = ['url' => '#', 'name' => $tool_name];
69
70
        ob_start();
71
72
        return true;
73
    }
74
75
    /**
76
     * Displays the reduced page header (without banner).
77
     */
78
    public static function display_reduced_header()
79
    {
80
        ob_start();
81
        self::$legacyTemplate = '@ChamiloTheme/Layout/no_layout.html.twig';
82
        return true;
83
84
        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...
85
        self::$global_template = new Template(
86
            $tool_name,
87
            false,
88
            false,
89
            $show_learnpath
90
        );
91
    }
92
93
    /**
94
     * Display no header.
95
     */
96
    public static function display_no_header()
97
    {
98
        global $tool_name, $show_learnpath;
99
        self::$global_template = new Template(
100
            $tool_name,
101
            false,
102
            false,
103
            $show_learnpath
104
        );
105
    }
106
107
    /**
108
     * Display the page footer.
109
     */
110
    public static function display_footer()
111
    {
112
        $contents = ob_get_contents();
113
        if (ob_get_length()) {
114
            ob_end_clean();
115
        }
116
        $tpl = '@ChamiloTheme/Layout/layout_one_col.html.twig';
117
        if (!empty(self::$legacyTemplate)) {
118
            $tpl = self::$legacyTemplate;
119
        }
120
        $response = new Response();
121
        $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...
122
        global $interbreadcrumb, $htmlHeadXtra;
123
        $params['legacy_javascript'] = $htmlHeadXtra;
124
        $params['legacy_breadcrumb'] = $interbreadcrumb;
125
126
        $flash = Display::getFlashToString();
127
        Display::cleanFlashMessages();
128
        $params['flash_messages'] = $flash;
129
130
        $content = Container::getTemplating()->render($tpl, $params);
131
        $response->setContent($content);
132
        $response->send();
133
        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...
134
    }
135
136
    /**
137
     * Display the page footer.
138
     */
139
    public static function display_reduced_footer()
140
    {
141
        echo self::$global_template->show_footer_js_template();
142
        echo '</body></html>';
143
    }
144
145
    /**
146
     * Displays the tool introduction of a tool.
147
     *
148
     * @author Patrick Cool <[email protected]>, Ghent University
149
     *
150
     * @param string $tool          these are the constants that are used for indicating the tools
151
     * @param array  $editor_config Optional configuration settings for the online editor.
152
     *                              return: $tool return a string array list with the "define" in main_api.lib
153
     *
154
     * @return string html code for adding an introduction
155
     */
156
    public static function display_introduction_section(
157
        $tool,
158
        $editor_config = null
159
    ) {
160
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::return_introductio...($tool, $editor_config) targeting Display::return_introduction_section() 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...
161
    }
162
163
    /**
164
     * @param string $tool
165
     * @param array  $editor_config
166
     */
167
    public static function return_introduction_section(
168
        $tool,
169
        $editor_config = null
170
    ) {
171
        $moduleId = $tool;
172
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
173
            $introduction_section = null;
174
            require api_get_path(SYS_CODE_PATH).'inc/introductionSection.inc.php';
175
176
            return $introduction_section;
177
        }
178
    }
179
180
    /**
181
     * Displays a table.
182
     *
183
     * @param array  $header          Titles for the table header
184
     *                                each item in this array can contain 3 values
185
     *                                - 1st element: the column title
186
     *                                - 2nd element: true or false (column sortable?)
187
     *                                - 3th element: additional attributes for
188
     *                                th-tag (eg for column-width)
189
     *                                - 4the element: additional attributes for the td-tags
190
     * @param array  $content         2D-array with the tables content
191
     * @param array  $sorting_options Keys are:
192
     *                                'column' = The column to use as sort-key
193
     *                                'direction' = SORT_ASC or SORT_DESC
194
     * @param array  $paging_options  Keys are:
195
     *                                'per_page_default' = items per page when switching from
196
     *                                full-    list to per-page-view
197
     *                                'per_page' = number of items to show per page
198
     *                                'page_nr' = The page to display
199
     * @param array  $query_vars      Additional variables to add in the query-string
200
     * @param array  $form_actions
201
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
202
     * @param string $tableName
203
     * @param string $tableId
204
     *
205
     * @author [email protected]
206
     */
207
    public static function display_sortable_table(
208
        $header,
209
        $content,
210
        $sorting_options = [],
211
        $paging_options = [],
212
        $query_vars = null,
213
        $form_actions = [],
214
        $style = 'table',
215
        $tableName = 'tablename',
216
        $tableId = ''
217
    ) {
218
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
219
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
220
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
221
        if (is_array($query_vars)) {
222
            $table->set_additional_parameters($query_vars);
223
        }
224
        if ($style == 'table') {
225
            if (is_array($header) && count($header) > 0) {
226
                foreach ($header as $index => $header_item) {
227
                    $table->set_header(
228
                        $index,
229
                        isset($header_item[0]) ? $header_item[0] : null,
230
                        isset($header_item[1]) ? $header_item[1] : null,
231
                        isset($header_item[2]) ? $header_item[2] : null,
232
                        isset($header_item[3]) ? $header_item[3] : null
233
                    );
234
                }
235
            }
236
            $table->set_form_actions($form_actions);
237
            $table->display();
238
        } else {
239
            $table->display_grid();
240
        }
241
    }
242
243
    /**
244
     * Returns an HTML table with sortable column (through complete page refresh).
245
     *
246
     * @param array  $header
247
     * @param array  $content         Array of row arrays
248
     * @param array  $sorting_options
249
     * @param array  $paging_options
250
     * @param array  $query_vars
251
     * @param array  $form_actions
252
     * @param string $style
253
     *
254
     * @return string HTML string for array
255
     */
256
    public static function return_sortable_table(
257
        $header,
258
        $content,
259
        $sorting_options = [],
260
        $paging_options = [],
261
        $query_vars = null,
262
        $form_actions = [],
263
        $style = 'table'
264
    ) {
265
        ob_start();
266
        self::display_sortable_table(
267
            $header,
268
            $content,
269
            $sorting_options,
270
            $paging_options,
271
            $query_vars,
272
            $form_actions,
273
            $style
274
        );
275
        $content = ob_get_contents();
276
        ob_end_clean();
277
278
        return $content;
279
    }
280
281
    /**
282
     * Shows a nice grid.
283
     *
284
     * @param string grid name (important to create css)
285
     * @param array header content
286
     * @param array array with the information to show
287
     * @param array $paging_options Keys are:
288
     *                              'per_page_default' = items per page when switching from
289
     *                              full-    list to per-page-view
290
     *                              'per_page' = number of items to show per page
291
     *                              'page_nr' = The page to display
292
     *                              'hide_navigation' =  true to hide the navigation
293
     * @param array $query_vars     Additional variables to add in the query-string
294
     * @param array $form           actions Additional variables to add in the query-string
295
     * @param mixed An array with bool values to know which columns show.
296
     * i.e: $visibility_options= array(true, false) we will only show the first column
297
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
298
     */
299
    public static function display_sortable_grid(
300
        $name,
301
        $header,
302
        $content,
303
        $paging_options = [],
304
        $query_vars = null,
305
        $form_actions = [],
306
        $visibility_options = true,
307
        $sort_data = true,
308
        $grid_class = []
309
    ) {
310
        echo self::return_sortable_grid(
311
            $name,
312
            $header,
313
            $content,
314
            $paging_options,
315
            $query_vars,
316
            $form_actions,
317
            $visibility_options,
318
            $sort_data,
319
            $grid_class
320
        );
321
    }
322
323
    /**
324
     * Gets a nice grid in html string.
325
     *
326
     * @param string grid name (important to create css)
327
     * @param array header content
328
     * @param array array with the information to show
329
     * @param array $paging_options Keys are:
330
     *                              'per_page_default' = items per page when switching from
331
     *                              full-    list to per-page-view
332
     *                              'per_page' = number of items to show per page
333
     *                              'page_nr' = The page to display
334
     *                              'hide_navigation' =  true to hide the navigation
335
     * @param array $query_vars     Additional variables to add in the query-string
336
     * @param array $form           actions Additional variables to add in the query-string
337
     * @param mixed An array with bool values to know which columns show. i.e:
338
     *  $visibility_options= array(true, false) we will only show the first column
339
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
340
     * @param bool  true for sorting data or false otherwise
341
     * @param array grid classes
342
     *
343
     * @return string html grid
344
     */
345
    public static function return_sortable_grid(
346
        $name,
347
        $header,
0 ignored issues
show
Unused Code introduced by
The parameter $header is not used and could be removed. ( Ignorable by Annotation )

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

347
        /** @scrutinizer ignore-unused */ $header,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
348
        $content,
349
        $paging_options = [],
350
        $query_vars = null,
351
        $form_actions = [],
0 ignored issues
show
Unused Code introduced by
The parameter $form_actions is not used and could be removed. ( Ignorable by Annotation )

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

351
        /** @scrutinizer ignore-unused */ $form_actions = [],

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
352
        $visibility_options = true,
353
        $sort_data = true,
354
        $grid_class = [],
355
        $elementCount = 0
356
    ) {
357
        $column = 0;
358
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
359
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
360
        $table->total_number_of_items = intval($elementCount);
361
        if (is_array($query_vars)) {
362
            $table->set_additional_parameters($query_vars);
363
        }
364
365
        return $table->display_simple_grid(
366
            $visibility_options,
367
            $paging_options['hide_navigation'],
368
            $default_items_per_page,
369
            $sort_data,
370
            $grid_class
371
        );
372
    }
373
374
    /**
375
     * Displays a table with a special configuration.
376
     *
377
     * @param array $header          Titles for the table header
378
     *                               each item in this array can contain 3 values
379
     *                               - 1st element: the column title
380
     *                               - 2nd element: true or false (column sortable?)
381
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
382
     *                               - 4the element: additional attributes for the td-tags
383
     * @param array $content         2D-array with the tables content
384
     * @param array $sorting_options Keys are:
385
     *                               'column' = The column to use as sort-key
386
     *                               'direction' = SORT_ASC or SORT_DESC
387
     * @param array $paging_options  Keys are:
388
     *                               'per_page_default' = items per page when switching from full list to per-page-view
389
     *                               'per_page' = number of items to show per page
390
     *                               'page_nr' = The page to display
391
     * @param array $query_vars      Additional variables to add in the query-string
392
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
393
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
394
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
395
     * @param array $form_actions    Set optional forms actions
396
     *
397
     * @author Julio Montoya
398
     */
399
    public static function display_sortable_config_table(
400
        $table_name,
401
        $header,
402
        $content,
403
        $sorting_options = [],
404
        $paging_options = [],
405
        $query_vars = null,
406
        $column_show = [],
407
        $column_order = [],
408
        $form_actions = []
409
    ) {
410
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
411
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
412
413
        $table = new SortableTableFromArrayConfig(
414
            $content,
415
            $column,
416
            $default_items_per_page,
417
            $table_name,
418
            $column_show,
419
            $column_order
420
        );
421
422
        if (is_array($query_vars)) {
423
            $table->set_additional_parameters($query_vars);
424
        }
425
        // Show or hide the columns header
426
        if (is_array($column_show)) {
427
            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...
428
                if (!empty($column_show[$i])) {
429
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
430
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
431
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
432
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
433
                    $table->set_header($i, $val0, $val1, $val2, $val3);
434
                }
435
            }
436
        }
437
        $table->set_form_actions($form_actions);
438
        $table->display();
439
    }
440
441
    /**
442
     * Returns a div html string with.
443
     *
444
     * @param string $message
445
     * @param string $type    Example: confirm, normal, warning, error
446
     * @param bool   $filter  Whether to XSS-filter or not
447
     *
448
     * @return string Message wrapped into an HTML div
449
     */
450
    public static function return_message(
451
        $message,
452
        $type = 'normal',
453
        $filter = true
454
    ) {
455
        if (empty($message)) {
456
            return '';
457
        }
458
459
        if ($filter) {
460
            $message = api_htmlentities(
461
                $message,
462
                ENT_QUOTES,
463
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
464
            );
465
        }
466
467
        $class = '';
468
        switch ($type) {
469
            case 'warning':
470
                $class .= 'alert alert-warning';
471
                break;
472
            case 'error':
473
                $class .= 'alert alert-danger';
474
                break;
475
            case 'confirmation':
476
            case 'confirm':
477
            case 'success':
478
                $class .= 'alert alert-success';
479
                break;
480
            case 'normal':
481
            default:
482
                $class .= 'alert alert-info';
483
        }
484
485
        return self::div($message, ['class' => $class]);
486
    }
487
488
    /**
489
     * Returns an encrypted mailto hyperlink.
490
     *
491
     * @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...
492
     * @param string  clickable text
493
     * @param string  optional, class from stylesheet
494
     * @param bool $addExtraContent
495
     *
496
     * @return string encrypted mailto hyperlink
497
     */
498
    public static function encrypted_mailto_link(
499
        $email,
500
        $clickable_text = null,
501
        $style_class = '',
502
        $addExtraContent = false
503
    ) {
504
        if (is_null($clickable_text)) {
505
            $clickable_text = $email;
506
        }
507
508
        // "mailto:" already present?
509
        if (substr($email, 0, 7) !== 'mailto:') {
510
            $email = 'mailto:'.$email;
511
        }
512
513
        // Class (stylesheet) defined?
514
        if ($style_class !== '') {
515
            $style_class = ' class="'.$style_class.'"';
516
        }
517
518
        // Encrypt email
519
        $hmail = '';
520
        for ($i = 0; $i < strlen($email); $i++) {
521
            $hmail .= '&#'.ord($email[$i]).';';
522
        }
523
524
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
525
526
        if ($value) {
527
            if (api_get_setting('allow_email_editor') === 'false') {
528
                $hmail .= '?';
529
            }
530
531
            if (!api_is_anonymous()) {
532
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
533
            }
534
            if ($addExtraContent) {
535
                $content = '';
536
                if (!api_is_anonymous()) {
537
                    $userInfo = api_get_user_info();
538
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
539
540
                    $courseInfo = api_get_course_info();
541
                    if (!empty($courseInfo)) {
542
                        $content .= get_lang('Course').': ';
543
                        $content .= $courseInfo['name'];
544
                        $sessionInfo = api_get_session_info(api_get_session_id());
545
                        if (!empty($sessionInfo)) {
546
                            $content .= ' '.$sessionInfo['name'].' <br />';
547
                        }
548
                    }
549
                }
550
                $hmail .= '&body='.rawurlencode($content);
551
            }
552
        }
553
554
        $hclickable_text = '';
555
        // Encrypt clickable text if @ is present
556
        if (strpos($clickable_text, '@')) {
557
            for ($i = 0; $i < strlen($clickable_text); $i++) {
558
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
559
            }
560
        } else {
561
            $hclickable_text = @htmlspecialchars(
562
                $clickable_text,
563
                ENT_QUOTES,
564
                api_get_system_encoding()
565
            );
566
        }
567
        // Return encrypted mailto hyperlink
568
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
569
    }
570
571
    /**
572
     * Returns an mailto icon hyperlink.
573
     *
574
     * @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...
575
     * @param string  icon source file from the icon lib
576
     * @param int  icon size from icon lib
577
     * @param string  optional, class from stylesheet
578
     *
579
     * @return string encrypted mailto hyperlink
580
     */
581
    public static function icon_mailto_link(
582
        $email,
583
        $icon_file = "mail.png",
584
        $icon_size = 22,
585
        $style_class = ''
586
    ) {
587
        // "mailto:" already present?
588
        if (substr($email, 0, 7) != 'mailto:') {
589
            $email = 'mailto:'.$email;
590
        }
591
        // Class (stylesheet) defined?
592
        if ($style_class != '') {
593
            $style_class = ' class="'.$style_class.'"';
594
        }
595
        // Encrypt email
596
        $hmail = '';
597
        for ($i = 0; $i < strlen($email); $i++) {
598
            $hmail .= '&#'.ord($email[
599
            $i]).';';
600
        }
601
        // icon html code
602
        $icon_html_source = self::return_icon(
603
            $icon_file,
604
            $hmail,
605
            '',
606
            $icon_size
607
        );
608
        // Return encrypted mailto hyperlink
609
610
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
611
    }
612
613
    /**
614
     * Prints an <option>-list with all letters (A-Z).
615
     *
616
     * @param string $selected_letter The letter that should be selected
617
     *
618
     * @todo This is English language specific implementation.
619
     * It should be adapted for the other languages.
620
     *
621
     * @return string
622
     */
623
    public static function get_alphabet_options($selectedLetter = '')
624
    {
625
        $result = '';
626
        for ($i = 65; $i <= 90; $i++) {
627
            $letter = chr($i);
628
            $result .= '<option value="'.$letter.'"';
629
            if ($selectedLetter == $letter) {
630
                $result .= ' selected="selected"';
631
            }
632
            $result .= '>'.$letter.'</option>';
633
        }
634
635
        return $result;
636
    }
637
638
    /**
639
     * Get the options withing a select box within the given values.
640
     *
641
     * @param int   Min value
642
     * @param int   Max value
643
     * @param int   Default value
644
     *
645
     * @return string HTML select options
646
     */
647
    public static function get_numeric_options($min, $max, $selected_num = 0)
648
    {
649
        $result = '';
650
        for ($i = $min; $i <= $max; $i++) {
651
            $result .= '<option value="'.$i.'"';
652
            if (is_int($selected_num)) {
653
                if ($selected_num == $i) {
654
                    $result .= ' selected="selected"';
655
                }
656
            }
657
            $result .= '>'.$i.'</option>';
658
        }
659
660
        return $result;
661
    }
662
663
    /**
664
     * This public function displays an icon.
665
     *
666
     * @param string   The filename of the file (in the main/img/ folder
667
     * @param string   The alt text (probably a language variable)
668
     * @param array    additional attributes (for instance height, width, onclick, ...)
669
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
670
     */
671
    public static function display_icon(
672
        $image,
673
        $alt_text = '',
674
        $additional_attributes = [],
675
        $size = null
676
    ) {
677
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
678
    }
679
680
    /**
681
     * Gets the path of an icon.
682
     *
683
     * @param string $icon
684
     * @param int    $size
685
     *
686
     * @return string
687
     */
688
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
689
    {
690
        return self::return_icon($icon, null, null, $size, null, true, false);
691
    }
692
693
    /**
694
     * This public function returns the htmlcode for an icon.
695
     *
696
     * @param string   The filename of the file (in the main/img/ folder
697
     * @param string   The alt text (probably a language variable)
698
     * @param array    Additional attributes (for instance height, width, onclick, ...)
699
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
700
     *
701
     * @return string An HTML string of the right <img> tag
702
     *
703
     * @author Patrick Cool <[email protected]>, Ghent University 2006
704
     * @author Julio Montoya 2010 Function improved, adding image constants
705
     * @author Yannick Warnier 2011 Added size handler
706
     *
707
     * @version Feb 2011
708
     */
709
    public static function return_icon(
710
        $image,
711
        $alt_text = '',
712
        $additional_attributes = [],
713
        $size = ICON_SIZE_SMALL,
714
        $show_text = true,
715
        $return_only_path = false,
716
        $loadThemeIcon = true
717
    ) {
718
        $code_path = api_get_path(SYS_PUBLIC_PATH);
719
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
720
        // The following path is checked to see if the file exist. It's
721
        // important to use the public path (i.e. web/css/) rather than the
722
        // internal path (/app/Resource/public/css/) because the path used
723
        // in the end must be the public path
724
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
725
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
726
727
        // Avoid issues with illegal string offset for legacy calls to this
728
        // method with an empty string rather than null or an empty array
729
        if (empty($additional_attributes)) {
730
            $additional_attributes = [];
731
        }
732
733
        $image = trim($image);
734
735
        if (isset($size)) {
736
            $size = (int) $size;
737
        } else {
738
            $size = ICON_SIZE_SMALL;
739
        }
740
741
        $size_extra = $size.'/';
742
        $icon = $w_code_path.'img/'.$image;
743
        $theme = 'themes/chamilo/icons/';
744
745
        if ($loadThemeIcon) {
746
            // @todo with chamilo 2 code
747
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
748
            if (is_file($alternateCssPath.$theme.$image)) {
749
                $icon = $alternateWebCssPath.$theme.$image;
750
            }
751
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
752
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
753
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
754
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
755
                //Checking the main/img/icons/XXX/ folder
756
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
757
            }
758
        } else {
759
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
760
                // Checking the main/img/icons/XXX/ folder
761
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
762
            }
763
        }
764
765
        // Special code to enable SVG - refs #7359 - Needs more work
766
        // The code below does something else to "test out" SVG: for each icon,
767
        // it checks if there is an SVG version. If so, it uses it.
768
        // When moving this to production, the return_icon() calls should
769
        // ask for the SVG version directly
770
        $svgIcons = api_get_setting('icons_mode_svg');
771
        if ($svgIcons == 'true' && $return_only_path == false) {
772
            $svgImage = substr($image, 0, -3).'svg';
773
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
774
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
775
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
776
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
777
            }
778
779
            if (empty($additional_attributes['height'])) {
780
                $additional_attributes['height'] = $size;
781
            }
782
            if (empty($additional_attributes['width'])) {
783
                $additional_attributes['width'] = $size;
784
            }
785
        }
786
787
        if ($return_only_path) {
788
            return $icon;
789
        }
790
791
        $img = self::img($icon, $alt_text, $additional_attributes);
792
        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...
793
            if ($show_text) {
794
                $img = "$img $alt_text";
795
            }
796
        }
797
798
        return $img;
799
    }
800
801
    /**
802
     * Returns the htmlcode for an image.
803
     *
804
     * @param string $image_path            the filename of the file (in the main/img/ folder
805
     * @param string $alt_text              the alt text (probably a language variable)
806
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
807
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
808
     *
809
     * @return string
810
     *
811
     * @author Julio Montoya 2010
812
     */
813
    public static function img(
814
        $image_path,
815
        $alt_text = '',
816
        $additional_attributes = null,
817
        $filterPath = true
818
    ) {
819
        if (empty($image_path)) {
820
            // For some reason, the call to img() happened without a proper
821
            // image. Log the error and return an empty string to avoid
822
            // breaking the HTML
823
            $trace = debug_backtrace();
824
            $caller = $trace[1];
825
            //error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
826
            return '';
827
        }
828
        // Sanitizing the parameter $image_path
829
        if ($filterPath) {
830
            $image_path = Security::filter_img_path($image_path);
831
        }
832
833
        // alt text = the image name if there is none provided (for XHTML compliance)
834
        if ($alt_text == '') {
835
            $alt_text = basename($image_path);
836
        }
837
838
        if (empty($additional_attributes)) {
839
            $additional_attributes = [];
840
        }
841
842
        $additional_attributes['src'] = $image_path;
843
844
        if (empty($additional_attributes['alt'])) {
845
            $additional_attributes['alt'] = $alt_text;
846
        }
847
        if (empty($additional_attributes['title'])) {
848
            $additional_attributes['title'] = $alt_text;
849
        }
850
851
        return self::tag('img', '', $additional_attributes);
852
    }
853
854
    /**
855
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
856
     *
857
     * @param string $tag                   the tag name
858
     * @param string $content               the tag's content
859
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
860
     *
861
     * @return string
862
     *
863
     * @author Julio Montoya 2010
864
     */
865
    public static function tag($tag, $content, $additional_attributes = [])
866
    {
867
        $attribute_list = '';
868
        // Managing the additional attributes
869
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
870
            $attribute_list = '';
871
            foreach ($additional_attributes as $key => &$value) {
872
                $attribute_list .= $key.'="'.$value.'" ';
873
            }
874
        }
875
        //some tags don't have this </XXX>
876
        if (in_array($tag, ['img', 'input', 'br'])) {
877
            $return_value = '<'.$tag.' '.$attribute_list.' />';
878
        } else {
879
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
880
        }
881
882
        return $return_value;
883
    }
884
885
    /**
886
     * Creates a URL anchor.
887
     *
888
     * @param string $name
889
     * @param string $url
890
     * @param array  $attributes
891
     *
892
     * @return string
893
     */
894
    public static function url($name, $url, $attributes = [])
895
    {
896
        if (!empty($url)) {
897
            $url = preg_replace('#&amp;#', '&', $url);
898
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
899
            $attributes['href'] = $url;
900
        }
901
902
        return self::tag('a', $name, $attributes);
903
    }
904
905
    /**
906
     * Creates a div tag.
907
     *
908
     * @param string $content
909
     * @param array  $attributes
910
     *
911
     * @return string
912
     */
913
    public static function div($content, $attributes = [])
914
    {
915
        return self::tag('div', $content, $attributes);
916
    }
917
918
    /**
919
     * Creates a span tag.
920
     */
921
    public static function span($content, $attributes = [])
922
    {
923
        return self::tag('span', $content, $attributes);
924
    }
925
926
    /**
927
     * Displays an HTML input tag.
928
     */
929
    public static function input($type, $name, $value, $attributes = [])
930
    {
931
        if (isset($type)) {
932
            $attributes['type'] = $type;
933
        }
934
        if (isset($name)) {
935
            $attributes['name'] = $name;
936
        }
937
        if (isset($value)) {
938
            $attributes['value'] = $value;
939
        }
940
941
        return self::tag('input', '', $attributes);
942
    }
943
944
    /**
945
     * @param $name
946
     * @param $value
947
     * @param array $attributes
948
     *
949
     * @return string
950
     */
951
    public static function button($name, $value, $attributes = [])
952
    {
953
        if (!empty($name)) {
954
            $attributes['name'] = $name;
955
        }
956
957
        return self::tag('button', $value, $attributes);
958
    }
959
960
    /**
961
     * Displays an HTML select tag.
962
     *
963
     * @param string $name
964
     * @param array  $values
965
     * @param int    $default
966
     * @param array  $extra_attributes
967
     * @param bool   $show_blank_item
968
     * @param null   $blank_item_text
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $blank_item_text is correct as it would always require null to be passed?
Loading history...
969
     *
970
     * @return string
971
     */
972
    public static function select(
973
        $name,
974
        $values,
975
        $default = -1,
976
        $extra_attributes = [],
977
        $show_blank_item = true,
978
        $blank_item_text = ''
979
    ) {
980
        $html = '';
981
        $extra = '';
982
        $default_id = 'id="'.$name.'" ';
983
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
984
        foreach ($extra_attributes as $key => $parameter) {
985
            if ($key == 'id') {
986
                $default_id = '';
987
            }
988
            $extra .= $key.'="'.$parameter.'" ';
989
        }
990
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
991
992
        if ($show_blank_item) {
993
            if (empty($blank_item_text)) {
994
                $blank_item_text = get_lang('Select');
995
            } else {
996
                $blank_item_text = Security::remove_XSS($blank_item_text);
997
            }
998
            $html .= self::tag(
999
                'option',
1000
                '-- '.$blank_item_text.' --',
1001
                ['value' => '-1']
1002
            );
1003
        }
1004
        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...
1005
            foreach ($values as $key => $value) {
1006
                if (is_array($value) && isset($value['name'])) {
1007
                    $value = $value['name'];
1008
                }
1009
                $html .= '<option value="'.$key.'"';
1010
1011
                if (is_array($default)) {
1012
                    foreach ($default as $item) {
1013
                        if ($item == $key) {
1014
                            $html .= ' selected="selected"';
1015
                            break;
1016
                        }
1017
                    }
1018
                } else {
1019
                    if ($default == $key) {
1020
                        $html .= ' selected="selected"';
1021
                    }
1022
                }
1023
1024
                $html .= '>'.$value.'</option>';
1025
            }
1026
        }
1027
        $html .= '</select>';
1028
1029
        return $html;
1030
    }
1031
1032
    /**
1033
     * Creates a tab menu
1034
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1035
     * in the $htmlHeadXtra variable before the display_header
1036
     * Add this script.
1037
     *
1038
     * @example
1039
     * <script>
1040
                </script>
1041
     * @param array  $headers       list of the tab titles
1042
     * @param array  $items
1043
     * @param string $id            id of the container of the tab in the example "tabs"
1044
     * @param array  $attributes    for the ul
1045
     * @param array  $ul_attributes
1046
     * @param int    $selected
1047
     *
1048
     * @return string
1049
     */
1050
    public static function tabs(
1051
        $headers,
1052
        $items,
1053
        $id = 'tabs',
1054
        $attributes = [],
1055
        $ul_attributes = [],
0 ignored issues
show
Unused Code introduced by
The parameter $ul_attributes is not used and could be removed. ( Ignorable by Annotation )

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

1055
        /** @scrutinizer ignore-unused */ $ul_attributes = [],

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1056
        $selected = ''
1057
    ) {
1058
        if (empty($headers) || count($headers) == 0) {
1059
            return '';
1060
        }
1061
1062
        $lis = '';
1063
        $i = 1;
1064
        foreach ($headers as $item) {
1065
            $active = '';
1066
            if ($i == 1) {
1067
                $active = ' active';
1068
            }
1069
1070
            if (!empty($selected)) {
1071
                $active = '';
1072
                if ($selected == $i) {
1073
                    $active = ' active';
1074
                }
1075
            }
1076
1077
            $item = self::tag(
1078
                'a',
1079
                $item,
1080
                [
1081
                    'href' => '#'.$id.'-'.$i,
1082
                    'class' => 'nav-item nav-link '.$active,
1083
                    'id' => $id.$i.'-tab',
1084
                    'data-toggle' => 'tab',
1085
                    'role' => 'tab',
1086
                    'aria-controls' => $id.'-'.$i,
1087
                    'aria-selected' => $selected,
1088
                ]
1089
            );
1090
            $lis .= $item;
1091
            $i++;
1092
        }
1093
1094
        $ul = self::tag(
1095
            'nav',
1096
            $lis,
1097
            [
1098
                'id' => 'ul_'.$id,
1099
                'class' => 'nav nav-tabs',
1100
                'role' => 'tablist',
1101
            ]
1102
        );
1103
1104
        $i = 1;
1105
        $divs = '';
1106
        foreach ($items as $content) {
1107
            $active = '';
1108
            if ($i == 1) {
1109
                $active = ' show active';
1110
            }
1111
1112
            if (!empty($selected)) {
1113
                $active = '';
1114
                if ($selected == $i) {
1115
                    $active = ' show active';
1116
                }
1117
            }
1118
1119
            $divs .= self::tag(
1120
                'div',
1121
                $content,
1122
                [
1123
                    'id' => $id.'-'.$i,
1124
                    'class' => 'tab-pane fade '.$active,
1125
                    'role' => 'tabpanel',
1126
                    'aria-labelledby' => $id.$i.'-tab',
1127
                ]
1128
            );
1129
            $i++;
1130
        }
1131
1132
        $attributes['id'] = $id;
1133
        $attributes['class'] = 'tab_wrapper';
1134
1135
        $html = self::tag(
1136
            'div',
1137
            $ul.
1138
            self::tag('div', $divs, ['class' => 'tab-content']),
1139
            $attributes
1140
        );
1141
1142
        return $html;
1143
    }
1144
1145
    /**
1146
     * @param $headers
1147
     * @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...
1148
     *
1149
     * @return string
1150
     */
1151
    public static function tabsOnlyLink($headers, $selected = null)
1152
    {
1153
        $id = uniqid();
1154
        $i = 1;
1155
        $lis = null;
1156
        foreach ($headers as $item) {
1157
            $class = null;
1158
            if ($i == $selected) {
1159
                $class = 'active';
1160
            }
1161
            $item = self::tag(
1162
                'a',
1163
                $item['content'],
1164
                [
1165
                    'id' => $id.'-'.$i,
1166
                    'href' => $item['url'],
1167
                    'class' => 'nav-link '.$class,
1168
                ]
1169
            );
1170
            $lis .= self::tag('li', $item, ['class' => 'nav-item']);
1171
            $i++;
1172
        }
1173
1174
        return self::tag(
1175
            'ul',
1176
            $lis,
1177
            ['class' => 'nav nav-tabs tabs-margin']
1178
        );
1179
    }
1180
1181
    /**
1182
     * In order to display a grid using jqgrid you have to:.
1183
     *
1184
     * @example
1185
     * After your Display::display_header function you have to add the nex javascript code:
1186
     * <script>
1187
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1188
     *   // for more information of this function check the grid_js() function
1189
     * </script>
1190
     * //Then you have to call the grid_html
1191
     * echo Display::grid_html('my_grid_name');
1192
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1193
     *
1194
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1195
     *
1196
     * @return string html
1197
     */
1198
    public static function grid_html($div_id)
1199
    {
1200
        $table = self::tag('table', '', ['id' => $div_id]);
1201
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1202
1203
        return $table;
1204
    }
1205
1206
    /**
1207
     * @param string $label
1208
     * @param string $form_item
1209
     *
1210
     * @return string
1211
     */
1212
    public static function form_row($label, $form_item)
1213
    {
1214
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1215
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1216
1217
        return self::div($label.$form_item, ['class' => 'form-group']);
1218
    }
1219
1220
    /**
1221
     * This is a wrapper to use the jqgrid in Chamilo.
1222
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1223
     * This function need to be in the ready jquery function
1224
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1225
     * In order to work this function needs the Display::grid_html function with the same div id.
1226
     *
1227
     * @param string $div_id       div id
1228
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1229
     * @param array  $column_names Visible columns (you should use get_lang).
1230
     *                             An array in which we place the names of the columns.
1231
     *                             This is the text that appears in the head of the grid (Header layer).
1232
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1233
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1234
     *                             This is the most important part of the grid.
1235
     *                             For a full description of all valid values see colModel API. See the url above.
1236
     * @param array  $extra_params extra parameters
1237
     * @param array  $data         data that will be loaded
1238
     * @param string $formatter    A string that will be appended to the JSON returned
1239
     * @param bool   $fixed_width  not implemented yet
1240
     *
1241
     * @return string the js code
1242
     */
1243
    public static function grid_js(
1244
        $div_id,
1245
        $url,
1246
        $column_names,
1247
        $column_model,
1248
        $extra_params,
1249
        $data = [],
1250
        $formatter = '',
1251
        $fixed_width = false
0 ignored issues
show
Unused Code introduced by
The parameter $fixed_width is not used and could be removed. ( Ignorable by Annotation )

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

1251
        /** @scrutinizer ignore-unused */ $fixed_width = false

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1252
    ) {
1253
        $obj = new stdClass();
1254
        $obj->first = 'first';
1255
1256
        if (!empty($url)) {
1257
            $obj->url = $url;
1258
        }
1259
1260
        // Needed it in order to render the links/html in the grid
1261
        foreach ($column_model as &$columnModel) {
1262
            if (!isset($columnModel['formatter'])) {
1263
                $columnModel['formatter'] = '';
1264
            }
1265
        }
1266
1267
        //This line should only be used/modified in case of having characters
1268
        // encoding problems - see #6159
1269
        //$column_names = array_map("utf8_encode", $column_names);
1270
        $obj->colNames = $column_names;
1271
        $obj->colModel = $column_model;
1272
        $obj->pager = '#'.$div_id.'_pager';
1273
        $obj->datatype = 'json';
1274
        $obj->viewrecords = 'true';
1275
        $obj->guiStyle = 'bootstrap4';
1276
        $obj->iconSet = 'fontAwesomeSolid';
1277
        $all_value = 10000000;
1278
1279
        // Sets how many records we want to view in the grid
1280
        $obj->rowNum = 20;
1281
1282
        // Default row quantity
1283
        if (!isset($extra_params['rowList'])) {
1284
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1285
            $rowList = api_get_configuration_value('table_row_list');
1286
            if (!empty($rowList) && isset($rowList['options'])) {
1287
                $rowList = $rowList['options'];
1288
                $rowList[] = $all_value;
1289
            }
1290
            $extra_params['rowList'] = $rowList;
1291
        }
1292
1293
        $defaultRow = api_get_configuration_value('table_default_row');
1294
        if (!empty($defaultRow)) {
1295
            $obj->rowNum = (int) $defaultRow;
1296
        }
1297
1298
        $json = '';
1299
        if (!empty($extra_params['datatype'])) {
1300
            $obj->datatype = $extra_params['datatype'];
1301
        }
1302
1303
        // Row even odd style.
1304
        $obj->altRows = true;
1305
        if (!empty($extra_params['altRows'])) {
1306
            $obj->altRows = $extra_params['altRows'];
1307
        }
1308
1309
        if (!empty($extra_params['sortname'])) {
1310
            $obj->sortname = $extra_params['sortname'];
1311
        }
1312
1313
        if (!empty($extra_params['sortorder'])) {
1314
            $obj->sortorder = $extra_params['sortorder'];
1315
        }
1316
1317
        if (!empty($extra_params['rowList'])) {
1318
            $obj->rowList = $extra_params['rowList'];
1319
        }
1320
1321
        if (!empty($extra_params['rowNum'])) {
1322
            $obj->rowNum = $extra_params['rowNum'];
1323
        } else {
1324
            // Try to load max rows from Session
1325
            $urlInfo = parse_url($url);
1326
            if (isset($urlInfo['query'])) {
1327
                parse_str($urlInfo['query'], $query);
1328
                if (isset($query['a'])) {
1329
                    $action = $query['a'];
1330
                    // This value is set in model.ajax.php
1331
                    $savedRows = Session::read('max_rows_'.$action);
1332
                    if (!empty($savedRows)) {
1333
                        $obj->rowNum = $savedRows;
1334
                    }
1335
                }
1336
            }
1337
        }
1338
1339
        if (!empty($extra_params['viewrecords'])) {
1340
            $obj->viewrecords = $extra_params['viewrecords'];
1341
        }
1342
1343
        $beforeSelectRow = null;
1344
        if (isset($extra_params['beforeSelectRow'])) {
1345
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1346
            unset($extra_params['beforeSelectRow']);
1347
        }
1348
1349
        $beforeProcessing = '';
1350
        if (isset($extra_params['beforeProcessing'])) {
1351
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1352
            unset($extra_params['beforeProcessing']);
1353
        }
1354
1355
        $beforeRequest = '';
1356
        if (isset($extra_params['beforeRequest'])) {
1357
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1358
            unset($extra_params['beforeRequest']);
1359
        }
1360
1361
        $gridComplete = '';
1362
        if (isset($extra_params['gridComplete'])) {
1363
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1364
            unset($extra_params['gridComplete']);
1365
        }
1366
1367
        // Adding extra params
1368
        if (!empty($extra_params)) {
1369
            foreach ($extra_params as $key => $element) {
1370
                // the groupHeaders key gets a special treatment
1371
                if ($key != 'groupHeaders') {
1372
                    $obj->$key = $element;
1373
                }
1374
            }
1375
        }
1376
1377
        // Adding static data.
1378
        if (!empty($data)) {
1379
            $data_var = $div_id.'_data';
1380
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1381
            $obj->data = $data_var;
1382
            $obj->datatype = 'local';
1383
            $json .= "\n";
1384
        }
1385
1386
        $obj->end = 'end';
1387
1388
        $json_encode = json_encode($obj);
1389
1390
        if (!empty($data)) {
1391
            //Converts the "data":"js_variable" to "data":js_variable,
1392
            // otherwise it will not work
1393
            $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...
1394
        }
1395
1396
        // Fixing true/false js values that doesn't need the ""
1397
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1398
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1399
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1400
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1401
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1402
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1403
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1404
1405
        if (api_get_configuration_value('allow_compilatio_tool') &&
1406
            (strpos($_SERVER['REQUEST_URI'], 'work/work.php') !== false ||
1407
             strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php') != false
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...
1408
            )
1409
        ) {
1410
            $json_encode = str_replace('"function () { compilatioInit() }"',
1411
                'function () { compilatioInit() }',
1412
                $json_encode
1413
            );
1414
        }
1415
        // Creating the jqgrid element.
1416
        $json .= '$("#'.$div_id.'").jqGrid({';
1417
        //$json .= $beforeSelectRow;
1418
        $json .= $gridComplete;
1419
        $json .= $beforeProcessing;
1420
        $json .= $beforeRequest;
1421
        $json .= $json_encode;
1422
        $json .= '});';
1423
1424
        // Grouping headers option
1425
        if (isset($extra_params['groupHeaders'])) {
1426
            $groups = '';
1427
            foreach ($extra_params['groupHeaders'] as $group) {
1428
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1429
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1430
            }
1431
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1432
                "useColSpanStyle" : false,
1433
                "groupHeaders"    : [
1434
                    '.$groups.'
1435
                ]
1436
            });';
1437
        }
1438
1439
        $all_text = addslashes(get_lang('All'));
1440
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1441
        $json .= "\n";
1442
        // Adding edit/delete icons.
1443
        $json .= $formatter;
1444
1445
        return $json;
1446
    }
1447
1448
    /**
1449
     * @param array $headers
1450
     * @param array $rows
1451
     * @param array $attributes
1452
     *
1453
     * @return string
1454
     */
1455
    public static function table($headers, $rows, $attributes = [])
1456
    {
1457
        if (empty($attributes)) {
1458
            $attributes['class'] = 'data_table';
1459
        }
1460
        $table = new HTML_Table($attributes);
1461
        $row = 0;
1462
        $column = 0;
1463
1464
        // Course headers
1465
        if (!empty($headers)) {
1466
            foreach ($headers as $item) {
1467
                $table->setHeaderContents($row, $column, $item);
1468
                $column++;
1469
            }
1470
            $row = 1;
1471
            $column = 0;
1472
        }
1473
1474
        if (!empty($rows)) {
1475
            foreach ($rows as $content) {
1476
                $table->setCellContents($row, $column, $content);
1477
                $row++;
1478
            }
1479
        }
1480
1481
        return $table->toHtml();
1482
    }
1483
1484
    /**
1485
     * Returns the "what's new" icon notifications.
1486
     *
1487
     * The general logic of this function is to track the last time the user
1488
     * entered the course and compare to what has changed inside this course
1489
     * since then, based on the item_property table inside this course. Note that,
1490
     * if the user never entered the course before, he will not see notification
1491
     * icons. This function takes session ID into account (if any) and only shows
1492
     * the corresponding notifications.
1493
     *
1494
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1495
     * @param bool  $loadAjax
1496
     *
1497
     * @return string The HTML link to be shown next to the course
1498
     */
1499
    public static function show_notification($courseInfo, $loadAjax = true)
0 ignored issues
show
Unused Code introduced by
The parameter $loadAjax is not used and could be removed. ( Ignorable by Annotation )

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

1499
    public static function show_notification($courseInfo, /** @scrutinizer ignore-unused */ $loadAjax = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1500
    {
1501
        if (empty($courseInfo)) {
1502
            return '';
1503
        }
1504
1505
        return '';
1506
1507
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
0 ignored issues
show
Unused Code introduced by
$t_track_e_access = Data...TIC_TRACK_E_LASTACCESS) 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...
1508
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1509
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1510
        $course_code = Database::escape_string($courseInfo['code']);
1511
1512
        $user_id = api_get_user_id();
1513
        $course_id = (int) $courseInfo['real_id'];
1514
        $sessionId = (int) $courseInfo['id_session'];
1515
        $status = (int) $courseInfo['status'];
1516
1517
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1518
1519
        if ($loadNotificationsByAjax) {
1520
            if ($loadAjax) {
1521
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1522
                Session::write($id, true);
1523
1524
                return '<span id ="'.$id.'" class="course_notification"></span>';
1525
            }
1526
        }
1527
1528
        // Get the user's last access dates to all tools of this course
1529
        $sql = "SELECT *
1530
                FROM $t_track_e_access
1531
                WHERE
1532
                    c_id = $course_id AND
1533
                    access_user_id = '$user_id' AND
1534
                    access_session_id ='".$sessionId."'
1535
                ORDER BY access_date DESC
1536
                LIMIT 1
1537
                ";
1538
        $result = Database::query($sql);
1539
1540
        // latest date by default is the creation date
1541
        $latestDate = $courseInfo['creation_date'];
1542
        if (Database::num_rows($result)) {
1543
            $row = Database::fetch_array($result, 'ASSOC');
1544
            $latestDate = $row['access_date'];
1545
        }
1546
1547
        $sessionCondition = api_get_session_condition(
1548
            $sessionId,
1549
            true,
1550
            false,
1551
            'session_id'
1552
        );
1553
1554
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1555
        // Get current tools in course
1556
        $sql = "SELECT name
1557
                FROM $course_tool_table
1558
                WHERE
1559
                    c_id = $course_id AND
1560
                    visibility = '1' AND
1561
                    name NOT IN ('".implode("','", $hideTools)." ')
1562
                ";
1563
        $result = Database::query($sql);
1564
        $tools = Database::store_result($result);
1565
1566
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1567
        $group_ids[] = 0; //add group 'everyone'
1568
        $notifications = [];
1569
        if ($tools) {
1570
            foreach ($tools as $tool) {
1571
                $toolName = $tool['name'];
1572
                $toolName = Database::escape_string($toolName);
1573
                // Fix to get student publications
1574
                $toolCondition = " tool = '$toolName' AND ";
1575
                if ($toolName == 'student_publication' || $toolName == 'work') {
1576
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1577
                }
1578
1579
                $toolName = addslashes($toolName);
1580
1581
                $sql = "SELECT * FROM $tool_edit_table
1582
                        WHERE
1583
                            c_id = $course_id AND
1584
                            $toolCondition
1585
                            lastedit_type NOT LIKE '%Deleted%' AND
1586
                            lastedit_type NOT LIKE '%deleted%' AND
1587
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1588
                            lastedit_date > '$latestDate' AND
1589
                            lastedit_user_id != $user_id $sessionCondition AND
1590
                            visibility != 2 AND
1591
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1592
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1593
                        ORDER BY lastedit_date DESC
1594
                        LIMIT 1";
1595
                $result = Database::query($sql);
1596
1597
                $latestChange = Database::fetch_array($result, 'ASSOC');
1598
1599
                if ($latestChange) {
1600
                    $latestChange['link'] = $tool['link'];
1601
                    $latestChange['image'] = $tool['image'];
1602
                    $latestChange['tool'] = $tool['name'];
1603
                    $notifications[$toolName] = $latestChange;
1604
                }
1605
            }
1606
        }
1607
1608
        // Show all tool icons where there is something new.
1609
        $return = '';
1610
        foreach ($notifications as $notification) {
1611
            $toolName = $notification['tool'];
1612
            if (!(
1613
                    $notification['visibility'] == '1' ||
1614
                    ($status == '1' && $notification['visibility'] == '0') ||
1615
                    !isset($notification['visibility'])
1616
                )
1617
            ) {
1618
                continue;
1619
            }
1620
1621
            if ($toolName == TOOL_SURVEY) {
1622
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1623
                if (!empty($survey_info)) {
1624
                    $invited_users = SurveyUtil::get_invited_users(
1625
                        $survey_info['code'],
1626
                        $course_code
1627
                    );
1628
                    if (!in_array($user_id, $invited_users['course_users'])) {
1629
                        continue;
1630
                    }
1631
                }
1632
            }
1633
1634
            if ($notification['tool'] == TOOL_LEARNPATH) {
1635
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1636
                    continue;
1637
                }
1638
            }
1639
1640
            if ($notification['tool'] == TOOL_DROPBOX) {
1641
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1642
            }
1643
1644
            if ($notification['tool'] == 'work' &&
1645
                $notification['lastedit_type'] == 'DirectoryCreated'
1646
            ) {
1647
                $notification['lastedit_type'] = 'WorkAdded';
1648
            }
1649
1650
            $lastDate = api_get_local_time($notification['lastedit_date']);
1651
            $type = $notification['lastedit_type'];
1652
            if ($type == 'CalendareventVisible') {
1653
                $type = 'Visible';
1654
            }
1655
            $label = get_lang('Since your latest visit').": ".get_lang($type)." ($lastDate)";
1656
1657
            if (strpos($notification['link'], '?') === false) {
1658
                $notification['link'] = $notification['link'].'?notification=1';
1659
            } else {
1660
                $notification['link'] = $notification['link'].'&notification=1';
1661
            }
1662
1663
            $image = substr($notification['image'], 0, -4).'.png';
1664
1665
            $return .= self::url(
1666
                self::return_icon($image, $label),
1667
                api_get_path(WEB_CODE_PATH).
1668
                $notification['link'].'&cidReq='.$course_code.
1669
                '&ref='.$notification['ref'].
1670
                '&gidReq='.$notification['to_group_id'].
1671
                '&id_session='.$sessionId
1672
            ).PHP_EOL;
1673
        }
1674
1675
        return $return;
1676
    }
1677
1678
    /**
1679
     * Get the session box details as an array.
1680
     *
1681
     * @param int $session_id
1682
     *
1683
     * @return array Empty array or session array
1684
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1685
     */
1686
    public static function getSessionTitleBox($session_id)
1687
    {
1688
        global $nosession;
1689
1690
        if (!$nosession) {
1691
            global $now, $date_start, $date_end;
1692
        }
1693
        $output = [];
1694
        if (!$nosession) {
1695
            $session_info = api_get_session_info($session_id);
1696
            $coachInfo = [];
1697
            if (!empty($session['id_coach'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $session does not exist. Did you maybe mean $session_info?
Loading history...
1698
                $coachInfo = api_get_user_info($session['id_coach']);
1699
            }
1700
1701
            $session = [];
1702
            $session['category_id'] = $session_info['session_category_id'];
1703
            $session['title'] = $session_info['name'];
1704
            $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1705
            $session['dates'] = '';
1706
            $session['coach'] = '';
1707
            if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1708
                $session['coach'] = get_lang('General coach').': '.$coachInfo['complete_name'];
1709
            }
1710
1711
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1712
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1713
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1714
            ) {
1715
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1716
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1717
                    $session['duration'] = $daysLeft >= 0
1718
                        ? sprintf(get_lang('This session has a maximum duration. Only %s days to go.'), $daysLeft)
1719
                        : get_lang('You are already registered but your allowed access time has expired.');
1720
                }
1721
                $active = true;
1722
            } else {
1723
                $dates = SessionManager::parseSessionDates($session_info, true);
1724
                $session['dates'] = $dates['access'];
1725
                if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1726
                    $session['coach'] = $coachInfo['complete_name'];
1727
                }
1728
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_end does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
1729
            }
1730
            $session['active'] = $active;
1731
            $session['session_category_id'] = $session_info['session_category_id'];
1732
            $session['visibility'] = $session_info['visibility'];
1733
            $session['num_users'] = $session_info['nbr_users'];
1734
            $session['num_courses'] = $session_info['nbr_courses'];
1735
            $session['description'] = $session_info['description'];
1736
            $session['show_description'] = $session_info['show_description'];
1737
            //$session['image'] = SessionManager::getSessionImage($session_info['id']);
1738
            $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1739
1740
            $entityManager = Database::getManager();
1741
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1742
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1743
                ExtraField::SESSION_FIELD_TYPE,
1744
                $session_id
1745
            );
1746
1747
            $session['extra_fields'] = [];
1748
            /** @var \Chamilo\CoreBundle\Entity\ExtraFieldValues $value */
1749
            foreach ($extraFieldValues as $value) {
1750
                if (empty($value)) {
1751
                    continue;
1752
                }
1753
                $session['extra_fields'][] = [
1754
                    'field' => [
1755
                        'variable' => $value->getField()->getVariable(),
1756
                        'display_text' => $value->getField()->getDisplayText(),
1757
                    ],
1758
                    'value' => $value->getValue(),
1759
                ];
1760
            }
1761
1762
            $output = $session;
1763
        }
1764
1765
        return $output;
1766
    }
1767
1768
    /**
1769
     * Return the five star HTML.
1770
     *
1771
     * @param string $id              of the rating ul element
1772
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1773
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1774
     * @param bool   $add_div_wrapper add a div wrapper
1775
     *
1776
     * @return string
1777
     */
1778
    public static function return_rating_system(
1779
        $id,
1780
        $url,
1781
        $point_info = [],
1782
        $add_div_wrapper = true
1783
    ) {
1784
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1785
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1786
1787
        if (!empty($percentage)) {
1788
            $percentage = $percentage * 125 / 100;
1789
        }
1790
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1791
        $star_label = sprintf(get_lang('%s stars out of 5'), $point_info['point_average_star']);
1792
1793
        $html = '<section class="rating-widget">';
1794
        $html .= '<div class="rating-stars"><ul id="stars">';
1795
        $html .= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1796
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1797
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1798
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1799
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1800
        ';
1801
        $html .= '</ul></div>';
1802
        $html .= '</section>';
1803
        $labels = [];
1804
1805
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1806
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1807
        $labels[] = $point_info['user_vote'] ? get_lang('Your vote').' ['.$point_info['user_vote'].']' : get_lang('Your vote').' [?] ';
1808
1809
        if (!$add_div_wrapper && api_is_anonymous()) {
1810
            $labels[] = self::tag('span', get_lang('Login to vote'), ['class' => 'error']);
1811
        }
1812
1813
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1814
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1815
1816
        if ($add_div_wrapper) {
1817
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1818
        }
1819
1820
        return $html;
1821
    }
1822
1823
    /**
1824
     * @param string $title
1825
     * @param string $second_title
1826
     * @param string $size
1827
     * @param bool   $filter
1828
     *
1829
     * @return string
1830
     */
1831
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1832
    {
1833
        if ($filter) {
1834
            $title = Security::remove_XSS($title);
1835
        }
1836
1837
        if (!empty($second_title)) {
1838
            if ($filter) {
1839
                $second_title = Security::remove_XSS($second_title);
1840
            }
1841
            $title .= "<small> $second_title</small>";
1842
        }
1843
1844
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1845
    }
1846
1847
    public static function page_header_and_translate($title, $second_title = null)
1848
    {
1849
        $title = get_lang($title);
1850
1851
        return self::page_header($title, $second_title);
1852
    }
1853
1854
    public static function page_subheader_and_translate($title, $second_title = null)
1855
    {
1856
        $title = get_lang($title);
1857
1858
        return self::page_subheader($title, $second_title);
1859
    }
1860
1861
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1862
    {
1863
        if (!empty($second_title)) {
1864
            $second_title = Security::remove_XSS($second_title);
1865
            $title .= "<small> $second_title<small>";
1866
        }
1867
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1868
1869
        return $subTitle;
1870
    }
1871
1872
    public static function page_subheader2($title, $second_title = null)
1873
    {
1874
        return self::page_header($title, $second_title, 'h4');
1875
    }
1876
1877
    public static function page_subheader3($title, $second_title = null)
1878
    {
1879
        return self::page_header($title, $second_title, 'h5');
1880
    }
1881
1882
    /**
1883
     * @param array $list
1884
     *
1885
     * @return string|null
1886
     */
1887
    public static function description($list)
1888
    {
1889
        $html = null;
1890
        if (!empty($list)) {
1891
            $html = '<dl class="dl-horizontal">';
1892
            foreach ($list as $item) {
1893
                $html .= '<dt>'.$item['title'].'</dt>';
1894
                $html .= '<dd>'.$item['content'].'</dd>';
1895
            }
1896
            $html .= '</dl>';
1897
        }
1898
1899
        return $html;
1900
    }
1901
1902
    /**
1903
     * @param int    $percentage      int value between 0 and 100
1904
     * @param bool   $show_percentage
1905
     * @param string $extra_info
1906
     * @param string $class           danger/success/infowarning
1907
     *
1908
     * @return string
1909
     */
1910
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1911
    {
1912
        $percentage = (int) $percentage;
1913
        $class = empty($class) ? '' : "progress-bar-$class";
1914
1915
        $div = '<div class="progress">
1916
                <div
1917
                    class="progress-bar progress-bar-striped '.$class.'"
1918
                    role="progressbar"
1919
                    aria-valuenow="'.$percentage.'"
1920
                    aria-valuemin="0"
1921
                    aria-valuemax="100"
1922
                    style="width: '.$percentage.'%;"
1923
                >';
1924
        if ($show_percentage) {
1925
            $div .= $percentage.'%';
1926
        } else {
1927
            if (!empty($extra_info)) {
1928
                $div .= $extra_info;
1929
            }
1930
        }
1931
        $div .= '</div></div>';
1932
1933
        return $div;
1934
    }
1935
1936
    /**
1937
     * @param string $count
1938
     * @param string $type
1939
     *
1940
     * @return string|null
1941
     */
1942
    public static function badge($count, $type = "warning")
1943
    {
1944
        $class = '';
1945
1946
        switch ($type) {
1947
            case 'success':
1948
                $class = 'badge-success';
1949
                break;
1950
            case 'warning':
1951
                $class = 'badge-warning';
1952
                break;
1953
            case 'important':
1954
                $class = 'badge-important';
1955
                break;
1956
            case 'info':
1957
                $class = 'badge-info';
1958
                break;
1959
            case 'inverse':
1960
                $class = 'badge-inverse';
1961
                break;
1962
        }
1963
1964
        if (!empty($count)) {
1965
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1966
        }
1967
1968
        return null;
1969
    }
1970
1971
    /**
1972
     * @param array $badge_list
1973
     *
1974
     * @return string
1975
     */
1976
    public static function badge_group($badge_list)
1977
    {
1978
        $html = '<div class="badge-group">';
1979
        foreach ($badge_list as $badge) {
1980
            $html .= $badge;
1981
        }
1982
        $html .= '</div>';
1983
1984
        return $html;
1985
    }
1986
1987
    /**
1988
     * @param string $content
1989
     * @param string $type
1990
     *
1991
     * @return string
1992
     */
1993
    public static function label($content, $type = 'default')
1994
    {
1995
        switch ($type) {
1996
            case 'success':
1997
                $class = 'success';
1998
                break;
1999
            case 'warning':
2000
                $class = 'warning';
2001
                break;
2002
            case 'important':
2003
            case 'danger':
2004
                $class = 'danger';
2005
                break;
2006
            case 'info':
2007
                $class = 'info';
2008
                break;
2009
            case 'primary':
2010
                $class = 'primary';
2011
                break;
2012
            default:
2013
                $class = 'secondary';
2014
                break;
2015
        }
2016
2017
        $html = '';
2018
        if (!empty($content)) {
2019
            $html = '<span class="badge badge-'.$class.'">';
2020
            $html .= $content;
2021
            $html .= '</span>';
2022
        }
2023
2024
        return $html;
2025
    }
2026
2027
    /**
2028
     * @param array  $items
2029
     * @param string $class
2030
     *
2031
     * @return string|null
2032
     */
2033
    public static function actions($items, $class = 'new_actions')
2034
    {
2035
        $html = null;
2036
        if (!empty($items)) {
2037
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2038
            foreach ($items as $value) {
2039
                $class = null;
2040
                if (isset($value['active']) && $value['active']) {
2041
                    $class = 'class ="active"';
2042
                }
2043
2044
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2045
                    $class = 'class ="active"';
2046
                }
2047
                $html .= "<li $class >";
2048
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2049
                $html .= self::url($value['content'], $value['url'], $attributes);
2050
                $html .= '</li>';
2051
            }
2052
            $html .= '</ul></div>';
2053
            $html .= '<br />';
2054
        }
2055
2056
        return $html;
2057
    }
2058
2059
    /**
2060
     * Prints a tooltip.
2061
     *
2062
     * @param string $text
2063
     * @param string $tip
2064
     *
2065
     * @return string
2066
     */
2067
    public static function tip($text, $tip)
2068
    {
2069
        if (empty($tip)) {
2070
            return $text;
2071
        }
2072
2073
        return self::span(
2074
            $text,
2075
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2076
        );
2077
    }
2078
2079
    /**
2080
     * @param array  $items
2081
     * @param string $type
2082
     * @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...
2083
     *
2084
     * @return string|null
2085
     */
2086
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2087
    {
2088
        $html = null;
2089
        if (!empty($items)) {
2090
            if (empty($id)) {
2091
                $id = api_get_unique_id();
2092
            }
2093
            if ($type == 'jquery') {
2094
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2095
            } else {
2096
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2097
            }
2098
2099
            $count = 1;
2100
            foreach ($items as $item) {
2101
                $html .= '<div class="accordion-my-group">';
2102
                $html .= '<div class="accordion-heading">
2103
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2104
                            '.$item['title'].'
2105
                            </a>
2106
                          </div>';
2107
2108
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2109
                $html .= '<div class="accordion-my-inner">
2110
                            '.$item['content'].'
2111
                            </div>
2112
                          </div>';
2113
            }
2114
            $html .= '</div>';
2115
        }
2116
2117
        return $html;
2118
    }
2119
2120
    /**
2121
     * @param array $buttons
2122
     *
2123
     * @return string
2124
     */
2125
    public static function groupButton($buttons)
2126
    {
2127
        $html = '<div class="btn-group" role="group">';
2128
        foreach ($buttons as $button) {
2129
            $html .= $button;
2130
        }
2131
        $html .= '</div>';
2132
2133
        return $html;
2134
    }
2135
2136
    /**
2137
     * @todo use twig
2138
     *
2139
     * @param string $title
2140
     * @param array  $elements
2141
     * @param bool   $alignToRight
2142
     *
2143
     * @return string
2144
     */
2145
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2146
    {
2147
        $id = uniqid('dropdown', true);
2148
        $html = '<div class="btn-group" role="group">
2149
                <button id = "'.$id.'" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
2150
                '.$title.'
2151
                </button>
2152
                <div class="dropdown-menu aria-labelledby="'.$id.'" '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2153
        foreach ($elements as $item) {
2154
            $html .= self::tag('li', self::url($item['title'], $item['href'], ['class' => 'dropdown-item']));
2155
        }
2156
        $html .= '</div>
2157
            </div>';
2158
2159
        return $html;
2160
    }
2161
2162
    /**
2163
     * @param string $file
2164
     * @param array  $params
2165
     *
2166
     * @return string|null
2167
     */
2168
    public static function getMediaPlayer($file, $params = [])
2169
    {
2170
        $fileInfo = pathinfo($file);
2171
2172
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2173
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2174
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2175
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2176
2177
        switch ($fileInfo['extension']) {
2178
            case 'mp3':
2179
            case 'webm':
2180
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2181
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2182
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2183
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2184
                          </object>';
2185
                $html .= '</audio>';
2186
2187
                return $html;
2188
                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...
2189
            case 'wav':
2190
            case 'ogg':
2191
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2192
2193
                return $html;
2194
                break;
2195
        }
2196
2197
        return null;
2198
    }
2199
2200
    /**
2201
     * @param int    $nextValue
2202
     * @param array  $list
2203
     * @param int    $current
2204
     * @param int    $fixedValue
2205
     * @param array  $conditions
2206
     * @param string $link
2207
     * @param bool   $isMedia
2208
     * @param bool   $addHeaders
2209
     * @param array  $linkAttributes
2210
     *
2211
     * @return string
2212
     */
2213
    public static function progressPaginationBar(
2214
        $nextValue,
2215
        $list,
2216
        $current,
2217
        $fixedValue = null,
2218
        $conditions = [],
2219
        $link = null,
2220
        $isMedia = false,
2221
        $addHeaders = true,
2222
        $linkAttributes = []
2223
    ) {
2224
        if ($addHeaders) {
2225
            $pagination_size = 'pagination-mini';
2226
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2227
        } else {
2228
            $html = null;
2229
        }
2230
        $affectAllItems = false;
2231
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2232
            $affectAllItems = true;
2233
        }
2234
        $localCounter = 0;
2235
        foreach ($list as $itemId) {
2236
            $isCurrent = false;
2237
            if ($affectAllItems) {
2238
                $isCurrent = true;
2239
            } else {
2240
                if (!$isMedia) {
2241
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2242
                }
2243
            }
2244
            $html .= self::parsePaginationItem(
2245
                $itemId,
2246
                $isCurrent,
2247
                $conditions,
2248
                $link,
2249
                $nextValue,
2250
                $isMedia,
2251
                $localCounter,
2252
                $fixedValue,
2253
                $linkAttributes
2254
            );
2255
            $localCounter++;
2256
        }
2257
        if ($addHeaders) {
2258
            $html .= '</ul></div>';
2259
        }
2260
2261
        return $html;
2262
    }
2263
2264
    /**
2265
     * @param int    $itemId
2266
     * @param bool   $isCurrent
2267
     * @param array  $conditions
2268
     * @param string $link
2269
     * @param int    $nextValue
2270
     * @param bool   $isMedia
2271
     * @param int    $localCounter
2272
     * @param int    $fixedValue
2273
     * @param array  $linkAttributes
2274
     *
2275
     * @return string
2276
     */
2277
    public static function parsePaginationItem(
2278
        $itemId,
2279
        $isCurrent,
2280
        $conditions,
2281
        $link,
2282
        $nextValue = 0,
2283
        $isMedia = false,
2284
        $localCounter = null,
2285
        $fixedValue = null,
2286
        $linkAttributes = []
2287
    ) {
2288
        $defaultClass = 'before';
2289
        $class = $defaultClass;
2290
        foreach ($conditions as $condition) {
2291
            $array = isset($condition['items']) ? $condition['items'] : [];
2292
            $class_to_applied = $condition['class'];
2293
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2294
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2295
            switch ($type) {
2296
                case 'positive':
2297
                    if (in_array($itemId, $array)) {
2298
                        if ($mode == 'overwrite') {
2299
                            $class = " $defaultClass $class_to_applied";
2300
                        } else {
2301
                            $class .= " $class_to_applied";
2302
                        }
2303
                    }
2304
                    break;
2305
                case 'negative':
2306
                    if (!in_array($itemId, $array)) {
2307
                        if ($mode == 'overwrite') {
2308
                            $class = " $defaultClass $class_to_applied";
2309
                        } else {
2310
                            $class .= " $class_to_applied";
2311
                        }
2312
                    }
2313
                    break;
2314
            }
2315
        }
2316
        if ($isCurrent) {
2317
            $class = 'before current';
2318
        }
2319
        if ($isMedia && $isCurrent) {
2320
            $class = 'before current';
2321
        }
2322
        if (empty($link)) {
2323
            $link_to_show = '#';
2324
        } else {
2325
            $link_to_show = $link.($nextValue + $localCounter);
2326
        }
2327
        $label = $nextValue + $localCounter + 1;
2328
        if ($isMedia) {
2329
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2330
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2331
        }
2332
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2333
2334
        return  '<li class = "'.$class.'">'.$link.'</li>';
2335
    }
2336
2337
    /**
2338
     * @param int $current
2339
     * @param int $total
2340
     *
2341
     * @return string
2342
     */
2343
    public static function paginationIndicator($current, $total)
2344
    {
2345
        $html = null;
2346
        if (!empty($current) && !empty($total)) {
2347
            $label = sprintf(get_lang('%s of %s'), $current, $total);
2348
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2349
        }
2350
2351
        return $html;
2352
    }
2353
2354
    /**
2355
     * @param $url
2356
     * @param $currentPage
2357
     * @param $pagesCount
2358
     * @param $totalItems
2359
     *
2360
     * @return string
2361
     */
2362
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2363
    {
2364
        $pagination = '';
2365
        if ($totalItems > 1 && $pagesCount > 1) {
2366
            $pagination .= '<ul class="pagination">';
2367
            for ($i = 0; $i < $pagesCount; $i++) {
2368
                $newPage = $i + 1;
2369
                if ($currentPage == $newPage) {
2370
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2371
                } else {
2372
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2373
                }
2374
            }
2375
            $pagination .= '</ul>';
2376
        }
2377
2378
        return $pagination;
2379
    }
2380
2381
    /**
2382
     * Adds a message in the queue.
2383
     *
2384
     * @param string $message
2385
     */
2386
    public static function addFlash($message)
2387
    {
2388
        $messages = Session::read('flash_messages');
2389
        if (empty($messages)) {
2390
            $messages[] = $message;
2391
        } else {
2392
            array_push($messages, $message);
2393
        }
2394
        Session::write('flash_messages', $messages);
2395
    }
2396
2397
    /**
2398
     * @return string
2399
     */
2400
    public static function getFlashToString()
2401
    {
2402
        $messages = Session::read('flash_messages');
2403
        $messageToString = '';
2404
        if (!empty($messages)) {
2405
            foreach ($messages as $message) {
2406
                $messageToString .= $message;
2407
            }
2408
        }
2409
2410
        return $messageToString;
2411
    }
2412
2413
    /**
2414
     * Shows the message from the session.
2415
     */
2416
    public static function showFlash()
2417
    {
2418
        echo self::getFlashToString();
2419
    }
2420
2421
    /**
2422
     * Destroys the message session.
2423
     */
2424
    public static function cleanFlashMessages()
2425
    {
2426
        Session::erase('flash_messages');
2427
    }
2428
2429
    /**
2430
     * Get the profile edition link for a user.
2431
     *
2432
     * @param int  $userId  The user id
2433
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2434
     *
2435
     * @return string The link
2436
     */
2437
    public static function getProfileEditionLink($userId, $asAdmin = false)
2438
    {
2439
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2440
        if ($asAdmin) {
2441
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2442
        }
2443
2444
        return $editProfileUrl;
2445
    }
2446
2447
    /**
2448
     * Get the vCard for a user.
2449
     *
2450
     * @param int $userId The user id
2451
     *
2452
     * @return string *.*vcf file
2453
     */
2454
    public static function getVCardUserLink($userId)
2455
    {
2456
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2457
2458
        return $vCardUrl;
2459
    }
2460
2461
    /**
2462
     * @param string $content
2463
     * @param string $title
2464
     * @param string $footer
2465
     * @param string $type        primary|success|info|warning|danger
2466
     * @param string $extra
2467
     * @param string $id
2468
     * @param string $customColor
2469
     * @param string $rightAction
2470
     *
2471
     * @return string
2472
     */
2473
    public static function panel(
2474
        $content,
2475
        $title = '',
2476
        $footer = '',
2477
        $type = 'default',
2478
        $extra = '',
2479
        $id = '',
2480
        $customColor = '',
2481
        $rightAction = ''
2482
    ) {
2483
        $headerStyle = '';
2484
        if (!empty($customColor)) {
2485
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2486
        }
2487
2488
        if (!empty($rightAction)) {
2489
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2490
        }
2491
2492
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2493
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2494
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2495
        $style = !in_array($type, $typeList) ? 'default' : $type;
2496
2497
        if (!empty($id)) {
2498
            $id = " id='$id'";
2499
        }
2500
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2501
2502
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2503
2504
        return '
2505
            <div '.$id.' class="card">
2506
                '.$panel.'
2507
            </div>'
2508
        ;
2509
    }
2510
2511
    /**
2512
     * @param string $content
2513
     */
2514
    public static function contentPanel($content): string
2515
    {
2516
        if (empty($content)) {
2517
            return '';
2518
        }
2519
2520
        return '<div class="card-text">'.$content.'</div>';
2521
    }
2522
2523
    /**
2524
     * Get the button HTML with an Awesome Font icon.
2525
     *
2526
     * @param string $text        The button content
2527
     * @param string $url         The url to button
2528
     * @param string $icon        The Awesome Font class for icon
2529
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2530
     * @param array  $attributes  The additional attributes
2531
     * @param bool   $includeText
2532
     *
2533
     * @return string The button HTML
2534
     */
2535
    public static function toolbarButton(
2536
        $text,
2537
        $url,
2538
        $icon = 'check',
2539
        $type = null,
2540
        array $attributes = [],
2541
        $includeText = true
2542
    ) {
2543
        $buttonClass = "btn btn-outline-secondary";
2544
        if (!empty($type)) {
2545
            $buttonClass = "btn btn-$type";
2546
        }
2547
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2548
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2549
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2550
2551
        if (!$includeText) {
2552
            $text = '<span class="sr-only">'.$text.'</span>';
2553
        }
2554
2555
        return self::url("$icon $text", $url, $attributes);
2556
    }
2557
2558
    /**
2559
     * @param string $id
2560
     * @param array  $content
2561
     * @param array  $colsWidth Optional. Columns width
2562
     *
2563
     * @return string
2564
     */
2565
    public static function toolbarAction($id, $content, $colsWidth = [])
2566
    {
2567
        $col = count($content);
2568
2569
        if (!$colsWidth) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $colsWidth 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...
2570
            $width = 12 / $col;
2571
            array_walk($content, function () use ($width, &$colsWidth) {
2572
                $colsWidth[] = $width;
2573
            });
2574
        }
2575
2576
        $html = '<div id="'.$id.'" class="actions">';
2577
        $html .= '<div class="row">';
2578
2579
        for ($i = 0; $i < $col; $i++) {
2580
            $class = 'col-sm-'.$colsWidth[$i];
2581
2582
            if ($col > 1) {
2583
                if ($i > 0 && $i < count($content) - 1) {
2584
                    $class .= ' text-center';
2585
                } elseif ($i === count($content) - 1) {
2586
                    $class .= ' text-right';
2587
                }
2588
            }
2589
2590
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2591
        }
2592
2593
        $html .= '</div>';
2594
        $html .= '</div>';
2595
2596
        return $html;
2597
    }
2598
2599
    /**
2600
     * Get a HTML code for a icon by Font Awesome.
2601
     *
2602
     * @param string     $name            The icon name. Example: "mail-reply"
2603
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2604
     * @param bool       $fixWidth        Optional. Whether add the fw class
2605
     * @param string     $additionalClass Optional. Additional class
2606
     *
2607
     * @return string
2608
     */
2609
    public static function returnFontAwesomeIcon(
2610
        $name,
2611
        $size = '',
2612
        $fixWidth = false,
2613
        $additionalClass = ''
2614
    ) {
2615
        $className = "fa fa-$name";
2616
2617
        if ($fixWidth) {
2618
            $className .= ' fa-fw';
2619
        }
2620
2621
        switch ($size) {
2622
            case 'xs':
2623
            case 'sm':
2624
            case 'lg':
2625
                $className .= " fa-{$size}";
2626
                break;
2627
            case 2:
2628
            case 3:
2629
            case 4:
2630
            case 5:
2631
                $className .= " fa-{$size}x";
2632
                break;
2633
        }
2634
2635
        if (!empty($additionalClass)) {
2636
            $className .= " $additionalClass";
2637
        }
2638
2639
        $icon = self::tag('em', null, ['class' => $className]);
2640
2641
        return "$icon ";
2642
    }
2643
2644
    /**
2645
     * @param string     $title
2646
     * @param string     $content
2647
     * @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...
2648
     * @param array      $params
2649
     * @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...
2650
     * @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...
2651
     * @param bool|true  $open
2652
     * @param bool|false $fullClickable
2653
     *
2654
     * @return string|null
2655
     *
2656
     * @todo rework function to easy use
2657
     */
2658
    public static function panelCollapse(
2659
        $title,
2660
        $content,
2661
        $id = null,
2662
        $params = [],
2663
        $idAccordion = null,
2664
        $idCollapse = null,
0 ignored issues
show
Unused Code introduced by
The parameter $idCollapse is not used and could be removed. ( Ignorable by Annotation )

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

2664
        /** @scrutinizer ignore-unused */ $idCollapse = null,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2665
        $open = true,
2666
        $fullClickable = false
2667
    ) {
2668
        if (!empty($idAccordion)) {
2669
            $headerClass = '';
2670
            $headerClass .= $fullClickable ? 'center-block ' : '';
2671
            $headerClass .= $open ? '' : 'collapsed';
2672
            $contentClass = 'panel-collapse collapse ';
2673
            $contentClass .= $open ? 'in' : '';
2674
            $ariaExpanded = $open ? 'true' : 'false';
2675
2676
            $html = <<<HTML
2677
2678
                <div class="card" id="$id">
2679
                    <div class="card-header">
2680
                        $title
2681
                    </div>
2682
                    <div class="card-body">$content</div>
2683
                </div>
2684
HTML;
2685
        } else {
2686
            if (!empty($id)) {
2687
                $params['id'] = $id;
2688
            }
2689
            $params['class'] = 'card';
2690
            $html = null;
2691
            if (!empty($title)) {
2692
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2693
            }
2694
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2695
            $html = self::div($html, $params);
2696
        }
2697
2698
        return $html;
2699
    }
2700
2701
    /**
2702
     * Returns the string "1 day ago" with a link showing the exact date time.
2703
     *
2704
     * @param string $dateTime in UTC or a DateTime in UTC
2705
     *
2706
     * @return string
2707
     */
2708
    public static function dateToStringAgoAndLongDate($dateTime)
2709
    {
2710
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2711
            return '';
2712
        }
2713
2714
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2715
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2716
        }
2717
2718
        return self::tip(
2719
            date_to_str_ago($dateTime),
2720
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2721
            //api_get_local_time($dateTime)
2722
        );
2723
    }
2724
2725
    /**
2726
     * @param array  $userInfo
2727
     * @param string $status
2728
     * @param string $toolbar
2729
     *
2730
     * @return string
2731
     */
2732
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2733
    {
2734
        if (empty($userInfo)) {
2735
            return '';
2736
        }
2737
2738
        if (!empty($status)) {
2739
            $status = '<div class="items-user-status">'.$status.'</div>';
2740
        }
2741
2742
        if (!empty($toolbar)) {
2743
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2744
        }
2745
2746
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">
2747
                    <img src="'.$userInfo['avatar'].'" class="rounded">
2748
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>
2749
                    <div class="card-body">
2750
                       <div class="card-title">
2751
                       '.$status.'
2752
                       '.$toolbar.'
2753
                       </div>
2754
                    </div>
2755
                    <hr />
2756
              </div>';
2757
    }
2758
2759
    /**
2760
     * @param string $fileName
2761
     * @param string $fileUrl
2762
     *
2763
     * @return string
2764
     */
2765
    public static function fileHtmlGuesser($fileName, $fileUrl)
2766
    {
2767
        $data = pathinfo($fileName);
2768
2769
        //$content = self::url($data['basename'], $fileUrl);
2770
        $content = '';
2771
        switch ($data['extension']) {
2772
            case 'webm':
2773
            case 'mp4':
2774
            case 'ogg':
2775
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2776
                // Allows video to play when loading during an ajax call
2777
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2778
                break;
2779
            case 'jpg':
2780
            case 'jpeg':
2781
            case 'gif':
2782
            case 'png':
2783
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2784
                break;
2785
            default:
2786
                //$html = self::url($data['basename'], $fileUrl);
2787
                break;
2788
        }
2789
        //$html = self::url($content, $fileUrl, ['ajax']);
2790
2791
        return $content;
2792
    }
2793
2794
    /**
2795
     * @param string $frameName
2796
     *
2797
     * @return string
2798
     */
2799
    public static function getFrameReadyBlock($frameName)
2800
    {
2801
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2802
2803
        $videoFeatures = [
2804
            'playpause',
2805
            'current',
2806
            'progress',
2807
            'duration',
2808
            'tracks',
2809
            'volume',
2810
            'fullscreen',
2811
            'vrview',
2812
            'markersrolls',
2813
        ];
2814
        $features = api_get_configuration_value('video_features');
2815
        $videoPluginsJS = [];
2816
        $videoPluginCSS = [];
2817
        if (!empty($features) && isset($features['features'])) {
2818
            foreach ($features['features'] as $feature) {
2819
                if ($feature === 'vrview') {
2820
                    continue;
2821
                }
2822
                $defaultFeatures[] = $feature;
2823
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.js";
2824
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.css";
2825
            }
2826
        }
2827
2828
        $videoPluginFiles = '';
2829
        foreach ($videoPluginsJS as $file) {
2830
            $videoPluginFiles .= '{type: "script", src: "'.$webPublicPath.'assets/'.$file.'"},';
2831
        }
2832
2833
        $videoPluginCssFiles = '';
2834
        foreach ($videoPluginCSS as $file) {
2835
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webPublicPath.'assets/'.$file.'"},';
2836
        }
2837
2838
        $translateHtml = '';
2839
        $translate = api_get_configuration_value('translate_html');
2840
        if ($translate) {
2841
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2842
        }
2843
2844
        $videoFeatures = implode("','", $videoFeatures);
2845
        $frameReady = '
2846
        $.frameReady(function() {
2847
             $(function () {
2848
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2849
                    pluginPath: "'.$webPublicPath.'assets/mediaelement/plugins/",
2850
                    features: [\''.$videoFeatures.'\'],
2851
                    success: function(mediaElement, originalNode, instance) {
2852
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2853
                    },
2854
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2855
                });
2856
            });
2857
        },
2858
        "'.$frameName.'",
2859
        [
2860
            {type:"script", src:"'.api_get_jquery_web_path().'", deps: [
2861
            {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2862
            {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2863
            {type:"script", src:"'.api_get_jquery_ui_js_web_path().'"},
2864
            {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/mediaelement-and-player.min.js",
2865
                deps: [
2866
                {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/vrview/vrview.js"},
2867
                {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/markersrolls/markersrolls.js"},
2868
                '.$videoPluginFiles.'
2869
            ]},
2870
            '.$translateHtml.'
2871
            ]},
2872
            '.$videoPluginCssFiles.'
2873
            {type:"script", src:"'.$webPublicPath.'build/libs/mathjax/MathJax.js?config=AM_HTMLorMML"},
2874
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
2875
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/theme.css"},
2876
        ]);';
2877
2878
        return $frameReady;
2879
    }
2880
2881
    /**
2882
     * @param string $image
2883
     * @param int    $size
2884
     *
2885
     * @return string
2886
     */
2887
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2888
    {
2889
        return self::return_icon($image, '', [], $size, false, true);
2890
    }
2891
2892
    /**
2893
     * @param string $image
2894
     * @param int    $size
2895
     * @param string $name
2896
     *
2897
     * @return string
2898
     */
2899
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
2900
    {
2901
        return self::return_icon($image, $name, [], $size);
2902
    }
2903
2904
    public static function dropdownMenu($items = [], array $attr = [])
2905
    {
2906
        $links = null;
2907
        $url = null;
2908
        foreach ($items as $row) {
2909
            $url = self::url($row['icon'].$row['item'], $row['url'], ['class' => 'dropdown-item']);
2910
            $links .= self::tag('li', $url);
2911
        }
2912
        $html = self::tag('ul', $links, $attr);
2913
2914
        return  $html;
2915
    }
2916
2917
    /**
2918
     * @param $id
2919
     *
2920
     * @return array|mixed
2921
     */
2922
    public static function randomColor($id)
2923
    {
2924
        static $colors = [];
2925
2926
        if (!empty($colors[$id])) {
2927
            return $colors[$id];
2928
        } else {
2929
            $color = substr(md5(time() * $id), 0, 6);
2930
            $c1 = hexdec(substr($color, 0, 2));
2931
            $c2 = hexdec(substr($color, 2, 2));
2932
            $c3 = hexdec(substr($color, 4, 2));
2933
            $luminosity = $c1 + $c2 + $c3;
2934
2935
            $type = '#000000';
2936
            if ($luminosity < (255 + 255 + 255) / 2) {
2937
                $type = '#FFFFFF';
2938
            }
2939
2940
            $result = [
2941
                'color' => '#'.$color,
2942
                'luminosity' => $type,
2943
            ];
2944
            $colors[$id] = $result;
2945
2946
            return $result; // example: #fc443a
2947
        }
2948
    }
2949
}
2950