Passed
Push — master ( bf3a28...ead698 )
by Julito
18:32 queued 09:28
created

Display::tabs()   C

Complexity

Conditions 11
Paths 50

Size

Total Lines 90
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 55
nc 50
nop 6
dl 0
loc 90
rs 6.8351
c 0
b 0
f 0

How to fix   Long Method    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\Entity\ExtraFieldValues;
8
use Chamilo\CoreBundle\Framework\Container;
9
use ChamiloSession as Session;
10
use Symfony\Component\HttpFoundation\Response;
11
12
/**
13
 * Class Display
14
 * Contains several public functions dealing with the display of
15
 * table data, messages, help topics, ...
16
 *
17
 * Include/require it in your code to use its public functionality.
18
 * There are also several display public functions in the main api library.
19
 *
20
 * All public functions static public functions inside a class called Display,
21
 * so you use them like this: e.g.
22
 * Display::return_message($message)
23
 */
24
class Display
25
{
26
    /** @var Template */
27
    public static $global_template;
28
    public static $preview_style = null;
29
    public static $legacyTemplate;
30
31
    /**
32
     * Constructor.
33
     */
34
    public function __construct()
35
    {
36
    }
37
38
    /**
39
     * @return array
40
     */
41
    public static function toolList()
42
    {
43
        return [
44
            'group',
45
            'work',
46
            'glossary',
47
            'forum',
48
            'course_description',
49
            'gradebook',
50
            'attendance',
51
            'course_progress',
52
            'notebook',
53
        ];
54
    }
55
56
    /**
57
     * Displays the page header.
58
     *
59
     * @param string The name of the page (will be showed in the page title)
60
     * @param string Optional help file name
61
     * @param string $page_header
62
     */
63
    public static function display_header(
64
        $tool_name = '',
65
        $help = null,
66
        $page_header = null
67
    ) {
68
        global $interbreadcrumb;
69
        $interbreadcrumb[] = ['url' => '#', 'name' => $tool_name];
70
71
        ob_start();
72
73
        return true;
74
    }
75
76
    /**
77
     * Displays the reduced page header (without banner).
78
     */
79
    public static function display_reduced_header()
80
    {
81
        ob_start();
82
        self::$legacyTemplate = '@ChamiloCore/Layout/no_layout.html.twig';
83
84
        return true;
85
86
        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...
87
        self::$global_template = new Template(
88
            $tool_name,
89
            false,
90
            false,
91
            $show_learnpath
92
        );
93
    }
94
95
    /**
96
     * Display no header.
97
     */
98
    public static function display_no_header()
99
    {
100
        global $tool_name, $show_learnpath;
101
        self::$global_template = new Template(
102
            $tool_name,
103
            false,
104
            false,
105
            $show_learnpath
106
        );
107
    }
108
109
    /**
110
     * Display the page footer.
111
     */
112
    public static function display_footer()
113
    {
114
        $contents = ob_get_contents();
115
        if (ob_get_length()) {
116
            ob_end_clean();
117
        }
118
        $tpl = '@ChamiloCore/Layout/layout_one_col.html.twig';
119
        if (!empty(self::$legacyTemplate)) {
120
            $tpl = self::$legacyTemplate;
121
        }
122
        $response = new Response();
123
        $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...
124
        global $interbreadcrumb, $htmlHeadXtra;
125
126
        $courseInfo = api_get_course_info();
127
        if (!empty($courseInfo)) {
128
            $url = $courseInfo['course_public_url'];
129
            $sessionId = api_get_session_id();
130
            if (!empty($sessionId)) {
131
                $url .= '?sid='.$sessionId;
132
            }
133
134
            array_unshift(
135
                $interbreadcrumb,
136
                ['name' => $courseInfo['title'], 'url' => $url]
137
            );
138
        }
139
140
        $params['legacy_javascript'] = $htmlHeadXtra;
141
        $params['legacy_breadcrumb'] = $interbreadcrumb;
142
143
        Template::setVueParams($params);
144
        $content = Container::getTwig()->render($tpl, $params);
145
        $response->setContent($content);
146
        $response->send();
147
        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...
148
    }
149
150
    /**
151
     * Display the page footer.
152
     */
153
    public static function display_reduced_footer()
154
    {
155
        $contents = ob_get_contents();
156
        if (ob_get_length()) {
157
            ob_end_clean();
158
        }
159
        $tpl = '@ChamiloCore/Layout/no_layout.html.twig';
160
        if (!empty(self::$legacyTemplate)) {
161
            $tpl = self::$legacyTemplate;
162
        }
163
        $response = new Response();
164
        $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...
165
        global $interbreadcrumb, $htmlHeadXtra;
166
        $params['legacy_javascript'] = $htmlHeadXtra;
167
        $params['legacy_breadcrumb'] = $interbreadcrumb;
168
169
        $content = Container::getTwig()->render($tpl, $params);
170
        $response->setContent($content);
171
        $response->send();
172
        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...
173
    }
174
175
    /**
176
     * Displays the tool introduction of a tool.
177
     *
178
     * @author Patrick Cool <[email protected]>, Ghent University
179
     *
180
     * @param string $tool          these are the constants that are used for indicating the tools
181
     * @param array  $editor_config Optional configuration settings for the online editor.
182
     *                              return: $tool return a string array list with the "define" in main_api.lib
183
     *
184
     * @return string html code for adding an introduction
185
     */
186
    public static function display_introduction_section(
187
        $tool,
188
        $editor_config = null
189
    ) {
190
        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...
191
    }
192
193
    /**
194
     * @param string $tool
195
     * @param array  $editor_config
196
     */
197
    public static function return_introduction_section(
198
        $tool,
199
        $editor_config = null
200
    ) {
201
        $moduleId = $tool;
202
        if ('true' === api_get_setting('enable_tool_introduction') || TOOL_COURSE_HOMEPAGE == $tool) {
203
            $introduction_section = null;
204
            require api_get_path(SYS_CODE_PATH).'inc/introductionSection.inc.php';
205
206
            return $introduction_section;
207
        }
208
    }
209
210
    /**
211
     * Displays a table.
212
     *
213
     * @param array  $header          Titles for the table header
214
     *                                each item in this array can contain 3 values
215
     *                                - 1st element: the column title
216
     *                                - 2nd element: true or false (column sortable?)
217
     *                                - 3th element: additional attributes for
218
     *                                th-tag (eg for column-width)
219
     *                                - 4the element: additional attributes for the td-tags
220
     * @param array  $content         2D-array with the tables content
221
     * @param array  $sorting_options Keys are:
222
     *                                'column' = The column to use as sort-key
223
     *                                'direction' = SORT_ASC or SORT_DESC
224
     * @param array  $paging_options  Keys are:
225
     *                                'per_page_default' = items per page when switching from
226
     *                                full-    list to per-page-view
227
     *                                'per_page' = number of items to show per page
228
     *                                'page_nr' = The page to display
229
     * @param array  $query_vars      Additional variables to add in the query-string
230
     * @param array  $form_actions
231
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
232
     * @param string $tableName
233
     * @param string $tableId
234
     *
235
     * @author [email protected]
236
     */
237
    public static function display_sortable_table(
238
        $header,
239
        $content,
240
        $sorting_options = [],
241
        $paging_options = [],
242
        $query_vars = null,
243
        $form_actions = [],
244
        $style = 'table',
245
        $tableName = 'tablename',
246
        $tableId = ''
247
    ) {
248
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
249
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
250
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
251
        if (is_array($query_vars)) {
252
            $table->set_additional_parameters($query_vars);
253
        }
254
        if ('table' == $style) {
255
            if (is_array($header) && count($header) > 0) {
256
                foreach ($header as $index => $header_item) {
257
                    $table->set_header(
258
                        $index,
259
                        isset($header_item[0]) ? $header_item[0] : null,
260
                        isset($header_item[1]) ? $header_item[1] : null,
261
                        isset($header_item[2]) ? $header_item[2] : null,
262
                        isset($header_item[3]) ? $header_item[3] : null
263
                    );
264
                }
265
            }
266
            $table->set_form_actions($form_actions);
267
            $table->display();
268
        } else {
269
            $table->display_grid();
270
        }
271
    }
272
273
    /**
274
     * Returns an HTML table with sortable column (through complete page refresh).
275
     *
276
     * @param array  $header
277
     * @param array  $content         Array of row arrays
278
     * @param array  $sorting_options
279
     * @param array  $paging_options
280
     * @param array  $query_vars
281
     * @param array  $form_actions
282
     * @param string $style
283
     *
284
     * @return string HTML string for array
285
     */
286
    public static function return_sortable_table(
287
        $header,
288
        $content,
289
        $sorting_options = [],
290
        $paging_options = [],
291
        $query_vars = null,
292
        $form_actions = [],
293
        $style = 'table'
294
    ) {
295
        ob_start();
296
        self::display_sortable_table(
297
            $header,
298
            $content,
299
            $sorting_options,
300
            $paging_options,
301
            $query_vars,
302
            $form_actions,
303
            $style
304
        );
305
        $content = ob_get_contents();
306
        ob_end_clean();
307
308
        return $content;
309
    }
310
311
    /**
312
     * Shows a nice grid.
313
     *
314
     * @param string grid name (important to create css)
315
     * @param array header content
316
     * @param array array with the information to show
317
     * @param array $paging_options Keys are:
318
     *                              'per_page_default' = items per page when switching from
319
     *                              full-    list to per-page-view
320
     *                              'per_page' = number of items to show per page
321
     *                              'page_nr' = The page to display
322
     *                              'hide_navigation' =  true to hide the navigation
323
     * @param array $query_vars     Additional variables to add in the query-string
324
     * @param mixed An array with bool values to know which columns show.
325
     * i.e: $visibility_options= array(true, false) we will only show the first column
326
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
327
     */
328
    public static function display_sortable_grid(
329
        $name,
330
        $header,
331
        $content,
332
        $paging_options = [],
333
        $query_vars = null,
334
        $form_actions = [],
335
        $visibility_options = true,
336
        $sort_data = true,
337
        $grid_class = []
338
    ) {
339
        echo self::return_sortable_grid(
340
            $name,
341
            $header,
342
            $content,
343
            $paging_options,
344
            $query_vars,
345
            $form_actions,
346
            $visibility_options,
347
            $sort_data,
348
            $grid_class
349
        );
350
    }
351
352
    /**
353
     * Gets a nice grid in html string.
354
     *
355
     * @param string grid name (important to create css)
356
     * @param array header content
357
     * @param array array with the information to show
358
     * @param array $paging_options Keys are:
359
     *                              'per_page_default' = items per page when switching from
360
     *                              full-    list to per-page-view
361
     *                              'per_page' = number of items to show per page
362
     *                              'page_nr' = The page to display
363
     *                              'hide_navigation' =  true to hide the navigation
364
     * @param array $query_vars     Additional variables to add in the query-string
365
     * @param mixed An array with bool values to know which columns show. i.e:
366
     *  $visibility_options= array(true, false) we will only show the first column
367
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
368
     * @param bool  true for sorting data or false otherwise
369
     * @param array grid classes
370
     *
371
     * @return string html grid
372
     */
373
    public static function return_sortable_grid(
374
        $name,
375
        $header,
376
        $content,
377
        $paging_options = [],
378
        $query_vars = null,
379
        $form_actions = [],
380
        $visibility_options = true,
381
        $sort_data = true,
382
        $grid_class = [],
383
        $elementCount = 0
384
    ) {
385
        $column = 0;
386
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
387
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
388
        $table->total_number_of_items = intval($elementCount);
389
        if (is_array($query_vars)) {
390
            $table->set_additional_parameters($query_vars);
391
        }
392
393
        return $table->display_simple_grid(
394
            $visibility_options,
395
            $paging_options['hide_navigation'],
396
            $default_items_per_page,
397
            $sort_data,
398
            $grid_class
399
        );
400
    }
401
402
    /**
403
     * Displays a table with a special configuration.
404
     *
405
     * @param array $header          Titles for the table header
406
     *                               each item in this array can contain 3 values
407
     *                               - 1st element: the column title
408
     *                               - 2nd element: true or false (column sortable?)
409
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
410
     *                               - 4the element: additional attributes for the td-tags
411
     * @param array $content         2D-array with the tables content
412
     * @param array $sorting_options Keys are:
413
     *                               'column' = The column to use as sort-key
414
     *                               'direction' = SORT_ASC or SORT_DESC
415
     * @param array $paging_options  Keys are:
416
     *                               'per_page_default' = items per page when switching from full list to per-page-view
417
     *                               'per_page' = number of items to show per page
418
     *                               'page_nr' = The page to display
419
     * @param array $query_vars      Additional variables to add in the query-string
420
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
421
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
422
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
423
     * @param array $form_actions    Set optional forms actions
424
     *
425
     * @author Julio Montoya
426
     */
427
    public static function display_sortable_config_table(
428
        $table_name,
429
        $header,
430
        $content,
431
        $sorting_options = [],
432
        $paging_options = [],
433
        $query_vars = null,
434
        $column_show = [],
435
        $column_order = [],
436
        $form_actions = []
437
    ) {
438
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
439
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
440
441
        $table = new SortableTableFromArrayConfig(
442
            $content,
443
            $column,
444
            $default_items_per_page,
445
            $table_name,
446
            $column_show,
447
            $column_order
448
        );
449
450
        if (is_array($query_vars)) {
451
            $table->set_additional_parameters($query_vars);
452
        }
453
        // Show or hide the columns header
454
        if (is_array($column_show)) {
455
            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...
456
                if (!empty($column_show[$i])) {
457
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
458
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
459
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
460
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
461
                    $table->set_header($i, $val0, $val1, $val2, $val3);
462
                }
463
            }
464
        }
465
        $table->set_form_actions($form_actions);
466
        $table->display();
467
    }
468
469
    /**
470
     * Returns a div html string with.
471
     *
472
     * @param string $message
473
     * @param string $type    Example: confirm, normal, warning, error
474
     * @param bool   $filter  Whether to XSS-filter or not
475
     *
476
     * @return string Message wrapped into an HTML div
477
     */
478
    public static function return_message($message, $type = 'normal', $filter = true)
479
    {
480
        if (empty($message)) {
481
            return '';
482
        }
483
484
        if ($filter) {
485
            $message = api_htmlentities(
486
                $message,
487
                ENT_QUOTES,
488
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
489
            );
490
        }
491
492
        $class = '';
493
        switch ($type) {
494
            case 'warning':
495
                $class .= 'alert alert-warning';
496
                break;
497
            case 'error':
498
                $class .= 'alert alert-danger';
499
                break;
500
            case 'confirmation':
501
            case 'confirm':
502
            case 'success':
503
                $class .= 'alert alert-success';
504
                break;
505
            case 'normal':
506
            case 'info':
507
            default:
508
                $class .= 'alert alert-info';
509
        }
510
511
        return self::div($message, ['class' => $class]);
512
    }
513
514
    /**
515
     * Returns an encrypted mailto hyperlink.
516
     *
517
     * @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...
518
     * @param string  clickable text
519
     * @param string  optional, class from stylesheet
520
     * @param bool $addExtraContent
521
     *
522
     * @return string encrypted mailto hyperlink
523
     */
524
    public static function encrypted_mailto_link(
525
        $email,
526
        $clickable_text = null,
527
        $style_class = '',
528
        $addExtraContent = false
529
    ) {
530
        if (is_null($clickable_text)) {
531
            $clickable_text = $email;
532
        }
533
534
        // "mailto:" already present?
535
        if ('mailto:' !== substr($email, 0, 7)) {
536
            $email = 'mailto:'.$email;
537
        }
538
539
        // Class (stylesheet) defined?
540
        if ('' !== $style_class) {
541
            $style_class = ' class="'.$style_class.'"';
542
        }
543
544
        // Encrypt email
545
        $hmail = '';
546
        for ($i = 0; $i < strlen($email); $i++) {
547
            $hmail .= '&#'.ord($email[$i]).';';
548
        }
549
550
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
551
552
        if ($value) {
553
            if ('false' === api_get_setting('allow_email_editor')) {
554
                $hmail .= '?';
555
            }
556
557
            if (!api_is_anonymous()) {
558
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
559
            }
560
            if ($addExtraContent) {
561
                $content = '';
562
                if (!api_is_anonymous()) {
563
                    $userInfo = api_get_user_info();
564
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
565
566
                    $courseInfo = api_get_course_info();
567
                    if (!empty($courseInfo)) {
568
                        $content .= get_lang('Course').': ';
569
                        $content .= $courseInfo['name'];
570
                        $sessionInfo = api_get_session_info(api_get_session_id());
571
                        if (!empty($sessionInfo)) {
572
                            $content .= ' '.$sessionInfo['name'].' <br />';
573
                        }
574
                    }
575
                }
576
                $hmail .= '&body='.rawurlencode($content);
577
            }
578
        }
579
580
        $hclickable_text = '';
581
        // Encrypt clickable text if @ is present
582
        if (strpos($clickable_text, '@')) {
583
            for ($i = 0; $i < strlen($clickable_text); $i++) {
584
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
585
            }
586
        } else {
587
            $hclickable_text = @htmlspecialchars(
588
                $clickable_text,
589
                ENT_QUOTES,
590
                api_get_system_encoding()
591
            );
592
        }
593
        // Return encrypted mailto hyperlink
594
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
595
    }
596
597
    /**
598
     * Returns an mailto icon hyperlink.
599
     *
600
     * @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...
601
     * @param string  icon source file from the icon lib
602
     * @param int  icon size from icon lib
603
     * @param string  optional, class from stylesheet
604
     *
605
     * @return string encrypted mailto hyperlink
606
     */
607
    public static function icon_mailto_link(
608
        $email,
609
        $icon_file = "mail.png",
610
        $icon_size = 22,
611
        $style_class = ''
612
    ) {
613
        // "mailto:" already present?
614
        if ('mailto:' != substr($email, 0, 7)) {
615
            $email = 'mailto:'.$email;
616
        }
617
        // Class (stylesheet) defined?
618
        if ('' != $style_class) {
619
            $style_class = ' class="'.$style_class.'"';
620
        }
621
        // Encrypt email
622
        $hmail = '';
623
        for ($i = 0; $i < strlen($email); $i++) {
624
            $hmail .= '&#'.ord($email[
625
            $i]).';';
626
        }
627
        // icon html code
628
        $icon_html_source = self::return_icon(
629
            $icon_file,
630
            $hmail,
631
            '',
632
            $icon_size
633
        );
634
        // Return encrypted mailto hyperlink
635
636
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
637
    }
638
639
    /**
640
     * Prints an <option>-list with all letters (A-Z).
641
     *
642
     * @todo This is English language specific implementation.
643
     * It should be adapted for the other languages.
644
     *
645
     * @return string
646
     */
647
    public static function get_alphabet_options($selectedLetter = '')
648
    {
649
        $result = '';
650
        for ($i = 65; $i <= 90; $i++) {
651
            $letter = chr($i);
652
            $result .= '<option value="'.$letter.'"';
653
            if ($selectedLetter == $letter) {
654
                $result .= ' selected="selected"';
655
            }
656
            $result .= '>'.$letter.'</option>';
657
        }
658
659
        return $result;
660
    }
661
662
    /**
663
     * Get the options withing a select box within the given values.
664
     *
665
     * @param int   Min value
666
     * @param int   Max value
667
     * @param int   Default value
668
     *
669
     * @return string HTML select options
670
     */
671
    public static function get_numeric_options($min, $max, $selected_num = 0)
672
    {
673
        $result = '';
674
        for ($i = $min; $i <= $max; $i++) {
675
            $result .= '<option value="'.$i.'"';
676
            if (is_int($selected_num)) {
677
                if ($selected_num == $i) {
678
                    $result .= ' selected="selected"';
679
                }
680
            }
681
            $result .= '>'.$i.'</option>';
682
        }
683
684
        return $result;
685
    }
686
687
    /**
688
     * This public function displays an icon.
689
     *
690
     * @param string   The filename of the file (in the main/img/ folder
691
     * @param string   The alt text (probably a language variable)
692
     * @param array    additional attributes (for instance height, width, onclick, ...)
693
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
694
     */
695
    public static function display_icon(
696
        $image,
697
        $alt_text = '',
698
        $additional_attributes = [],
699
        $size = null
700
    ) {
701
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
702
    }
703
704
    /**
705
     * Gets the path of an icon.
706
     *
707
     * @param string $icon
708
     * @param int    $size
709
     *
710
     * @return string
711
     */
712
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
713
    {
714
        return self::return_icon($icon, null, null, $size, null, true, false);
715
    }
716
717
    /**
718
     * This public function returns the htmlcode for an icon.
719
     *
720
     * @param string   The filename of the file (in the main/img/ folder
721
     * @param string   The alt text (probably a language variable)
722
     * @param array    Additional attributes (for instance height, width, onclick, ...)
723
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
724
     *
725
     * @return string An HTML string of the right <img> tag
726
     *
727
     * @author Patrick Cool <[email protected]>, Ghent University 2006
728
     * @author Julio Montoya 2010 Function improved, adding image constants
729
     * @author Yannick Warnier 2011 Added size handler
730
     *
731
     * @version Feb 2011
732
     */
733
    public static function return_icon(
734
        $image,
735
        $alt_text = '',
736
        $additional_attributes = [],
737
        $size = ICON_SIZE_SMALL,
738
        $show_text = true,
739
        $return_only_path = false,
740
        $loadThemeIcon = true
741
    ) {
742
        $code_path = api_get_path(SYS_PUBLIC_PATH);
743
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
744
        // The following path is checked to see if the file exist. It's
745
        // important to use the public path (i.e. web/css/) rather than the
746
        // internal path (/app/Resource/public/css/) because the path used
747
        // in the end must be the public path
748
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
749
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
750
751
        // Avoid issues with illegal string offset for legacy calls to this
752
        // method with an empty string rather than null or an empty array
753
        if (empty($additional_attributes)) {
754
            $additional_attributes = [];
755
        }
756
757
        $image = trim($image);
758
759
        if (isset($size)) {
760
            $size = (int) $size;
761
        } else {
762
            $size = ICON_SIZE_SMALL;
763
        }
764
765
        $size_extra = $size.'/';
766
        $icon = $w_code_path.'img/'.$image;
767
        $theme = 'themes/chamilo/icons/';
768
769
        if ($loadThemeIcon) {
770
            // @todo with chamilo 2 code
771
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
772
            if (is_file($alternateCssPath.$theme.$image)) {
773
                $icon = $alternateWebCssPath.$theme.$image;
774
            }
775
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
776
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
777
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
778
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
779
                //Checking the main/img/icons/XXX/ folder
780
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
781
            }
782
        } else {
783
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
784
                // Checking the main/img/icons/XXX/ folder
785
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
786
            }
787
        }
788
789
        // Special code to enable SVG - refs #7359 - Needs more work
790
        // The code below does something else to "test out" SVG: for each icon,
791
        // it checks if there is an SVG version. If so, it uses it.
792
        // When moving this to production, the return_icon() calls should
793
        // ask for the SVG version directly
794
        $svgIcons = api_get_setting('icons_mode_svg');
795
        if ('true' == $svgIcons && false == $return_only_path) {
796
            $svgImage = substr($image, 0, -3).'svg';
797
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
798
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
799
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
800
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
801
            }
802
803
            if (empty($additional_attributes['height'])) {
804
                $additional_attributes['height'] = $size;
805
            }
806
            if (empty($additional_attributes['width'])) {
807
                $additional_attributes['width'] = $size;
808
            }
809
        }
810
811
        if ($return_only_path) {
812
            return $icon;
813
        }
814
815
        $img = self::img($icon, $alt_text, $additional_attributes);
816
        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...
817
            if ($show_text) {
818
                $img = "$img $alt_text";
819
            }
820
        }
821
822
        return $img;
823
    }
824
825
    /**
826
     * Returns the htmlcode for an image.
827
     *
828
     * @param string $image_path            the filename of the file (in the main/img/ folder
829
     * @param string $alt_text              the alt text (probably a language variable)
830
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
831
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
832
     *
833
     * @return string
834
     *
835
     * @author Julio Montoya 2010
836
     */
837
    public static function img(
838
        $image_path,
839
        $alt_text = '',
840
        $additional_attributes = null,
841
        $filterPath = true
842
    ) {
843
        if (empty($image_path)) {
844
            return '';
845
        }
846
        // Sanitizing the parameter $image_path
847
        if ($filterPath) {
848
            $image_path = Security::filter_img_path($image_path);
849
        }
850
851
        // alt text = the image name if there is none provided (for XHTML compliance)
852
        if ('' == $alt_text) {
853
            $alt_text = basename($image_path);
854
        }
855
856
        if (empty($additional_attributes)) {
857
            $additional_attributes = [];
858
        }
859
860
        $additional_attributes['src'] = $image_path;
861
862
        if (empty($additional_attributes['alt'])) {
863
            $additional_attributes['alt'] = $alt_text;
864
        }
865
        if (empty($additional_attributes['title'])) {
866
            $additional_attributes['title'] = $alt_text;
867
        }
868
869
        return self::tag('img', '', $additional_attributes);
870
    }
871
872
    /**
873
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
874
     *
875
     * @param string $tag                   the tag name
876
     * @param string $content               the tag's content
877
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
878
     *
879
     * @return string
880
     *
881
     * @author Julio Montoya 2010
882
     */
883
    public static function tag($tag, $content, $additional_attributes = [])
884
    {
885
        $attribute_list = '';
886
        // Managing the additional attributes
887
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
888
            $attribute_list = '';
889
            foreach ($additional_attributes as $key => &$value) {
890
                $attribute_list .= $key.'="'.$value.'" ';
891
            }
892
        }
893
        //some tags don't have this </XXX>
894
        if (in_array($tag, ['img', 'input', 'br'])) {
895
            $return_value = '<'.$tag.' '.$attribute_list.' />';
896
        } else {
897
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
898
        }
899
900
        return $return_value;
901
    }
902
903
    /**
904
     * Creates a URL anchor.
905
     *
906
     * @param string $name
907
     * @param string $url
908
     * @param array  $attributes
909
     *
910
     * @return string
911
     */
912
    public static function url($name, $url, $attributes = [])
913
    {
914
        if (!empty($url)) {
915
            $url = preg_replace('#&amp;#', '&', $url);
916
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
917
            $attributes['href'] = $url;
918
        }
919
920
        return self::tag('a', $name, $attributes);
921
    }
922
923
    /**
924
     * Creates a div tag.
925
     *
926
     * @param string $content
927
     * @param array  $attributes
928
     *
929
     * @return string
930
     */
931
    public static function div($content, $attributes = [])
932
    {
933
        return self::tag('div', $content, $attributes);
934
    }
935
936
    /**
937
     * Creates a span tag.
938
     */
939
    public static function span($content, $attributes = [])
940
    {
941
        return self::tag('span', $content, $attributes);
942
    }
943
944
    /**
945
     * Displays an HTML input tag.
946
     */
947
    public static function input($type, $name, $value, $attributes = [])
948
    {
949
        if (isset($type)) {
950
            $attributes['type'] = $type;
951
        }
952
        if (isset($name)) {
953
            $attributes['name'] = $name;
954
        }
955
        if (isset($value)) {
956
            $attributes['value'] = $value;
957
        }
958
959
        return self::tag('input', '', $attributes);
960
    }
961
962
    /**
963
     * @param $name
964
     * @param $value
965
     * @param array $attributes
966
     *
967
     * @return string
968
     */
969
    public static function button($name, $value, $attributes = [])
970
    {
971
        if (!empty($name)) {
972
            $attributes['name'] = $name;
973
        }
974
975
        return self::tag('button', $value, $attributes);
976
    }
977
978
    /**
979
     * Displays an HTML select tag.
980
     *
981
     * @param string $name
982
     * @param array  $values
983
     * @param int    $default
984
     * @param array  $extra_attributes
985
     * @param bool   $show_blank_item
986
     * @param string $blank_item_text
987
     *
988
     * @return string
989
     */
990
    public static function select(
991
        $name,
992
        $values,
993
        $default = -1,
994
        $extra_attributes = [],
995
        $show_blank_item = true,
996
        $blank_item_text = ''
997
    ) {
998
        $html = '';
999
        $extra = '';
1000
        $default_id = 'id="'.$name.'" ';
1001
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1002
        foreach ($extra_attributes as $key => $parameter) {
1003
            if ('id' == $key) {
1004
                $default_id = '';
1005
            }
1006
            $extra .= $key.'="'.$parameter.'" ';
1007
        }
1008
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1009
1010
        if ($show_blank_item) {
1011
            if (empty($blank_item_text)) {
1012
                $blank_item_text = get_lang('Select');
1013
            } else {
1014
                $blank_item_text = Security::remove_XSS($blank_item_text);
1015
            }
1016
            $html .= self::tag(
1017
                'option',
1018
                '-- '.$blank_item_text.' --',
1019
                ['value' => '-1']
1020
            );
1021
        }
1022
        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...
1023
            foreach ($values as $key => $value) {
1024
                if (is_array($value) && isset($value['name'])) {
1025
                    $value = $value['name'];
1026
                }
1027
                $html .= '<option value="'.$key.'"';
1028
1029
                if (is_array($default)) {
1030
                    foreach ($default as $item) {
1031
                        if ($item == $key) {
1032
                            $html .= ' selected="selected"';
1033
                            break;
1034
                        }
1035
                    }
1036
                } else {
1037
                    if ($default == $key) {
1038
                        $html .= ' selected="selected"';
1039
                    }
1040
                }
1041
1042
                $html .= '>'.$value.'</option>';
1043
            }
1044
        }
1045
        $html .= '</select>';
1046
1047
        return $html;
1048
    }
1049
1050
    /**
1051
     * Creates a tab menu
1052
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1053
     * in the $htmlHeadXtra variable before the display_header
1054
     * Add this script.
1055
     *
1056
     * @example
1057
     * <script>
1058
                </script>
1059
     * @param array  $headers       list of the tab titles
1060
     * @param array  $items
1061
     * @param string $id            id of the container of the tab in the example "tabs"
1062
     * @param array  $attributes    for the ul
1063
     * @param array  $ul_attributes
1064
     * @param string $selected
1065
     *
1066
     * @return string
1067
     */
1068
    public static function tabs(
1069
        $headers,
1070
        $items,
1071
        $id = 'tabs',
1072
        $attributes = [],
1073
        $ul_attributes = [],
1074
        $selected = ''
1075
    ) {
1076
        if (empty($headers) || 0 == count($headers)) {
1077
            return '';
1078
        }
1079
1080
        $lis = '';
1081
        $i = 1;
1082
        foreach ($headers as $item) {
1083
            $active = '';
1084
            if (1 == $i) {
1085
                $active = ' active';
1086
            }
1087
1088
            if (!empty($selected)) {
1089
                $active = '';
1090
                if ($selected == $i) {
1091
                    $active = ' active';
1092
                }
1093
            }
1094
1095
            $item = self::tag(
1096
                'a',
1097
                $item,
1098
                [
1099
                    'href' => '#'.$id.'-'.$i,
1100
                    'class' => 'nav-item nav-link '.$active,
1101
                    'id' => $id.$i.'-tab',
1102
                    'data-toggle' => 'tab',
1103
                    'role' => 'tab',
1104
                    'aria-controls' => $id.'-'.$i,
1105
                    'aria-selected' => $selected,
1106
                ]
1107
            );
1108
            $lis .= $item;
1109
            $i++;
1110
        }
1111
1112
        $ul = self::tag(
1113
            'nav',
1114
            $lis,
1115
            [
1116
                'id' => 'ul_'.$id,
1117
                'class' => 'nav nav-tabs',
1118
                'role' => 'tablist',
1119
            ]
1120
        );
1121
1122
        $i = 1;
1123
        $divs = '';
1124
        foreach ($items as $content) {
1125
            $active = '';
1126
            if (1 == $i) {
1127
                $active = ' show active';
1128
            }
1129
1130
            if (!empty($selected)) {
1131
                $active = '';
1132
                if ($selected == $i) {
1133
                    $active = ' show active';
1134
                }
1135
            }
1136
1137
            $divs .= self::tag(
1138
                'div',
1139
                $content,
1140
                [
1141
                    'id' => $id.'-'.$i,
1142
                    'class' => 'tab-pane fade '.$active,
1143
                    'role' => 'tabpanel',
1144
                    'aria-labelledby' => $id.$i.'-tab',
1145
                ]
1146
            );
1147
            $i++;
1148
        }
1149
1150
        $attributes['id'] = $id;
1151
        $attributes['class'] = 'tab_wrapper';
1152
1153
        return self::tag(
1154
            'div',
1155
            $ul.
1156
            self::tag('div', $divs, ['class' => 'tab-content']),
1157
            $attributes
1158
        );
1159
    }
1160
1161
    /**
1162
     * @param $headers
1163
     * @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...
1164
     *
1165
     * @return string
1166
     */
1167
    public static function tabsOnlyLink($headers, $selected = null)
1168
    {
1169
        $id = uniqid('tabs_');
1170
        $i = 1;
1171
        $list = '';
1172
        foreach ($headers as $item) {
1173
            $class = null;
1174
            if ($i == $selected) {
1175
                $class = 'active';
1176
            }
1177
            $item = self::tag(
1178
                'a',
1179
                $item['content'],
1180
                [
1181
                    'id' => $id.'-'.$i,
1182
                    'href' => $item['url'],
1183
                    'class' => 'nav-link '.$class,
1184
                ]
1185
            );
1186
            $list .= $item;
1187
            $i++;
1188
        }
1189
1190
        return self::toolbarAction($id, [$list]);
1191
    }
1192
1193
    /**
1194
     * In order to display a grid using jqgrid you have to:.
1195
     *
1196
     * @example
1197
     * After your Display::display_header function you have to add the nex javascript code:
1198
     * <script>
1199
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1200
     *   // for more information of this function check the grid_js() function
1201
     * </script>
1202
     * //Then you have to call the grid_html
1203
     * echo Display::grid_html('my_grid_name');
1204
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1205
     *
1206
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1207
     *
1208
     * @return string html
1209
     */
1210
    public static function grid_html($div_id)
1211
    {
1212
        $table = self::tag('table', '', ['id' => $div_id]);
1213
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1214
1215
        return $table;
1216
    }
1217
1218
    /**
1219
     * @param string $label
1220
     * @param string $form_item
1221
     *
1222
     * @return string
1223
     */
1224
    public static function form_row($label, $form_item)
1225
    {
1226
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1227
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1228
1229
        return self::div($label.$form_item, ['class' => 'form-group']);
1230
    }
1231
1232
    /**
1233
     * This is a wrapper to use the jqgrid in Chamilo.
1234
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1235
     * This function need to be in the ready jquery function
1236
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1237
     * In order to work this function needs the Display::grid_html function with the same div id.
1238
     *
1239
     * @param string $div_id       div id
1240
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1241
     * @param array  $column_names Visible columns (you should use get_lang).
1242
     *                             An array in which we place the names of the columns.
1243
     *                             This is the text that appears in the head of the grid (Header layer).
1244
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1245
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1246
     *                             This is the most important part of the grid.
1247
     *                             For a full description of all valid values see colModel API. See the url above.
1248
     * @param array  $extra_params extra parameters
1249
     * @param array  $data         data that will be loaded
1250
     * @param string $formatter    A string that will be appended to the JSON returned
1251
     * @param bool   $fixed_width  not implemented yet
1252
     *
1253
     * @return string the js code
1254
     */
1255
    public static function grid_js(
1256
        $div_id,
1257
        $url,
1258
        $column_names,
1259
        $column_model,
1260
        $extra_params,
1261
        $data = [],
1262
        $formatter = '',
1263
        $fixed_width = false
1264
    ) {
1265
        $obj = new stdClass();
1266
        $obj->first = 'first';
1267
1268
        if (!empty($url)) {
1269
            $obj->url = $url;
1270
        }
1271
1272
        // Needed it in order to render the links/html in the grid
1273
        foreach ($column_model as &$columnModel) {
1274
            if (!isset($columnModel['formatter'])) {
1275
                $columnModel['formatter'] = '';
1276
            }
1277
        }
1278
1279
        //This line should only be used/modified in case of having characters
1280
        // encoding problems - see #6159
1281
        //$column_names = array_map("utf8_encode", $column_names);
1282
        $obj->colNames = $column_names;
1283
        $obj->colModel = $column_model;
1284
        $obj->pager = '#'.$div_id.'_pager';
1285
        $obj->datatype = 'json';
1286
        $obj->viewrecords = 'true';
1287
        $obj->guiStyle = 'bootstrap4';
1288
        $obj->iconSet = 'fontAwesomeSolid';
1289
        $all_value = 10000000;
1290
1291
        // Sets how many records we want to view in the grid
1292
        $obj->rowNum = 20;
1293
1294
        // Default row quantity
1295
        if (!isset($extra_params['rowList'])) {
1296
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1297
            $rowList = api_get_configuration_value('table_row_list');
1298
            if (!empty($rowList) && isset($rowList['options'])) {
1299
                $rowList = $rowList['options'];
1300
                $rowList[] = $all_value;
1301
            }
1302
            $extra_params['rowList'] = $rowList;
1303
        }
1304
1305
        $defaultRow = api_get_configuration_value('table_default_row');
1306
        if (!empty($defaultRow)) {
1307
            $obj->rowNum = (int) $defaultRow;
1308
        }
1309
1310
        $json = '';
1311
        if (!empty($extra_params['datatype'])) {
1312
            $obj->datatype = $extra_params['datatype'];
1313
        }
1314
1315
        // Row even odd style.
1316
        $obj->altRows = true;
1317
        if (!empty($extra_params['altRows'])) {
1318
            $obj->altRows = $extra_params['altRows'];
1319
        }
1320
1321
        if (!empty($extra_params['sortname'])) {
1322
            $obj->sortname = $extra_params['sortname'];
1323
        }
1324
1325
        if (!empty($extra_params['sortorder'])) {
1326
            $obj->sortorder = $extra_params['sortorder'];
1327
        }
1328
1329
        if (!empty($extra_params['rowList'])) {
1330
            $obj->rowList = $extra_params['rowList'];
1331
        }
1332
1333
        if (!empty($extra_params['rowNum'])) {
1334
            $obj->rowNum = $extra_params['rowNum'];
1335
        } else {
1336
            // Try to load max rows from Session
1337
            $urlInfo = parse_url($url);
1338
            if (isset($urlInfo['query'])) {
1339
                parse_str($urlInfo['query'], $query);
1340
                if (isset($query['a'])) {
1341
                    $action = $query['a'];
1342
                    // This value is set in model.ajax.php
1343
                    $savedRows = Session::read('max_rows_'.$action);
1344
                    if (!empty($savedRows)) {
1345
                        $obj->rowNum = $savedRows;
1346
                    }
1347
                }
1348
            }
1349
        }
1350
1351
        if (!empty($extra_params['viewrecords'])) {
1352
            $obj->viewrecords = $extra_params['viewrecords'];
1353
        }
1354
1355
        $beforeSelectRow = null;
1356
        if (isset($extra_params['beforeSelectRow'])) {
1357
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1358
            unset($extra_params['beforeSelectRow']);
1359
        }
1360
1361
        $beforeProcessing = '';
1362
        if (isset($extra_params['beforeProcessing'])) {
1363
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1364
            unset($extra_params['beforeProcessing']);
1365
        }
1366
1367
        $beforeRequest = '';
1368
        if (isset($extra_params['beforeRequest'])) {
1369
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1370
            unset($extra_params['beforeRequest']);
1371
        }
1372
1373
        $gridComplete = '';
1374
        if (isset($extra_params['gridComplete'])) {
1375
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1376
            unset($extra_params['gridComplete']);
1377
        }
1378
1379
        // Adding extra params
1380
        if (!empty($extra_params)) {
1381
            foreach ($extra_params as $key => $element) {
1382
                // the groupHeaders key gets a special treatment
1383
                if ('groupHeaders' != $key) {
1384
                    $obj->$key = $element;
1385
                }
1386
            }
1387
        }
1388
1389
        // Adding static data.
1390
        if (!empty($data)) {
1391
            $data_var = $div_id.'_data';
1392
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1393
            $obj->data = $data_var;
1394
            $obj->datatype = 'local';
1395
            $json .= "\n";
1396
        }
1397
1398
        $obj->end = 'end';
1399
1400
        $json_encode = json_encode($obj);
1401
1402
        if (!empty($data)) {
1403
            //Converts the "data":"js_variable" to "data":js_variable,
1404
            // otherwise it will not work
1405
            $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...
1406
        }
1407
1408
        // Fixing true/false js values that doesn't need the ""
1409
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1410
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1411
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1412
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1413
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1414
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1415
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1416
1417
        if (api_get_configuration_value('allow_compilatio_tool') &&
1418
            (false !== strpos($_SERVER['REQUEST_URI'], 'work/work.php') ||
1419
             false != strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php')
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($_SERVER['REQUEST...ork/work_list_all.php') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1420
            )
1421
        ) {
1422
            $json_encode = str_replace('"function () { compilatioInit() }"',
1423
                'function () { compilatioInit() }',
1424
                $json_encode
1425
            );
1426
        }
1427
        // Creating the jqgrid element.
1428
        $json .= '$("#'.$div_id.'").jqGrid({';
1429
        //$json .= $beforeSelectRow;
1430
        $json .= $gridComplete;
1431
        $json .= $beforeProcessing;
1432
        $json .= $beforeRequest;
1433
        $json .= $json_encode;
1434
        $json .= '});';
1435
1436
        // Grouping headers option
1437
        if (isset($extra_params['groupHeaders'])) {
1438
            $groups = '';
1439
            foreach ($extra_params['groupHeaders'] as $group) {
1440
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1441
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1442
            }
1443
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1444
                "useColSpanStyle" : false,
1445
                "groupHeaders"    : [
1446
                    '.$groups.'
1447
                ]
1448
            });';
1449
        }
1450
1451
        $all_text = addslashes(get_lang('All'));
1452
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1453
        $json .= "\n";
1454
        // Adding edit/delete icons.
1455
        $json .= $formatter;
1456
1457
        return $json;
1458
    }
1459
1460
    /**
1461
     * @param array $headers
1462
     * @param array $rows
1463
     * @param array $attributes
1464
     *
1465
     * @return string
1466
     */
1467
    public static function table($headers, $rows, $attributes = [])
1468
    {
1469
        if (empty($attributes)) {
1470
            $attributes['class'] = 'data_table';
1471
        }
1472
        $table = new HTML_Table($attributes);
1473
        $row = 0;
1474
        $column = 0;
1475
1476
        // Course headers
1477
        if (!empty($headers)) {
1478
            foreach ($headers as $item) {
1479
                $table->setHeaderContents($row, $column, $item);
1480
                $column++;
1481
            }
1482
            $row = 1;
1483
            $column = 0;
1484
        }
1485
1486
        if (!empty($rows)) {
1487
            foreach ($rows as $content) {
1488
                $table->setCellContents($row, $column, $content);
1489
                $row++;
1490
            }
1491
        }
1492
1493
        return $table->toHtml();
1494
    }
1495
1496
    /**
1497
     * Returns the "what's new" icon notifications.
1498
     *
1499
     * The general logic of this function is to track the last time the user
1500
     * entered the course and compare to what has changed inside this course
1501
     * since then, based on the item_property table inside this course. Note that,
1502
     * if the user never entered the course before, he will not see notification
1503
     * icons. This function takes session ID into account (if any) and only shows
1504
     * the corresponding notifications.
1505
     *
1506
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1507
     * @param bool  $loadAjax
1508
     *
1509
     * @return string The HTML link to be shown next to the course
1510
     */
1511
    public static function show_notification($courseInfo, $loadAjax = true)
1512
    {
1513
        if (empty($courseInfo)) {
1514
            return '';
1515
        }
1516
1517
        return '';
1518
1519
        $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...
1520
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1521
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
0 ignored issues
show
Bug introduced by
The constant TABLE_ITEM_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1522
        $course_code = Database::escape_string($courseInfo['code']);
1523
1524
        $user_id = api_get_user_id();
1525
        $course_id = (int) $courseInfo['real_id'];
1526
        $sessionId = (int) $courseInfo['id_session'];
1527
        $status = (int) $courseInfo['status'];
1528
1529
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1530
1531
        if ($loadNotificationsByAjax) {
1532
            if ($loadAjax) {
1533
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1534
                Session::write($id, true);
1535
1536
                return '<span id ="'.$id.'" class="course_notification"></span>';
1537
            }
1538
        }
1539
1540
        // Get the user's last access dates to all tools of this course
1541
        $sql = "SELECT *
1542
                FROM $t_track_e_access
1543
                WHERE
1544
                    c_id = $course_id AND
1545
                    access_user_id = '$user_id' AND
1546
                    access_session_id ='".$sessionId."'
1547
                ORDER BY access_date DESC
1548
                LIMIT 1
1549
                ";
1550
        $result = Database::query($sql);
1551
1552
        // latest date by default is the creation date
1553
        $latestDate = $courseInfo['creation_date'];
1554
        if (Database::num_rows($result)) {
1555
            $row = Database::fetch_array($result, 'ASSOC');
1556
            $latestDate = $row['access_date'];
1557
        }
1558
1559
        $sessionCondition = api_get_session_condition(
1560
            $sessionId,
1561
            true,
1562
            false,
1563
            'session_id'
1564
        );
1565
1566
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1567
        // Get current tools in course
1568
        $sql = "SELECT name
1569
                FROM $course_tool_table
1570
                WHERE
1571
                    c_id = $course_id AND
1572
                    visibility = '1' AND
1573
                    name NOT IN ('".implode("','", $hideTools)." ')
1574
                ";
1575
        $result = Database::query($sql);
1576
        $tools = Database::store_result($result);
1577
1578
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1579
        $group_ids[] = 0; //add group 'everyone'
1580
        $notifications = [];
1581
        if ($tools) {
1582
            foreach ($tools as $tool) {
1583
                $toolName = $tool['name'];
1584
                $toolName = Database::escape_string($toolName);
1585
                // Fix to get student publications
1586
                $toolCondition = " tool = '$toolName' AND ";
1587
                if ('student_publication' == $toolName || 'work' == $toolName) {
1588
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1589
                }
1590
1591
                $toolName = addslashes($toolName);
1592
1593
                $sql = "SELECT * FROM $tool_edit_table
1594
                        WHERE
1595
                            c_id = $course_id AND
1596
                            $toolCondition
1597
                            lastedit_type NOT LIKE '%Deleted%' AND
1598
                            lastedit_type NOT LIKE '%deleted%' AND
1599
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1600
                            lastedit_date > '$latestDate' AND
1601
                            lastedit_user_id != $user_id $sessionCondition AND
1602
                            visibility != 2 AND
1603
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1604
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1605
                        ORDER BY lastedit_date DESC
1606
                        LIMIT 1";
1607
                $result = Database::query($sql);
1608
1609
                $latestChange = Database::fetch_array($result, 'ASSOC');
1610
1611
                if ($latestChange) {
1612
                    $latestChange['link'] = $tool['link'];
1613
                    $latestChange['image'] = $tool['image'];
1614
                    $latestChange['tool'] = $tool['name'];
1615
                    $notifications[$toolName] = $latestChange;
1616
                }
1617
            }
1618
        }
1619
1620
        // Show all tool icons where there is something new.
1621
        $return = '';
1622
        foreach ($notifications as $notification) {
1623
            $toolName = $notification['tool'];
1624
            if (!(
1625
                    '1' == $notification['visibility'] ||
1626
                    ('1' == $status && '0' == $notification['visibility']) ||
1627
                    !isset($notification['visibility'])
1628
                )
1629
            ) {
1630
                continue;
1631
            }
1632
1633
            if (TOOL_SURVEY == $toolName) {
1634
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1635
                if (!empty($survey_info)) {
1636
                    /*$invited_users = SurveyUtil::get_invited_users(
1637
                        $survey_info['code'],
1638
                        $course_code
1639
                    );
1640
                    if (!in_array($user_id, $invited_users['course_users'])) {
1641
                        continue;
1642
                    }*/
1643
                }
1644
            }
1645
1646
            if (TOOL_LEARNPATH == $notification['tool']) {
1647
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1648
                    continue;
1649
                }
1650
            }
1651
1652
            if (TOOL_DROPBOX == $notification['tool']) {
1653
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1654
            }
1655
1656
            if ('work' == $notification['tool'] &&
1657
                'DirectoryCreated' == $notification['lastedit_type']
1658
            ) {
1659
                $notification['lastedit_type'] = 'WorkAdded';
1660
            }
1661
1662
            $lastDate = api_get_local_time($notification['lastedit_date']);
1663
            $type = $notification['lastedit_type'];
1664
            if ('CalendareventVisible' == $type) {
1665
                $type = 'Visible';
1666
            }
1667
            $label = get_lang('Since your latest visit').": ".get_lang($type)." ($lastDate)";
1668
1669
            if (false === strpos($notification['link'], '?')) {
1670
                $notification['link'] = $notification['link'].'?notification=1';
1671
            } else {
1672
                $notification['link'] = $notification['link'].'&notification=1';
1673
            }
1674
1675
            $image = substr($notification['image'], 0, -4).'.png';
1676
1677
            $return .= self::url(
1678
                self::return_icon($image, $label),
1679
                api_get_path(WEB_CODE_PATH).
1680
                $notification['link'].'&cidReq='.$course_code.
1681
                '&ref='.$notification['ref'].
1682
                '&gid='.$notification['to_group_id'].
1683
                '&sid='.$sessionId
1684
            ).PHP_EOL;
1685
        }
1686
1687
        return $return;
1688
    }
1689
1690
    /**
1691
     * Get the session box details as an array.
1692
     *
1693
     * @todo check session visibility.
1694
     *
1695
     * @param int $session_id
1696
     *
1697
     * @return array Empty array or session array
1698
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1699
     */
1700
    public static function getSessionTitleBox($session_id)
1701
    {
1702
        $session_info = api_get_session_info($session_id);
1703
        $coachInfo = [];
1704
        if (!empty($session_info['id_coach'])) {
1705
            $coachInfo = api_get_user_info($session_info['id_coach']);
1706
        }
1707
1708
        $session = [];
1709
        $session['category_id'] = $session_info['session_category_id'];
1710
        $session['title'] = $session_info['name'];
1711
        $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1712
        $session['dates'] = '';
1713
        $session['coach'] = '';
1714
        if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1715
            $session['coach'] = get_lang('General coach').': '.$coachInfo['complete_name'];
1716
        }
1717
        $active = false;
1718
        if (('0000-00-00 00:00:00' == $session_info['access_end_date'] &&
1719
            '0000-00-00 00:00:00' == $session_info['access_start_date']) ||
1720
            (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1721
        ) {
1722
            if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1723
                $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1724
                $session['duration'] = $daysLeft >= 0
1725
                    ? sprintf(get_lang('This session has a maximum duration. Only %s days to go.'), $daysLeft)
1726
                    : get_lang('You are already registered but your allowed access time has expired.');
1727
            }
1728
            $active = true;
1729
        } else {
1730
            $dates = SessionManager::parseSessionDates($session_info, true);
1731
            $session['dates'] = $dates['access'];
1732
            if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1733
                $session['coach'] = $coachInfo['complete_name'];
1734
            }
1735
            //$active = $date_start <= $now && $date_end >= $now;
1736
        }
1737
        $session['active'] = $active;
1738
        $session['session_category_id'] = $session_info['session_category_id'];
1739
        $session['visibility'] = $session_info['visibility'];
1740
        $session['num_users'] = $session_info['nbr_users'];
1741
        $session['num_courses'] = $session_info['nbr_courses'];
1742
        $session['description'] = $session_info['description'];
1743
        $session['show_description'] = $session_info['show_description'];
1744
        //$session['image'] = SessionManager::getSessionImage($session_info['id']);
1745
        $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1746
1747
        $entityManager = Database::getManager();
1748
        $fieldValuesRepo = $entityManager->getRepository(ExtraFieldValues::class);
1749
        $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1750
            ExtraField::SESSION_FIELD_TYPE,
1751
            $session_id
1752
        );
1753
1754
        $session['extra_fields'] = [];
1755
        /** @var ExtraFieldValues $value */
1756
        foreach ($extraFieldValues as $value) {
1757
            if (empty($value)) {
1758
                continue;
1759
            }
1760
            $session['extra_fields'][] = [
1761
                'field' => [
1762
                    'variable' => $value->getField()->getVariable(),
1763
                    'display_text' => $value->getField()->getDisplayText(),
1764
                ],
1765
                'value' => $value->getValue(),
1766
            ];
1767
        }
1768
1769
        return $session;
1770
    }
1771
1772
    /**
1773
     * Return the five star HTML.
1774
     *
1775
     * @param string $id              of the rating ul element
1776
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1777
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1778
     * @param bool   $add_div_wrapper add a div wrapper
1779
     *
1780
     * @return string
1781
     */
1782
    public static function return_rating_system(
1783
        $id,
1784
        $url,
1785
        $point_info = [],
1786
        $add_div_wrapper = true
1787
    ) {
1788
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1789
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1790
1791
        if (!empty($percentage)) {
1792
            $percentage = $percentage * 125 / 100;
1793
        }
1794
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1795
        $star_label = sprintf(get_lang('%s stars out of 5'), $point_info['point_average_star']);
1796
1797
        $html = '<section class="rating-widget">';
1798
        $html .= '<div class="rating-stars"><ul id="stars">';
1799
        $html .= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1800
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1801
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1802
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1803
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1804
        ';
1805
        $html .= '</ul></div>';
1806
        $html .= '</section>';
1807
        $labels = [];
1808
1809
        $labels[] = 1 == $number_of_users_who_voted ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1810
        $labels[] = 1 == $accesses ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1811
        $labels[] = $point_info['user_vote'] ? get_lang('Your vote').' ['.$point_info['user_vote'].']' : get_lang('Your vote').' [?] ';
1812
1813
        if (!$add_div_wrapper && api_is_anonymous()) {
1814
            $labels[] = self::tag('span', get_lang('Login to vote'), ['class' => 'error']);
1815
        }
1816
1817
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1818
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1819
1820
        if ($add_div_wrapper) {
1821
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1822
        }
1823
1824
        return $html;
1825
    }
1826
1827
    /**
1828
     * @param string $title
1829
     * @param string $second_title
1830
     * @param string $size
1831
     * @param bool   $filter
1832
     *
1833
     * @return string
1834
     */
1835
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1836
    {
1837
        if ($filter) {
1838
            $title = Security::remove_XSS($title);
1839
        }
1840
1841
        if (!empty($second_title)) {
1842
            if ($filter) {
1843
                $second_title = Security::remove_XSS($second_title);
1844
            }
1845
            $title .= "<small> $second_title</small>";
1846
        }
1847
1848
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1849
    }
1850
1851
    public static function page_header_and_translate($title, $second_title = null)
1852
    {
1853
        $title = get_lang($title);
1854
1855
        return self::page_header($title, $second_title);
1856
    }
1857
1858
    public static function page_subheader_and_translate($title, $second_title = null)
1859
    {
1860
        $title = get_lang($title);
1861
1862
        return self::page_subheader($title, $second_title);
1863
    }
1864
1865
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1866
    {
1867
        if (!empty($second_title)) {
1868
            $second_title = Security::remove_XSS($second_title);
1869
            $title .= "<small> $second_title<small>";
1870
        }
1871
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1872
1873
        return $subTitle;
1874
    }
1875
1876
    public static function page_subheader2($title, $second_title = null)
1877
    {
1878
        return self::page_header($title, $second_title, 'h4');
1879
    }
1880
1881
    public static function page_subheader3($title, $second_title = null)
1882
    {
1883
        return self::page_header($title, $second_title, 'h5');
1884
    }
1885
1886
    /**
1887
     * @param array $list
1888
     *
1889
     * @return string|null
1890
     */
1891
    public static function description($list)
1892
    {
1893
        $html = null;
1894
        if (!empty($list)) {
1895
            $html = '<dl class="dl-horizontal">';
1896
            foreach ($list as $item) {
1897
                $html .= '<dt>'.$item['title'].'</dt>';
1898
                $html .= '<dd>'.$item['content'].'</dd>';
1899
            }
1900
            $html .= '</dl>';
1901
        }
1902
1903
        return $html;
1904
    }
1905
1906
    /**
1907
     * @param int    $percentage      int value between 0 and 100
1908
     * @param bool   $show_percentage
1909
     * @param string $extra_info
1910
     * @param string $class           danger/success/infowarning
1911
     *
1912
     * @return string
1913
     */
1914
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1915
    {
1916
        $percentage = (int) $percentage;
1917
        $class = empty($class) ? '' : "progress-bar-$class";
1918
1919
        $div = '<div class="progress">
1920
                <div
1921
                    class="progress-bar progress-bar-striped '.$class.'"
1922
                    role="progressbar"
1923
                    aria-valuenow="'.$percentage.'"
1924
                    aria-valuemin="0"
1925
                    aria-valuemax="100"
1926
                    style="width: '.$percentage.'%;"
1927
                >';
1928
        if ($show_percentage) {
1929
            $div .= $percentage.'%';
1930
        } else {
1931
            if (!empty($extra_info)) {
1932
                $div .= $extra_info;
1933
            }
1934
        }
1935
        $div .= '</div></div>';
1936
1937
        return $div;
1938
    }
1939
1940
    /**
1941
     * @param string $count
1942
     * @param string $type
1943
     *
1944
     * @return string|null
1945
     */
1946
    public static function badge($count, $type = 'warning')
1947
    {
1948
        $class = '';
1949
1950
        switch ($type) {
1951
            case 'success':
1952
                $class = 'bg-success';
1953
                break;
1954
            case 'warning':
1955
                $class = 'bg-warning text-dark';
1956
                break;
1957
            case 'important':
1958
                $class = 'bg-important';
1959
                break;
1960
            case 'info':
1961
                $class = 'bg-info';
1962
                break;
1963
            case 'inverse':
1964
                $class = 'bg-inverse';
1965
                break;
1966
        }
1967
1968
        if (!empty($count)) {
1969
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1970
        }
1971
1972
        return null;
1973
    }
1974
1975
    /**
1976
     * @param array $badge_list
1977
     *
1978
     * @return string
1979
     */
1980
    public static function badge_group($badge_list)
1981
    {
1982
        $html = '<div class="badge-group">';
1983
        foreach ($badge_list as $badge) {
1984
            $html .= $badge;
1985
        }
1986
        $html .= '</div>';
1987
1988
        return $html;
1989
    }
1990
1991
    /**
1992
     * @param string $content
1993
     * @param string $type
1994
     *
1995
     * @return string
1996
     */
1997
    public static function label($content, $type = 'default')
1998
    {
1999
        switch ($type) {
2000
            case 'success':
2001
                $class = 'success';
2002
                break;
2003
            case 'warning':
2004
                $class = 'warning text-dark';
2005
                break;
2006
            case 'important':
2007
            case 'danger':
2008
                $class = 'danger';
2009
                break;
2010
            case 'info':
2011
                $class = 'info';
2012
                break;
2013
            case 'primary':
2014
                $class = 'primary';
2015
                break;
2016
            default:
2017
                $class = 'secondary';
2018
                break;
2019
        }
2020
2021
        $html = '';
2022
        if (!empty($content)) {
2023
            $html = '<span class="badge bg-'.$class.'">';
2024
            $html .= $content;
2025
            $html .= '</span>';
2026
        }
2027
2028
        return $html;
2029
    }
2030
2031
    /**
2032
     * @param array  $items
2033
     * @param string $class
2034
     *
2035
     * @return string|null
2036
     */
2037
    public static function actions($items, $class = 'new_actions')
2038
    {
2039
        $html = null;
2040
        if (!empty($items)) {
2041
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2042
            foreach ($items as $value) {
2043
                $class = null;
2044
                if (isset($value['active']) && $value['active']) {
2045
                    $class = 'class ="active"';
2046
                }
2047
2048
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2049
                    $class = 'class ="active"';
2050
                }
2051
                $html .= "<li $class >";
2052
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2053
                $html .= self::url($value['content'], $value['url'], $attributes);
2054
                $html .= '</li>';
2055
            }
2056
            $html .= '</ul></div>';
2057
            $html .= '<br />';
2058
        }
2059
2060
        return $html;
2061
    }
2062
2063
    /**
2064
     * Prints a tooltip.
2065
     *
2066
     * @param string $text
2067
     * @param string $tip
2068
     *
2069
     * @return string
2070
     */
2071
    public static function tip($text, $tip)
2072
    {
2073
        if (empty($tip)) {
2074
            return $text;
2075
        }
2076
2077
        return self::span(
2078
            $text,
2079
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2080
        );
2081
    }
2082
2083
    /**
2084
     * @param array  $items
2085
     * @param string $type
2086
     * @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...
2087
     *
2088
     * @return string|null
2089
     */
2090
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2091
    {
2092
        $html = null;
2093
        if (!empty($items)) {
2094
            if (empty($id)) {
2095
                $id = api_get_unique_id();
2096
            }
2097
            if ('jquery' == $type) {
2098
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2099
            } else {
2100
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2101
            }
2102
2103
            $count = 1;
2104
            foreach ($items as $item) {
2105
                $html .= '<div class="accordion-my-group">';
2106
                $html .= '<div class="accordion-heading">
2107
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2108
                            '.$item['title'].'
2109
                            </a>
2110
                          </div>';
2111
2112
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2113
                $html .= '<div class="accordion-my-inner">
2114
                            '.$item['content'].'
2115
                            </div>
2116
                          </div>';
2117
            }
2118
            $html .= '</div>';
2119
        }
2120
2121
        return $html;
2122
    }
2123
2124
    /**
2125
     * @param array $buttons
2126
     *
2127
     * @return string
2128
     */
2129
    public static function groupButton($buttons)
2130
    {
2131
        $html = '<div class="btn-group" role="group">';
2132
        foreach ($buttons as $button) {
2133
            $html .= $button;
2134
        }
2135
        $html .= '</div>';
2136
2137
        return $html;
2138
    }
2139
2140
    /**
2141
     * @todo use twig
2142
     *
2143
     * @param string $title
2144
     * @param array  $elements
2145
     * @param bool   $alignToRight
2146
     *
2147
     * @return string
2148
     */
2149
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2150
    {
2151
        $id = uniqid('dropdown', false);
2152
        $html = '
2153
        <div class="dropdown inline-block relative">
2154
            <button
2155
                id="'.$id.'"
2156
                type="button"
2157
                class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
2158
                aria-expanded="false"
2159
                aria-haspopup="true"
2160
            >
2161
              '.$title.'
2162
              <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
2163
                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
2164
              </svg>
2165
            </button>
2166
            <div
2167
                id="'.$id.'_menu"
2168
                class=" dropdown-menu hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
2169
                role="menu"
2170
                aria-orientation="vertical"
2171
                aria-labelledby="menu-button"
2172
                tabindex="-1"
2173
            >
2174
            <div class="py-1" role="none">';
2175
            foreach ($elements as $item) {
2176
                $html .= self::url(
2177
                    $item['title'],
2178
                    $item['href'],
2179
                    [
2180
                        'class' => 'text-gray-700 block px-4 py-2 text-sm',
2181
                        'role' => 'menuitem',
2182
                        'onclick' => $item['onclick'] ?? '',
2183
                        'data-action' => $item['data-action'] ?? '',
2184
                    ]
2185
                );
2186
            }
2187
        $html .= '
2188
            </div>
2189
            </div>
2190
            </div>
2191
            <script>
2192
             document.addEventListener("DOMContentLoaded", function() {
2193
                const button = document.querySelector("#'.$id.'");
2194
                    button.addEventListener("click", (e) => {
2195
                    let menu = document.querySelector("#'.$id.'_menu");
2196
                    if (menu.classList.contains("hidden")) {
2197
                        menu.classList.remove("hidden");
2198
                    } else {
2199
                        menu.classList.add("hidden");
2200
                    }
2201
                });
2202
            });
2203
            </script>';
2204
2205
        return $html;
2206
    }
2207
2208
    /**
2209
     * @param string $file
2210
     * @param array  $params
2211
     *
2212
     * @return string|null
2213
     */
2214
    public static function getMediaPlayer($file, $params = [])
2215
    {
2216
        $fileInfo = pathinfo($file);
2217
2218
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2219
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2220
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2221
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2222
2223
        switch ($fileInfo['extension']) {
2224
            case 'mp3':
2225
            case 'webm':
2226
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2227
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2228
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2229
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2230
                          </object>';
2231
                $html .= '</audio>';
2232
2233
                return $html;
2234
                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...
2235
            case 'wav':
2236
            case 'ogg':
2237
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2238
2239
                return $html;
2240
                break;
2241
        }
2242
2243
        return null;
2244
    }
2245
2246
    /**
2247
     * @param int    $nextValue
2248
     * @param array  $list
2249
     * @param int    $current
2250
     * @param int    $fixedValue
2251
     * @param array  $conditions
2252
     * @param string $link
2253
     * @param bool   $isMedia
2254
     * @param bool   $addHeaders
2255
     * @param array  $linkAttributes
2256
     *
2257
     * @return string
2258
     */
2259
    public static function progressPaginationBar(
2260
        $nextValue,
2261
        $list,
2262
        $current,
2263
        $fixedValue = null,
2264
        $conditions = [],
2265
        $link = null,
2266
        $isMedia = false,
2267
        $addHeaders = true,
2268
        $linkAttributes = []
2269
    ) {
2270
        if ($addHeaders) {
2271
            $pagination_size = 'pagination-mini';
2272
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2273
        } else {
2274
            $html = null;
2275
        }
2276
        $affectAllItems = false;
2277
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2278
            $affectAllItems = true;
2279
        }
2280
        $localCounter = 0;
2281
        foreach ($list as $itemId) {
2282
            $isCurrent = false;
2283
            if ($affectAllItems) {
2284
                $isCurrent = true;
2285
            } else {
2286
                if (!$isMedia) {
2287
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2288
                }
2289
            }
2290
            $html .= self::parsePaginationItem(
2291
                $itemId,
2292
                $isCurrent,
2293
                $conditions,
2294
                $link,
2295
                $nextValue,
2296
                $isMedia,
2297
                $localCounter,
2298
                $fixedValue,
2299
                $linkAttributes
2300
            );
2301
            $localCounter++;
2302
        }
2303
        if ($addHeaders) {
2304
            $html .= '</ul></div>';
2305
        }
2306
2307
        return $html;
2308
    }
2309
2310
    /**
2311
     * @param int    $itemId
2312
     * @param bool   $isCurrent
2313
     * @param array  $conditions
2314
     * @param string $link
2315
     * @param int    $nextValue
2316
     * @param bool   $isMedia
2317
     * @param int    $localCounter
2318
     * @param int    $fixedValue
2319
     * @param array  $linkAttributes
2320
     *
2321
     * @return string
2322
     */
2323
    public static function parsePaginationItem(
2324
        $itemId,
2325
        $isCurrent,
2326
        $conditions,
2327
        $link,
2328
        $nextValue = 0,
2329
        $isMedia = false,
2330
        $localCounter = null,
2331
        $fixedValue = null,
2332
        $linkAttributes = []
2333
    ) {
2334
        $defaultClass = 'before';
2335
        $class = $defaultClass;
2336
        foreach ($conditions as $condition) {
2337
            $array = isset($condition['items']) ? $condition['items'] : [];
2338
            $class_to_applied = $condition['class'];
2339
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2340
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2341
            switch ($type) {
2342
                case 'positive':
2343
                    if (in_array($itemId, $array)) {
2344
                        if ('overwrite' == $mode) {
2345
                            $class = " $defaultClass $class_to_applied";
2346
                        } else {
2347
                            $class .= " $class_to_applied";
2348
                        }
2349
                    }
2350
                    break;
2351
                case 'negative':
2352
                    if (!in_array($itemId, $array)) {
2353
                        if ('overwrite' == $mode) {
2354
                            $class = " $defaultClass $class_to_applied";
2355
                        } else {
2356
                            $class .= " $class_to_applied";
2357
                        }
2358
                    }
2359
                    break;
2360
            }
2361
        }
2362
        if ($isCurrent) {
2363
            $class = 'before current';
2364
        }
2365
        if ($isMedia && $isCurrent) {
2366
            $class = 'before current';
2367
        }
2368
        if (empty($link)) {
2369
            $link_to_show = '#';
2370
        } else {
2371
            $link_to_show = $link.($nextValue + $localCounter);
2372
        }
2373
        $label = $nextValue + $localCounter + 1;
2374
        if ($isMedia) {
2375
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2376
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2377
        }
2378
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2379
2380
        return '<li class = "'.$class.'">'.$link.'</li>';
2381
    }
2382
2383
    /**
2384
     * @param int $current
2385
     * @param int $total
2386
     *
2387
     * @return string
2388
     */
2389
    public static function paginationIndicator($current, $total)
2390
    {
2391
        $html = null;
2392
        if (!empty($current) && !empty($total)) {
2393
            $label = sprintf(get_lang('%s of %s'), $current, $total);
2394
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2395
        }
2396
2397
        return $html;
2398
    }
2399
2400
    /**
2401
     * @param $url
2402
     * @param $currentPage
2403
     * @param $pagesCount
2404
     * @param $totalItems
2405
     *
2406
     * @return string
2407
     */
2408
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2409
    {
2410
        $pagination = '';
2411
        if ($totalItems > 1 && $pagesCount > 1) {
2412
            $pagination .= '<ul class="pagination">';
2413
            for ($i = 0; $i < $pagesCount; $i++) {
2414
                $newPage = $i + 1;
2415
                if ($currentPage == $newPage) {
2416
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2417
                } else {
2418
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2419
                }
2420
            }
2421
            $pagination .= '</ul>';
2422
        }
2423
2424
        return $pagination;
2425
    }
2426
2427
    /**
2428
     * Adds a legacy message in the queue.
2429
     *
2430
     * @param string $message
2431
     */
2432
    public static function addFlash($message)
2433
    {
2434
        // Detect type of message.
2435
        $parts = preg_match('/alert-([a-z]*)/', $message, $matches);
2436
        $type = 'primary';
2437
        if ($parts && isset($matches[1]) && $matches[1]) {
2438
            $type = $matches[1];
2439
        }
2440
        // Detect legacy content of message.
2441
        $result = preg_match('/<div(.*?)\>(.*?)\<\/div>/s', $message, $matches);
2442
        if ($result && isset($matches[2])) {
2443
            Container::getSession()->getFlashBag()->add($type, $matches[2]);
2444
        }
2445
    }
2446
2447
    /**
2448
     * Get the profile edition link for a user.
2449
     *
2450
     * @param int  $userId  The user id
2451
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2452
     *
2453
     * @return string The link
2454
     */
2455
    public static function getProfileEditionLink($userId, $asAdmin = false)
2456
    {
2457
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2458
        if ($asAdmin) {
2459
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2460
        }
2461
2462
        return $editProfileUrl;
2463
    }
2464
2465
    /**
2466
     * Get the vCard for a user.
2467
     *
2468
     * @param int $userId The user id
2469
     *
2470
     * @return string *.*vcf file
2471
     */
2472
    public static function getVCardUserLink($userId)
2473
    {
2474
        return api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2475
    }
2476
2477
    /**
2478
     * @param string $content
2479
     * @param string $title
2480
     * @param string $footer
2481
     * @param string $type        primary|success|info|warning|danger
2482
     * @param string $extra
2483
     * @param string $id
2484
     * @param string $customColor
2485
     * @param string $rightAction
2486
     *
2487
     * @return string
2488
     */
2489
    public static function panel(
2490
        $content,
2491
        $title = '',
2492
        $footer = '',
2493
        $type = 'default',
2494
        $extra = '',
2495
        $id = '',
2496
        $customColor = '',
2497
        $rightAction = ''
2498
    ) {
2499
        $headerStyle = '';
2500
        if (!empty($customColor)) {
2501
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2502
        }
2503
2504
        if (!empty($rightAction)) {
2505
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2506
        }
2507
2508
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2509
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2510
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2511
        $style = !in_array($type, $typeList) ? 'default' : $type;
2512
2513
        if (!empty($id)) {
2514
            $id = " id='$id'";
2515
        }
2516
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2517
2518
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2519
2520
        return '
2521
            <div '.$id.' class="card">
2522
                '.$panel.'
2523
            </div>'
2524
        ;
2525
    }
2526
2527
    /**
2528
     * @param string $content
2529
     */
2530
    public static function contentPanel($content): string
2531
    {
2532
        if (empty($content)) {
2533
            return '';
2534
        }
2535
2536
        return '<div class="card-text">'.$content.'</div>';
2537
    }
2538
2539
    /**
2540
     * Get the button HTML with an Awesome Font icon.
2541
     *
2542
     * @param string $text        The button content
2543
     * @param string $url         The url to button
2544
     * @param string $icon        The Awesome Font class for icon
2545
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2546
     * @param array  $attributes  The additional attributes
2547
     * @param bool   $includeText
2548
     *
2549
     * @return string The button HTML
2550
     */
2551
    public static function toolbarButton(
2552
        $text,
2553
        $url,
2554
        $icon = 'check',
2555
        $type = null,
2556
        array $attributes = [],
2557
        $includeText = true
2558
    ) {
2559
        $buttonClass = "btn btn-outline-secondary";
2560
        if (!empty($type)) {
2561
            $buttonClass = "btn btn-$type";
2562
        }
2563
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2564
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2565
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2566
2567
        if (!$includeText) {
2568
            $text = '<span class="sr-only">'.$text.'</span>';
2569
        }
2570
2571
        return self::url("$icon $text", $url, $attributes);
2572
    }
2573
2574
    public static function toolbarAction(string $id, array $contentList): string
2575
    {
2576
        $contentList = array_filter($contentList);
2577
2578
        if (empty($contentList)) {
2579
            return '';
2580
        }
2581
2582
        $col = count($contentList);
2583
        $html = ' <div id="'.$id.'" class="q-card p-2 mb-4">';
2584
        $html .= ' <div class="flex justify-between '.$col.'">';
2585
        foreach ($contentList as $item) {
2586
            $html .= '<div class="flex p-2 gap-2 ">'.$item.'</div>';
2587
        }
2588
        $html .= '</div>';
2589
        $html .= '</div>';
2590
2591
        return $html;
2592
    }
2593
2594
    /**
2595
     * Get a HTML code for a icon by Font Awesome.
2596
     *
2597
     * @param string     $name            The icon name. Example: "mail-reply"
2598
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2599
     * @param bool       $fixWidth        Optional. Whether add the fw class
2600
     * @param string     $additionalClass Optional. Additional class
2601
     *
2602
     * @return string
2603
     */
2604
    public static function returnFontAwesomeIcon(
2605
        $name,
2606
        $size = '',
2607
        $fixWidth = false,
2608
        $additionalClass = ''
2609
    ) {
2610
        $className = "fa fa-$name";
2611
2612
        if ($fixWidth) {
2613
            $className .= ' fa-fw';
2614
        }
2615
2616
        switch ($size) {
2617
            case 'xs':
2618
            case 'sm':
2619
            case 'lg':
2620
                $className .= " fa-{$size}";
2621
                break;
2622
            case 2:
2623
            case 3:
2624
            case 4:
2625
            case 5:
2626
                $className .= " fa-{$size}x";
2627
                break;
2628
        }
2629
2630
        if (!empty($additionalClass)) {
2631
            $className .= " $additionalClass";
2632
        }
2633
2634
        $icon = self::tag('em', null, ['class' => $className]);
2635
2636
        return "$icon ";
2637
    }
2638
2639
    /**
2640
     * @param string     $title
2641
     * @param string     $content
2642
     * @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...
2643
     * @param array      $params
2644
     * @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...
2645
     * @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...
2646
     * @param bool|true  $open
2647
     * @param bool|false $fullClickable
2648
     *
2649
     * @return string
2650
     *
2651
     * @todo rework function to easy use
2652
     */
2653
    public static function panelCollapse(
2654
        $title,
2655
        $content,
2656
        $id = null,
2657
        $params = [],
2658
        $idAccordion = null,
2659
        $idCollapse = null,
2660
        $open = true,
2661
        $fullClickable = false
2662
    ) {
2663
        if (!empty($idAccordion)) {
2664
            $headerClass = '';
2665
            $headerClass .= $fullClickable ? 'center-block ' : '';
2666
            $headerClass .= $open ? '' : 'collapsed';
2667
            $contentClass = 'panel-collapse collapse ';
2668
            $contentClass .= $open ? 'in' : '';
2669
            $ariaExpanded = $open ? 'true' : 'false';
2670
2671
            $html = <<<HTML
2672
                <div class="card" id="$id">
2673
                    <div class="card-header">
2674
                        $title
2675
                    </div>
2676
                    <div class="card-body">$content</div>
2677
                </div>
2678
HTML;
2679
        } else {
2680
            if (!empty($id)) {
2681
                $params['id'] = $id;
2682
            }
2683
            $params['class'] = 'card';
2684
            $html = '';
2685
            if (!empty($title)) {
2686
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2687
            }
2688
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2689
            $html = self::div($html, $params);
2690
        }
2691
2692
        return $html;
2693
    }
2694
2695
    /**
2696
     * Returns the string "1 day ago" with a link showing the exact date time.
2697
     *
2698
     * @param string $dateTime in UTC or a DateTime in UTC
2699
     *
2700
     * @return string
2701
     */
2702
    public static function dateToStringAgoAndLongDate($dateTime)
2703
    {
2704
        if (empty($dateTime) || '0000-00-00 00:00:00' === $dateTime) {
2705
            return '';
2706
        }
2707
2708
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2709
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2710
        }
2711
2712
        return self::tip(
2713
            date_to_str_ago($dateTime),
2714
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2715
            //api_get_local_time($dateTime)
2716
        );
2717
    }
2718
2719
    /**
2720
     * @param array  $userInfo
2721
     * @param string $status
2722
     * @param string $toolbar
2723
     *
2724
     * @return string
2725
     */
2726
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2727
    {
2728
        if (empty($userInfo)) {
2729
            return '';
2730
        }
2731
2732
        if (!empty($status)) {
2733
            $status = '<div class="items-user-status">'.$status.'</div>';
2734
        }
2735
2736
        if (!empty($toolbar)) {
2737
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2738
        }
2739
2740
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">
2741
                    <img src="'.$userInfo['avatar'].'" class="rounded" />
2742
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>
2743
                    <div class="card-body">
2744
                       <div class="card-title">
2745
                       '.$status.'
2746
                       '.$toolbar.'
2747
                       </div>
2748
                    </div>
2749
                    <hr />
2750
              </div>';
2751
    }
2752
2753
    /**
2754
     * @param string $fileName
2755
     * @param string $fileUrl
2756
     *
2757
     * @return string
2758
     */
2759
    public static function fileHtmlGuesser($fileName, $fileUrl)
2760
    {
2761
        $data = pathinfo($fileName);
2762
2763
        //$content = self::url($data['basename'], $fileUrl);
2764
        $content = '';
2765
        switch ($data['extension']) {
2766
            case 'webm':
2767
            case 'mp4':
2768
            case 'ogg':
2769
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2770
                // Allows video to play when loading during an ajax call
2771
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2772
                break;
2773
            case 'jpg':
2774
            case 'jpeg':
2775
            case 'gif':
2776
            case 'png':
2777
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2778
                break;
2779
            default:
2780
                //$html = self::url($data['basename'], $fileUrl);
2781
                break;
2782
        }
2783
        //$html = self::url($content, $fileUrl, ['ajax']);
2784
2785
        return $content;
2786
    }
2787
2788
    /**
2789
     * @param string $frameName
2790
     *
2791
     * @return string
2792
     */
2793
    public static function getFrameReadyBlock($frameName)
2794
    {
2795
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2796
        $videoFeatures = [
2797
            'playpause',
2798
            'current',
2799
            'progress',
2800
            'duration',
2801
            'tracks',
2802
            'volume',
2803
            'fullscreen',
2804
            'vrview',
2805
            'markersrolls',
2806
        ];
2807
        $features = api_get_configuration_value('video_features');
2808
        $videoPluginsJS = [];
2809
        $videoPluginCSS = [];
2810
        if (!empty($features) && isset($features['features'])) {
2811
            foreach ($features['features'] as $feature) {
2812
                if ('vrview' === $feature) {
2813
                    continue;
2814
                }
2815
                $defaultFeatures[] = $feature;
2816
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.js";
2817
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.css";
2818
            }
2819
        }
2820
2821
        $videoPluginFiles = '';
2822
        foreach ($videoPluginsJS as $file) {
2823
            $videoPluginFiles .= '{type: "script", src: "'.$webPublicPath.'assets/'.$file.'"},';
2824
        }
2825
2826
        $videoPluginCssFiles = '';
2827
        foreach ($videoPluginCSS as $file) {
2828
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webPublicPath.'assets/'.$file.'"},';
2829
        }
2830
2831
        $translateHtml = '';
2832
        $translate = api_get_configuration_value('translate_html');
2833
        if ($translate) {
2834
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2835
        }
2836
2837
        $lpJs = api_get_path(WEB_PUBLIC_PATH).'build/lp.js';
2838
        // {type:"script", src:"'.api_get_jquery_ui_js_web_path().'"},
2839
        // {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/markersrolls/markersrolls.js"},
2840
        // {type:"script", src:"'.$webPublicPath.'build/libs/mathjax/MathJax.js?config=AM_HTMLorMML"},
2841
        $videoFeatures = implode("','", $videoFeatures);
2842
        $frameReady = '
2843
        $.frameReady(function() {
2844
             $(function () {
2845
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2846
                    pluginPath: "'.$webPublicPath.'assets/mediaelement/plugins/",
2847
                    features: [\''.$videoFeatures.'\'],
2848
                    success: function(mediaElement, originalNode, instance) {
2849
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2850
                    },
2851
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2852
                });
2853
            });
2854
        },
2855
        "'.$frameName.'",
2856
        [
2857
            {type:"script", src:"'.$lpJs.'", deps: [
2858
2859
            {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2860
2861
            {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/mediaelement-and-player.min.js",
2862
                deps: [
2863
                {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/vrview/vrview.js"},
2864
                '.$videoPluginFiles.'
2865
            ]},
2866
            '.$translateHtml.'
2867
            ]},
2868
            '.$videoPluginCssFiles.'
2869
        ]);';
2870
2871
        return $frameReady;
2872
    }
2873
2874
    /**
2875
     * @param string $image
2876
     * @param int    $size
2877
     *
2878
     * @return string
2879
     */
2880
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2881
    {
2882
        return self::return_icon($image, '', [], $size, false, true);
2883
    }
2884
2885
    /**
2886
     * @param string $image
2887
     * @param int    $size
2888
     * @param string $name
2889
     *
2890
     * @return string
2891
     */
2892
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
2893
    {
2894
        return self::return_icon($image, $name, [], $size);
2895
    }
2896
2897
    /**
2898
     * @param $id
2899
     *
2900
     * @return array|mixed
2901
     */
2902
    public static function randomColor($id)
2903
    {
2904
        static $colors = [];
2905
2906
        if (!empty($colors[$id])) {
2907
            return $colors[$id];
2908
        } else {
2909
            $color = substr(md5(time() * $id), 0, 6);
2910
            $c1 = hexdec(substr($color, 0, 2));
2911
            $c2 = hexdec(substr($color, 2, 2));
2912
            $c3 = hexdec(substr($color, 4, 2));
2913
            $luminosity = $c1 + $c2 + $c3;
2914
2915
            $type = '#000000';
2916
            if ($luminosity < (255 + 255 + 255) / 2) {
2917
                $type = '#FFFFFF';
2918
            }
2919
2920
            $result = [
2921
                'color' => '#'.$color,
2922
                'luminosity' => $type,
2923
            ];
2924
            $colors[$id] = $result;
2925
2926
            return $result; // example: #fc443a
2927
        }
2928
    }
2929
2930
    public static function noDataView(string $title, string $icon, string $buttonTitle, string $url): string
2931
    {
2932
        $content = '<div id="no-data-view">';
2933
        $content .= '<h3>'.$title.'</h3>';
2934
        $content .= $icon;
2935
        $content .= '<div class="controls">';
2936
        $content .= self::url(
2937
            '<em class="fa fa-plus"></em> '.$buttonTitle,
2938
            $url,
2939
            ['class' => 'btn btn-primary']
2940
        );
2941
        $content .= '</div>';
2942
        $content .= '</div>';
2943
2944
        return $content;
2945
    }
2946
}
2947