Passed
Pull Request — 1.11.x (#4275)
by Angel Fernando Quiroz
09:33
created

Display::paginationIndicator()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 2
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
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 ChamiloSession as Session;
8
9
/**
10
 * Class Display
11
 * Contains several public functions dealing with the display of
12
 * table data, messages, help topics, ...
13
 *
14
 * Include/require it in your code to use its public functionality.
15
 * There are also several display public functions in the main api library.
16
 *
17
 * All public functions static public functions inside a class called Display,
18
 * so you use them like this: e.g.
19
 * Display::return_message($message)
20
 *
21
 * @package chamilo.library
22
 */
23
class Display
24
{
25
    /** @var Template */
26
    public static $global_template;
27
    public static $preview_style = null;
28
29
    /**
30
     * Constructor.
31
     */
32
    public function __construct()
33
    {
34
    }
35
36
    /**
37
     * @return array
38
     */
39
    public static function toolList()
40
    {
41
        return [
42
            'group',
43
            'work',
44
            'glossary',
45
            'forum',
46
            'course_description',
47
            'gradebook',
48
            'attendance',
49
            'course_progress',
50
            'notebook',
51
        ];
52
    }
53
54
    /**
55
     * Displays the page header.
56
     *
57
     * @param string The name of the page (will be showed in the page title)
58
     * @param string Optional help file name
59
     * @param string $page_header
60
     */
61
    public static function display_header(
62
        $tool_name = '',
63
        $help = null,
64
        $page_header = null
65
    ) {
66
        $origin = api_get_origin();
67
        $showHeader = true;
68
        if (isset($origin) && ($origin == 'learnpath' || $origin == 'mobileapp')) {
69
            $showHeader = false;
70
        }
71
72
        if (Session::read('origin') == 'mobileapp') {
73
            $showHeader = false;
74
        }
75
76
        /* USER_IN_ANON_SURVEY is defined in fillsurvey.php when survey is marked as anonymous survey */
77
        $userInAnonSurvey = defined('USER_IN_ANON_SURVEY') && USER_IN_ANON_SURVEY;
78
79
        self::$global_template = new Template($tool_name, $showHeader, $showHeader, false, $userInAnonSurvey);
80
        self::$global_template->assign('user_in_anon_survey', $userInAnonSurvey);
81
82
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
83
        if (empty($help)) {
84
            $currentURL = api_get_self();
85
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
86
            $toolList = self::toolList();
87
            if (!empty($matches)) {
88
                foreach ($matches as $match) {
89
                    if (in_array($match, $toolList)) {
90
                        $help = explode('_', $match);
91
                        $help = array_map('ucfirst', $help);
92
                        $help = implode('', $help);
93
                        break;
94
                    }
95
                }
96
            }
97
        }
98
99
        self::$global_template->setHelp($help);
100
101
        if (!empty(self::$preview_style)) {
102
            self::$global_template->preview_theme = self::$preview_style;
103
            self::$global_template->set_system_parameters();
104
            self::$global_template->setCssFiles();
105
            self::$global_template->set_js_files();
106
            self::$global_template->setCssCustomFiles();
107
        }
108
109
        if (!empty($page_header)) {
110
            self::$global_template->assign('header', $page_header);
111
        }
112
113
        echo self::$global_template->show_header_template();
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::global_template->show_header_template() targeting Template::show_header_template() 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...
114
    }
115
116
    /**
117
     * Displays the reduced page header (without banner).
118
     */
119
    public static function display_reduced_header()
120
    {
121
        global $show_learnpath, $tool_name;
122
        self::$global_template = new Template(
123
            $tool_name,
124
            false,
125
            false,
126
            $show_learnpath
127
        );
128
        echo self::$global_template->show_header_template();
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::global_template->show_header_template() targeting Template::show_header_template() 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...
129
    }
130
131
    /**
132
     * Display no header.
133
     */
134
    public static function display_no_header()
135
    {
136
        global $tool_name, $show_learnpath;
137
        $disable_js_and_css_files = true;
138
        self::$global_template = new Template(
139
            $tool_name,
140
            false,
141
            false,
142
            $show_learnpath
143
        );
144
    }
145
146
    /**
147
     * Displays the reduced page header (without banner).
148
     */
149
    public static function set_header()
150
    {
151
        global $show_learnpath, $tool_name;
152
        self::$global_template = new Template(
153
            $tool_name,
154
            false,
155
            false,
156
            $show_learnpath
157
        );
158
    }
159
160
    /**
161
     * Display the page footer.
162
     */
163
    public static function display_footer()
164
    {
165
        echo self::$global_template->show_footer_template();
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::global_template->show_footer_template() targeting Template::show_footer_template() 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...
166
    }
167
168
    /**
169
     * Display the page footer.
170
     */
171
    public static function display_reduced_footer()
172
    {
173
        echo '</body></html>';
174
    }
175
176
    /**
177
     * Displays the tool introduction of a tool.
178
     *
179
     * @author Patrick Cool <[email protected]>, Ghent University
180
     *
181
     * @param string $tool          these are the constants that are used for indicating the tools
182
     * @param array  $editor_config Optional configuration settings for the online editor.
183
     *                              return: $tool return a string array list with the "define" in main_api.lib
184
     *
185
     * @return string html code for adding an introduction
186
     */
187
    public static function display_introduction_section(
188
        $tool,
189
        $editor_config = null
190
    ) {
191
        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...
192
    }
193
194
    /**
195
     * @param string $tool
196
     * @param array  $editor_config
197
     */
198
    public static function return_introduction_section(
199
        $tool,
200
        $editor_config = null
201
    ) {
202
        $moduleId = $tool;
203
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
204
            $introduction_section = null;
205
            require api_get_path(SYS_INC_PATH).'introductionSection.inc.php';
206
207
            return $introduction_section;
208
        }
209
    }
210
211
    /**
212
     * Displays a table.
213
     *
214
     * @param array  $header          Titles for the table header
215
     *                                each item in this array can contain 3 values
216
     *                                - 1st element: the column title
217
     *                                - 2nd element: true or false (column sortable?)
218
     *                                - 3th element: additional attributes for
219
     *                                th-tag (eg for column-width)
220
     *                                - 4the element: additional attributes for the td-tags
221
     * @param array  $content         2D-array with the tables content
222
     * @param array  $sorting_options Keys are:
223
     *                                'column' = The column to use as sort-key
224
     *                                'direction' = SORT_ASC or SORT_DESC
225
     * @param array  $paging_options  Keys are:
226
     *                                'per_page_default' = items per page when switching from
227
     *                                full-    list to per-page-view
228
     *                                'per_page' = number of items to show per page
229
     *                                'page_nr' = The page to display
230
     * @param array  $query_vars      Additional variables to add in the query-string
231
     * @param array  $form_actions
232
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
233
     * @param string $tableName
234
     * @param string $tableId
235
     *
236
     * @author [email protected]
237
     */
238
    public static function display_sortable_table(
239
        $header,
240
        $content,
241
        $sorting_options = [],
242
        $paging_options = [],
243
        $query_vars = null,
244
        $form_actions = [],
245
        $style = 'table',
246
        $tableName = 'tablename',
247
        $tableId = ''
248
    ) {
249
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
250
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
251
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
252
        if (is_array($query_vars)) {
253
            $table->set_additional_parameters($query_vars);
254
        }
255
        if ($style === 'table') {
256
            if (is_array($header) && count($header) > 0) {
257
                foreach ($header as $index => $header_item) {
258
                    $table->set_header(
259
                        $index,
260
                        isset($header_item[0]) ? $header_item[0] : null,
261
                        isset($header_item[1]) ? $header_item[1] : null,
262
                        isset($header_item[2]) ? $header_item[2] : null,
263
                        isset($header_item[3]) ? $header_item[3] : null
264
                    );
265
                }
266
            }
267
            $table->set_form_actions($form_actions);
268
            $table->display();
269
        } else {
270
            $table->display_grid();
271
        }
272
    }
273
274
    /**
275
     * Returns an HTML table with sortable column (through complete page refresh).
276
     *
277
     * @param array  $header
278
     * @param array  $content         Array of row arrays
279
     * @param array  $sorting_options
280
     * @param array  $paging_options
281
     * @param array  $query_vars
282
     * @param array  $form_actions
283
     * @param string $style
284
     *
285
     * @return string HTML string for array
286
     */
287
    public static function return_sortable_table(
288
        $header,
289
        $content,
290
        $sorting_options = [],
291
        $paging_options = [],
292
        $query_vars = null,
293
        $form_actions = [],
294
        $style = 'table'
295
    ) {
296
        ob_start();
297
        self::display_sortable_table(
298
            $header,
299
            $content,
300
            $sorting_options,
301
            $paging_options,
302
            $query_vars,
303
            $form_actions,
304
            $style
305
        );
306
        $content = ob_get_contents();
307
        ob_end_clean();
308
309
        return $content;
310
    }
311
312
    /**
313
     * Shows a nice grid.
314
     *
315
     * @param string grid name (important to create css)
316
     * @param array header content
317
     * @param array array with the information to show
318
     * @param array $paging_options Keys are:
319
     *                              'per_page_default' = items per page when switching from
320
     *                              full-    list to per-page-view
321
     *                              'per_page' = number of items to show per page
322
     *                              'page_nr' = The page to display
323
     *                              'hide_navigation' =  true to hide the navigation
324
     * @param array $query_vars     Additional variables to add in the query-string
325
     * @param array $form_actions   actions Additional variables to add in the query-string
326
     * @param mixed An array with bool values to know which columns show.
327
     * i.e: $visibility_options= array(true, false) we will only show the first column
328
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
329
     */
330
    public static function display_sortable_grid(
331
        $name,
332
        $header,
333
        $content,
334
        $paging_options = [],
335
        $query_vars = null,
336
        $form_actions = [],
337
        $visibility_options = true,
338
        $sort_data = true,
339
        $grid_class = []
340
    ) {
341
        echo self::return_sortable_grid(
342
            $name,
343
            $header,
344
            $content,
345
            $paging_options,
346
            $query_vars,
347
            $form_actions,
348
            $visibility_options,
349
            $sort_data,
350
            $grid_class
351
        );
352
    }
353
354
    /**
355
     * Gets a nice grid in html string.
356
     *
357
     * @param string grid name (important to create css)
358
     * @param array header content
359
     * @param array array with the information to show
360
     * @param array $paging_options Keys are:
361
     *                              'per_page_default' = items per page when switching from
362
     *                              full-    list to per-page-view
363
     *                              'per_page' = number of items to show per page
364
     *                              'page_nr' = The page to display
365
     *                              'hide_navigation' =  true to hide the navigation
366
     * @param array $query_vars     Additional variables to add in the query-string
367
     * @param mixed An array with bool values to know which columns show. i.e:
368
     *  $visibility_options= array(true, false) we will only show the first column
369
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
370
     * @param bool  true for sorting data or false otherwise
371
     * @param array grid classes
372
     *
373
     * @return string html grid
374
     */
375
    public static function return_sortable_grid(
376
        $name,
377
        $header,
378
        $content,
379
        $paging_options = [],
380
        $query_vars = null,
381
        $form_actions = [],
382
        $visibility_options = true,
383
        $sort_data = true,
384
        $grid_class = [],
385
        $elementCount = 0
386
    ) {
387
        $column = 0;
388
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
389
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
390
        $table->total_number_of_items = intval($elementCount);
391
        if (is_array($query_vars)) {
392
            $table->set_additional_parameters($query_vars);
393
        }
394
395
        return $table->display_simple_grid(
396
            $visibility_options,
397
            $paging_options['hide_navigation'],
398
            $default_items_per_page,
399
            $sort_data,
400
            $grid_class
401
        );
402
    }
403
404
    /**
405
     * Displays a table with a special configuration.
406
     *
407
     * @param array $header          Titles for the table header
408
     *                               each item in this array can contain 3 values
409
     *                               - 1st element: the column title
410
     *                               - 2nd element: true or false (column sortable?)
411
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
412
     *                               - 4the element: additional attributes for the td-tags
413
     * @param array $content         2D-array with the tables content
414
     * @param array $sorting_options Keys are:
415
     *                               'column' = The column to use as sort-key
416
     *                               'direction' = SORT_ASC or SORT_DESC
417
     * @param array $paging_options  Keys are:
418
     *                               'per_page_default' = items per page when switching from full list to per-page-view
419
     *                               'per_page' = number of items to show per page
420
     *                               'page_nr' = The page to display
421
     * @param array $query_vars      Additional variables to add in the query-string
422
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
423
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
424
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
425
     * @param array $form_actions    Set optional forms actions
426
     *
427
     * @author Julio Montoya
428
     */
429
    public static function display_sortable_config_table(
430
        $table_name,
431
        $header,
432
        $content,
433
        $sorting_options = [],
434
        $paging_options = [],
435
        $query_vars = null,
436
        $column_show = [],
437
        $column_order = [],
438
        $form_actions = []
439
    ) {
440
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
441
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
442
443
        $table = new SortableTableFromArrayConfig(
444
            $content,
445
            $column,
446
            $default_items_per_page,
447
            $table_name,
448
            $column_show,
449
            $column_order
450
        );
451
452
        if (is_array($query_vars)) {
453
            $table->set_additional_parameters($query_vars);
454
        }
455
        // Show or hide the columns header
456
        if (is_array($column_show)) {
457
            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...
458
                if (!empty($column_show[$i])) {
459
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
460
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
461
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
462
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
463
                    $table->set_header($i, $val0, $val1, $val2, $val3);
464
                }
465
            }
466
        }
467
        $table->set_form_actions($form_actions);
468
        $table->display();
469
    }
470
471
    /**
472
     * @param string $message
473
     * @param string $type
474
     * @param bool   $filter
475
     */
476
    public static function return_message_and_translate(
477
        $message,
478
        $type = 'normal',
479
        $filter = true
480
    ) {
481
        $message = get_lang($message);
482
        echo self::return_message($message, $type, $filter);
483
    }
484
485
    /**
486
     * Returns a div html string with.
487
     *
488
     * @param string $message
489
     * @param string $type    Example: confirm, normal, warning, error
490
     * @param bool   $filter  Whether to XSS-filter or not
491
     *
492
     * @return string Message wrapped into an HTML div
493
     */
494
    public static function return_message(
495
        $message,
496
        $type = 'normal',
497
        $filter = true
498
    ) {
499
        if (empty($message)) {
500
            return '';
501
        }
502
503
        if ($filter) {
504
            $message = api_htmlentities(
505
                $message,
506
                ENT_QUOTES,
507
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
508
            );
509
        }
510
511
        $class = '';
512
        switch ($type) {
513
            case 'warning':
514
                $class .= 'alert alert-warning';
515
                break;
516
            case 'error':
517
                $class .= 'alert alert-danger';
518
                break;
519
            case 'confirmation':
520
            case 'confirm':
521
            case 'success':
522
                $class .= 'alert alert-success';
523
                break;
524
            case 'normal':
525
            default:
526
                $class .= 'alert alert-info';
527
        }
528
529
        return self::div($message, ['class' => $class]);
530
    }
531
532
    /**
533
     * Returns an encrypted mailto hyperlink.
534
     *
535
     * @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...
536
     * @param string  clickable text
537
     * @param string  optional, class from stylesheet
538
     * @param bool $addExtraContent
539
     *
540
     * @return string encrypted mailto hyperlink
541
     */
542
    public static function encrypted_mailto_link(
543
        $email,
544
        $clickable_text = null,
545
        $style_class = '',
546
        $addExtraContent = false
547
    ) {
548
        if (is_null($clickable_text)) {
549
            $clickable_text = $email;
550
        }
551
552
        // "mailto:" already present?
553
        if (substr($email, 0, 7) !== 'mailto:') {
554
            $email = 'mailto:'.$email;
555
        }
556
557
        // Class (stylesheet) defined?
558
        if ($style_class !== '') {
559
            $style_class = ' class="'.$style_class.'"';
560
        }
561
562
        // Encrypt email
563
        $hmail = '';
564
        for ($i = 0; $i < strlen($email); $i++) {
565
            $hmail .= '&#'.ord($email[$i]).';';
566
        }
567
568
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
569
570
        if ($value) {
571
            if (api_get_setting('allow_email_editor') === 'false') {
572
                $hmail .= '?';
573
            }
574
575
            if (!api_is_anonymous()) {
576
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
577
            }
578
            if ($addExtraContent) {
579
                $content = '';
580
                if (!api_is_anonymous()) {
581
                    $userInfo = api_get_user_info();
582
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
583
584
                    $courseInfo = api_get_course_info();
585
                    if (!empty($courseInfo)) {
586
                        $content .= get_lang('Course').': ';
587
                        $content .= $courseInfo['name'];
588
                        $sessionInfo = api_get_session_info(api_get_session_id());
589
                        if (!empty($sessionInfo)) {
590
                            $content .= ' '.$sessionInfo['name'].' <br />';
591
                        }
592
                    }
593
                }
594
595
                if (!empty($content)) {
596
                    $hmail .= '&body='.rawurlencode($content);
597
                }
598
            }
599
        }
600
601
        $hclickable_text = '';
602
        // Encrypt clickable text if @ is present
603
        if (strpos($clickable_text, '@')) {
604
            for ($i = 0; $i < strlen($clickable_text); $i++) {
605
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
606
            }
607
        } else {
608
            $hclickable_text = @htmlspecialchars(
609
                $clickable_text,
610
                ENT_QUOTES,
611
                api_get_system_encoding()
612
            );
613
        }
614
        // Return encrypted mailto hyperlink
615
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
616
    }
617
618
    /**
619
     * Returns an mailto icon hyperlink.
620
     *
621
     * @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...
622
     * @param string  icon source file from the icon lib
623
     * @param int  icon size from icon lib
624
     * @param string  optional, class from stylesheet
625
     *
626
     * @return string encrypted mailto hyperlink
627
     */
628
    public static function icon_mailto_link(
629
        $email,
630
        $icon_file = "mail.png",
631
        $icon_size = 22,
632
        $style_class = ''
633
    ) {
634
        // "mailto:" already present?
635
        if (substr($email, 0, 7) != 'mailto:') {
636
            $email = 'mailto:'.$email;
637
        }
638
        // Class (stylesheet) defined?
639
        if ($style_class != '') {
640
            $style_class = ' class="'.$style_class.'"';
641
        }
642
        // Encrypt email
643
        $hmail = '';
644
        for ($i = 0; $i < strlen($email); $i++) {
645
            $hmail .= '&#'.ord($email[
646
            $i]).';';
647
        }
648
        // icon html code
649
        $icon_html_source = self::return_icon(
650
            $icon_file,
651
            $hmail,
652
            '',
653
            $icon_size
654
        );
655
        // Return encrypted mailto hyperlink
656
657
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
658
    }
659
660
    /**
661
     * Prints an <option>-list with all letters (A-Z).
662
     *
663
     * @todo This is English language specific implementation.
664
     * It should be adapted for the other languages.
665
     *
666
     * @return string
667
     */
668
    public static function get_alphabet_options($selectedLetter = '')
669
    {
670
        $result = '';
671
        for ($i = 65; $i <= 90; $i++) {
672
            $letter = chr($i);
673
            $result .= '<option value="'.$letter.'"';
674
            if ($selectedLetter == $letter) {
675
                $result .= ' selected="selected"';
676
            }
677
            $result .= '>'.$letter.'</option>';
678
        }
679
680
        return $result;
681
    }
682
683
    /**
684
     * Get the options withing a select box within the given values.
685
     *
686
     * @param int   Min value
687
     * @param int   Max value
688
     * @param int   Default value
689
     *
690
     * @return string HTML select options
691
     */
692
    public static function get_numeric_options($min, $max, $selected_num = 0)
693
    {
694
        $result = '';
695
        for ($i = $min; $i <= $max; $i++) {
696
            $result .= '<option value="'.$i.'"';
697
            if (is_int($selected_num)) {
698
                if ($selected_num == $i) {
699
                    $result .= ' selected="selected"';
700
                }
701
            }
702
            $result .= '>'.$i.'</option>';
703
        }
704
705
        return $result;
706
    }
707
708
    /**
709
     * This public function displays an icon.
710
     *
711
     * @param string   The filename of the file (in the main/img/ folder
712
     * @param string   The alt text (probably a language variable)
713
     * @param array    additional attributes (for instance height, width, onclick, ...)
714
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
715
     */
716
    public static function display_icon(
717
        $image,
718
        $alt_text = '',
719
        $additional_attributes = [],
720
        $size = null
721
    ) {
722
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
723
    }
724
725
    /**
726
     * Gets the path of an icon.
727
     *
728
     * @param string $icon
729
     * @param int    $size
730
     *
731
     * @return string
732
     */
733
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
734
    {
735
        return self::return_icon($icon, null, null, $size, null, true, false);
736
    }
737
738
    /**
739
     * This public function returns the HTML code for an icon.
740
     *
741
     * @param string $image                 The filename of the file (in the main/img/ folder
742
     * @param string $alt_text              The alt text (probably a language variable)
743
     * @param array  $additional_attributes Additional attributes (for instance height, width, onclick, ...)
744
     * @param int    $size                  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
745
     * @param bool   $show_text             Whether to show the text next (usually under) the icon
746
     * @param bool   $return_only_path      Whether we only want the path to the icon or the whole HTML tag
747
     * @param bool   $loadThemeIcon         Whether we want to allow an overloaded theme icon, if it exists, to replace the default icon
748
     *
749
     * @return string An HTML string of the right <img> tag
750
     *
751
     * @author Patrick Cool <[email protected]>, Ghent University 2006
752
     * @author Julio Montoya 2010 Function improved, adding image constants
753
     * @author Yannick Warnier 2011 Added size handler
754
     *
755
     * @version Feb 2011
756
     */
757
    public static function return_icon(
758
        $image,
759
        $alt_text = '',
760
        $additional_attributes = [],
761
        $size = ICON_SIZE_SMALL,
762
        $show_text = true,
763
        $return_only_path = false,
764
        $loadThemeIcon = true
765
    ) {
766
        $code_path = api_get_path(SYS_CODE_PATH);
767
        $w_code_path = api_get_path(WEB_CODE_PATH);
768
        // The following path is checked to see if the file exist. It's
769
        // important to use the public path (i.e. web/css/) rather than the
770
        // internal path (/app/Resource/public/css/) because the path used
771
        // in the end must be the public path
772
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
773
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
774
775
        // Avoid issues with illegal string offset for legacy calls to this
776
        // method with an empty string rather than null or an empty array
777
        if (empty($additional_attributes)) {
778
            $additional_attributes = [];
779
        }
780
781
        $image = trim($image);
782
783
        if (isset($size)) {
784
            $size = intval($size);
785
        } else {
786
            $size = ICON_SIZE_SMALL;
787
        }
788
789
        $size_extra = $size.'/';
790
        $icon = $w_code_path.'img/'.$image;
791
        $theme = 'themes/chamilo/icons/';
792
793
        if ($loadThemeIcon) {
794
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
795
            if (is_file($alternateCssPath.$theme.$image)) {
796
                $icon = $alternateWebCssPath.$theme.$image;
797
            }
798
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
799
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
800
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
801
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
802
                //Checking the main/img/icons/XXX/ folder
803
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
804
            }
805
        } else {
806
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
807
                // Checking the main/img/icons/XXX/ folder
808
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
809
            }
810
        }
811
812
        // Special code to enable SVG - refs #7359 - Needs more work
813
        // The code below does something else to "test out" SVG: for each icon,
814
        // it checks if there is an SVG version. If so, it uses it.
815
        // When moving this to production, the return_icon() calls should
816
        // ask for the SVG version directly
817
        $svgIcons = api_get_setting('icons_mode_svg');
818
        if ($svgIcons === 'true' && $return_only_path == false) {
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...
819
            $svgImage = substr($image, 0, -3).'svg';
820
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
821
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
822
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
823
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
824
            }
825
826
            if (empty($additional_attributes['height'])) {
827
                $additional_attributes['height'] = $size;
828
            }
829
            if (empty($additional_attributes['width'])) {
830
                $additional_attributes['width'] = $size;
831
            }
832
        }
833
834
        $icon = api_get_cdn_path($icon);
835
836
        if ($return_only_path) {
837
            return $icon;
838
        }
839
840
        $img = self::img($icon, $alt_text, $additional_attributes);
841
        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...
842
            if ($show_text) {
843
                $img = "$img $alt_text";
844
            }
845
        }
846
847
        return $img;
848
    }
849
850
    /**
851
     * Returns the HTML code for an image.
852
     *
853
     * @param string $image_path            the filename of the file (in the main/img/ folder
854
     * @param string $alt_text              the alt text (probably a language variable)
855
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
856
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
857
     *
858
     * @return string
859
     *
860
     * @author Julio Montoya 2010
861
     */
862
    public static function img(
863
        $image_path,
864
        $alt_text = '',
865
        $additional_attributes = null,
866
        $filterPath = true
867
    ) {
868
        if (empty($image_path)) {
869
            // For some reason, the call to img() happened without a proper
870
            // image. Log the error and return an empty string to avoid
871
            // breaking the HTML
872
            $trace = debug_backtrace();
873
            $caller = $trace[1];
874
            error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
0 ignored issues
show
Bug introduced by
Are you sure print_r($caller, 1) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

874
            error_log('No image provided in Display::img(). Caller info: './** @scrutinizer ignore-type */ print_r($caller, 1));
Loading history...
875
876
            return '';
877
        }
878
        // Sanitizing the parameter $image_path
879
        if ($filterPath) {
880
            $image_path = Security::filter_img_path($image_path);
881
        }
882
883
        // alt text = the image name if there is none provided (for XHTML compliance)
884
        if ($alt_text == '') {
885
            $alt_text = basename($image_path);
886
        }
887
888
        if (empty($additional_attributes)) {
889
            $additional_attributes = [];
890
        }
891
892
        $additional_attributes['src'] = $image_path;
893
894
        if (empty($additional_attributes['alt'])) {
895
            $additional_attributes['alt'] = $alt_text;
896
        }
897
        if (empty($additional_attributes['title'])) {
898
            $additional_attributes['title'] = $alt_text;
899
        }
900
901
        return self::tag('img', '', $additional_attributes);
902
    }
903
904
    /**
905
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
906
     *
907
     * @param string $tag                   the tag name
908
     * @param string $content               the tag's content
909
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
910
     *
911
     * @return string
912
     *
913
     * @author Julio Montoya 2010
914
     */
915
    public static function tag($tag, $content, $additional_attributes = [])
916
    {
917
        $attribute_list = '';
918
        // Managing the additional attributes
919
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
920
            $attribute_list = '';
921
            foreach ($additional_attributes as $key => &$value) {
922
                $attribute_list .= $key.'="'.$value.'" ';
923
            }
924
        }
925
        //some tags don't have this </XXX>
926
        if (in_array($tag, ['img', 'input', 'br'])) {
927
            $return_value = '<'.$tag.' '.$attribute_list.' />';
928
        } else {
929
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
930
        }
931
932
        return $return_value;
933
    }
934
935
    /**
936
     * Creates a URL anchor.
937
     *
938
     * @param string $name
939
     * @param string $url
940
     * @param array  $attributes
941
     *
942
     * @return string
943
     */
944
    public static function url($name, $url, $attributes = [])
945
    {
946
        if (!empty($url)) {
947
            $url = preg_replace('#&amp;#', '&', $url);
948
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
949
            $attributes['href'] = $url;
950
        }
951
952
        return self::tag('a', $name, $attributes);
953
    }
954
955
    /**
956
     * Creates a div tag.
957
     *
958
     * @param string $content
959
     * @param array  $attributes
960
     *
961
     * @return string
962
     */
963
    public static function div($content, $attributes = [])
964
    {
965
        return self::tag('div', $content, $attributes);
966
    }
967
968
    /**
969
     * Creates a span tag.
970
     */
971
    public static function span($content, $attributes = [])
972
    {
973
        return self::tag('span', $content, $attributes);
974
    }
975
976
    /**
977
     * Displays an HTML input tag.
978
     */
979
    public static function input($type, $name, $value, $attributes = [])
980
    {
981
        if (isset($type)) {
982
            $attributes['type'] = $type;
983
        }
984
        if (isset($name)) {
985
            $attributes['name'] = $name;
986
        }
987
        if (isset($value)) {
988
            $attributes['value'] = $value;
989
        }
990
991
        return self::tag('input', '', $attributes);
992
    }
993
994
    /**
995
     * @param $name
996
     * @param $value
997
     * @param array $attributes
998
     *
999
     * @return string
1000
     */
1001
    public static function button($name, $value, $attributes = [])
1002
    {
1003
        if (!empty($name)) {
1004
            $attributes['name'] = $name;
1005
        }
1006
1007
        return self::tag('button', $value, $attributes);
1008
    }
1009
1010
    /**
1011
     * Displays an HTML select tag.
1012
     *
1013
     * @param string $name
1014
     * @param array  $values
1015
     * @param int    $default
1016
     * @param array  $extra_attributes
1017
     * @param bool   $show_blank_item
1018
     * @param null   $blank_item_text
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $blank_item_text is correct as it would always require null to be passed?
Loading history...
1019
     *
1020
     * @return string
1021
     */
1022
    public static function select(
1023
        $name,
1024
        $values,
1025
        $default = -1,
1026
        $extra_attributes = [],
1027
        $show_blank_item = true,
1028
        $blank_item_text = ''
1029
    ) {
1030
        $html = '';
1031
        $extra = '';
1032
        $default_id = 'id="'.$name.'" ';
1033
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1034
        foreach ($extra_attributes as $key => $parameter) {
1035
            if ($key == 'id') {
1036
                $default_id = '';
1037
            }
1038
            $extra .= $key.'="'.$parameter.'" ';
1039
        }
1040
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1041
1042
        if ($show_blank_item) {
1043
            if (empty($blank_item_text)) {
1044
                $blank_item_text = get_lang('Select');
1045
            } else {
1046
                $blank_item_text = Security::remove_XSS($blank_item_text);
1047
            }
1048
            $html .= self::tag(
1049
                'option',
1050
                '-- '.$blank_item_text.' --',
1051
                ['value' => '-1']
1052
            );
1053
        }
1054
        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...
1055
            foreach ($values as $key => $value) {
1056
                if (is_array($value) && isset($value['name'])) {
1057
                    $value = $value['name'];
1058
                }
1059
                $html .= '<option value="'.$key.'"';
1060
1061
                if (is_array($default)) {
1062
                    foreach ($default as $item) {
1063
                        if ($item == $key) {
1064
                            $html .= ' selected="selected"';
1065
                            break;
1066
                        }
1067
                    }
1068
                } else {
1069
                    if ($default == $key) {
1070
                        $html .= ' selected="selected"';
1071
                    }
1072
                }
1073
1074
                $html .= '>'.$value.'</option>';
1075
            }
1076
        }
1077
        $html .= '</select>';
1078
1079
        return $html;
1080
    }
1081
1082
    /**
1083
     * Creates a tab menu
1084
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1085
     * in the $htmlHeadXtra variable before the display_header
1086
     * Add this script.
1087
     *
1088
     * @example
1089
     * <script>
1090
                </script>
1091
     * @param array  $headers       list of the tab titles
1092
     * @param array  $items
1093
     * @param string $id            id of the container of the tab in the example "tabs"
1094
     * @param array  $attributes    for the ul
1095
     * @param array  $ul_attributes
1096
     * @param int    $selected
1097
     *
1098
     * @return string
1099
     */
1100
    public static function tabs(
1101
        $headers,
1102
        $items,
1103
        $id = 'tabs',
1104
        $attributes = [],
1105
        $ul_attributes = [],
1106
        $selected = ''
1107
    ) {
1108
        if (empty($headers) || count($headers) == 0) {
1109
            return '';
1110
        }
1111
1112
        $lis = '';
1113
        $i = 1;
1114
        foreach ($headers as $item) {
1115
            $active = '';
1116
            if ($i == 1) {
1117
                $active = ' active';
1118
            }
1119
1120
            if (!empty($selected)) {
1121
                $active = '';
1122
                if ($selected == $i) {
1123
                    $active = ' active';
1124
                }
1125
            }
1126
1127
            $item = self::tag(
1128
                'a',
1129
                $item,
1130
                [
1131
                    'href' => '#'.$id.'-'.$i,
1132
                    'role' => 'tab',
1133
                    'data-toggle' => 'tab',
1134
                    'id' => $id.$i,
1135
                ]
1136
            );
1137
            $ul_attributes['role'] = 'presentation';
1138
            $ul_attributes['class'] = $active;
1139
            $lis .= self::tag('li', $item, $ul_attributes);
1140
            $i++;
1141
        }
1142
1143
        $ul = self::tag(
1144
            'ul',
1145
            $lis,
1146
            [
1147
                'class' => 'nav nav-tabs tabs-margin',
1148
                'role' => 'tablist',
1149
                'id' => 'ul_'.$id,
1150
            ]
1151
        );
1152
1153
        $i = 1;
1154
        $divs = '';
1155
        foreach ($items as $content) {
1156
            $active = '';
1157
            if ($i == 1) {
1158
                $active = ' active';
1159
            }
1160
1161
            if (!empty($selected)) {
1162
                $active = '';
1163
                if ($selected == $i) {
1164
                    $active = ' active';
1165
                }
1166
            }
1167
1168
            $divs .= self::tag(
1169
                'div',
1170
                $content,
1171
                ['id' => $id.'-'.$i, 'class' => 'tab-pane '.$active, 'role' => 'tabpanel']
1172
            );
1173
            $i++;
1174
        }
1175
1176
        $attributes['id'] = $id;
1177
        $attributes['role'] = 'tabpanel';
1178
        $attributes['class'] = 'tab-wrapper';
1179
1180
        $main_div = self::tag(
1181
            'div',
1182
            $ul.self::tag('div', $divs, ['class' => 'tab-content']),
1183
            $attributes
1184
        );
1185
1186
        return $main_div;
1187
    }
1188
1189
    /**
1190
     * @param $headers
1191
     * @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...
1192
     *
1193
     * @return string
1194
     */
1195
    public static function tabsOnlyLink($headers, $selected = null)
1196
    {
1197
        $id = uniqid();
1198
        $i = 1;
1199
        $lis = null;
1200
        foreach ($headers as $item) {
1201
            $class = null;
1202
            if ($i == $selected) {
1203
                $class = 'active';
1204
            }
1205
            $item = self::tag(
1206
                'a',
1207
                $item['content'],
1208
                ['id' => $id.'-'.$i, 'href' => $item['url']]
1209
            );
1210
            $lis .= self::tag('li', $item, ['class' => $class]);
1211
            $i++;
1212
        }
1213
1214
        return self::tag(
1215
            'ul',
1216
            $lis,
1217
            ['class' => 'nav nav-tabs tabs-margin']
1218
        );
1219
    }
1220
1221
    /**
1222
     * In order to display a grid using jqgrid you have to:.
1223
     *
1224
     * @example
1225
     * After your Display::display_header function you have to add the nex javascript code:
1226
     * <script>
1227
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1228
     *   // for more information of this function check the grid_js() function
1229
     * </script>
1230
     * //Then you have to call the grid_html
1231
     * echo Display::grid_html('my_grid_name');
1232
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1233
     *
1234
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1235
     *
1236
     * @return string html
1237
     */
1238
    public static function grid_html($div_id)
1239
    {
1240
        $table = self::tag('table', '', ['id' => $div_id]);
1241
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1242
1243
        return $table;
1244
    }
1245
1246
    /**
1247
     * @param string $label
1248
     * @param string $form_item
1249
     *
1250
     * @return string
1251
     */
1252
    public static function form_row($label, $form_item)
1253
    {
1254
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1255
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1256
1257
        return self::div($label.$form_item, ['class' => 'form-group']);
1258
    }
1259
1260
    /**
1261
     * This is a wrapper to use the jqgrid in Chamilo.
1262
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1263
     * This function need to be in the ready jquery function
1264
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1265
     * In order to work this function needs the Display::grid_html function with the same div id.
1266
     *
1267
     * @param string $div_id       div id
1268
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1269
     * @param array  $column_names Visible columns (you should use get_lang).
1270
     *                             An array in which we place the names of the columns.
1271
     *                             This is the text that appears in the head of the grid (Header layer).
1272
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1273
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1274
     *                             This is the most important part of the grid.
1275
     *                             For a full description of all valid values see colModel API. See the url above.
1276
     * @param array  $extra_params extra parameters
1277
     * @param array  $data         data that will be loaded
1278
     * @param string $formatter    A string that will be appended to the JSON returned
1279
     * @param bool   $fixed_width  not implemented yet
1280
     *
1281
     * @return string the js code
1282
     */
1283
    public static function grid_js(
1284
        $div_id,
1285
        $url,
1286
        $column_names,
1287
        $column_model,
1288
        $extra_params,
1289
        $data = [],
1290
        $formatter = '',
1291
        $fixed_width = false
1292
    ) {
1293
        $obj = new stdClass();
1294
        $obj->first = 'first';
1295
1296
        if (!empty($url)) {
1297
            $obj->url = $url;
1298
        }
1299
1300
        //This line should only be used/modified in case of having characters
1301
        // encoding problems - see #6159
1302
        //$column_names = array_map("utf8_encode", $column_names);
1303
        $obj->colNames = $column_names;
1304
        $obj->colModel = $column_model;
1305
        $obj->pager = '#'.$div_id.'_pager';
1306
        $obj->datatype = 'json';
1307
        $obj->viewrecords = 'true';
1308
        $all_value = 10000000;
1309
1310
        // Sets how many records we want to view in the grid
1311
        $obj->rowNum = 20;
1312
1313
        // Default row quantity
1314
        if (!isset($extra_params['rowList'])) {
1315
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1316
            $rowList = api_get_configuration_value('table_row_list');
1317
            if (!empty($rowList) && isset($rowList['options'])) {
1318
                $rowList = $rowList['options'];
1319
                $rowList[] = $all_value;
1320
                $extra_params['rowList'] = $rowList;
1321
            }
1322
        }
1323
1324
        $defaultRow = api_get_configuration_value('table_default_row');
1325
        if (!empty($defaultRow)) {
1326
            $obj->rowNum = (int) $defaultRow;
1327
        }
1328
1329
        $json = '';
1330
        if (!empty($extra_params['datatype'])) {
1331
            $obj->datatype = $extra_params['datatype'];
1332
        }
1333
1334
        // Row even odd style.
1335
        $obj->altRows = true;
1336
        if (!empty($extra_params['altRows'])) {
1337
            $obj->altRows = $extra_params['altRows'];
1338
        }
1339
1340
        if (!empty($extra_params['sortname'])) {
1341
            $obj->sortname = $extra_params['sortname'];
1342
        }
1343
1344
        if (!empty($extra_params['sortorder'])) {
1345
            $obj->sortorder = $extra_params['sortorder'];
1346
        }
1347
1348
        if (!empty($extra_params['rowList'])) {
1349
            $obj->rowList = $extra_params['rowList'];
1350
        }
1351
1352
        if (!empty($extra_params['rowNum'])) {
1353
            $obj->rowNum = $extra_params['rowNum'];
1354
        } else {
1355
            // Try to load max rows from Session
1356
            $urlInfo = parse_url($url);
1357
            if (isset($urlInfo['query'])) {
1358
                parse_str($urlInfo['query'], $query);
1359
                if (isset($query['a'])) {
1360
                    $action = $query['a'];
1361
                    // This value is set in model.ajax.php
1362
                    $savedRows = Session::read('max_rows_'.$action);
1363
                    if (!empty($savedRows)) {
1364
                        $obj->rowNum = $savedRows;
1365
                    }
1366
                }
1367
            }
1368
        }
1369
1370
        if (!empty($extra_params['viewrecords'])) {
1371
            $obj->viewrecords = $extra_params['viewrecords'];
1372
        }
1373
1374
        $beforeSelectRow = null;
1375
        if (isset($extra_params['beforeSelectRow'])) {
1376
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1377
            unset($extra_params['beforeSelectRow']);
1378
        }
1379
1380
        $beforeProcessing = '';
1381
        if (isset($extra_params['beforeProcessing'])) {
1382
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1383
            unset($extra_params['beforeProcessing']);
1384
        }
1385
1386
        $beforeRequest = '';
1387
        if (isset($extra_params['beforeRequest'])) {
1388
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1389
            unset($extra_params['beforeRequest']);
1390
        }
1391
1392
        $gridComplete = '';
1393
        if (isset($extra_params['gridComplete'])) {
1394
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1395
            unset($extra_params['gridComplete']);
1396
        }
1397
1398
        // Adding extra params
1399
        if (!empty($extra_params)) {
1400
            foreach ($extra_params as $key => $element) {
1401
                // the groupHeaders key gets a special treatment
1402
                if ($key != 'groupHeaders') {
1403
                    $obj->$key = $element;
1404
                }
1405
            }
1406
        }
1407
1408
        // Adding static data.
1409
        if (!empty($data)) {
1410
            $data_var = $div_id.'_data';
1411
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1412
            $obj->data = $data_var;
1413
            $obj->datatype = 'local';
1414
            $json .= "\n";
1415
        }
1416
1417
        $obj->end = 'end';
1418
1419
        $json_encode = json_encode($obj);
1420
1421
        if (!empty($data)) {
1422
            //Converts the "data":"js_variable" to "data":js_variable,
1423
            // otherwise it will not work
1424
            $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...
1425
        }
1426
1427
        // Fixing true/false js values that doesn't need the ""
1428
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1429
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1430
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1431
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1432
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1433
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1434
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1435
1436
        if (api_get_configuration_value('allow_compilatio_tool') &&
1437
            (strpos($_SERVER['REQUEST_URI'], 'work/work.php') !== false ||
1438
             strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php') != false
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($_SERVER['REQUEST...ork/work_list_all.php') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1439
            )
1440
        ) {
1441
            $json_encode = str_replace('"function () { compilatioInit() }"',
1442
                'function () { compilatioInit() }',
1443
                $json_encode
1444
            );
1445
        }
1446
        // Creating the jqgrid element.
1447
        $json .= '$("#'.$div_id.'").jqGrid({';
1448
        //$json .= $beforeSelectRow;
1449
        $json .= $gridComplete;
1450
        $json .= $beforeProcessing;
1451
        $json .= $beforeRequest;
1452
        $json .= $json_encode;
1453
        $json .= '});';
1454
1455
        // Grouping headers option
1456
        if (isset($extra_params['groupHeaders'])) {
1457
            $groups = '';
1458
            foreach ($extra_params['groupHeaders'] as $group) {
1459
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1460
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1461
            }
1462
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1463
                "useColSpanStyle" : false,
1464
                "groupHeaders"    : [
1465
                    '.$groups.'
1466
                ]
1467
            });';
1468
        }
1469
1470
        $all_text = addslashes(get_lang('All'));
1471
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1472
        $json .= "\n";
1473
        // Adding edit/delete icons.
1474
        $json .= $formatter;
1475
1476
        return $json;
1477
    }
1478
1479
    /**
1480
     * @param array $headers
1481
     * @param array $rows
1482
     * @param array $attributes
1483
     *
1484
     * @return string
1485
     */
1486
    public static function table($headers, $rows, $attributes = [])
1487
    {
1488
        if (empty($attributes)) {
1489
            $attributes['class'] = 'table table-hover table-striped data_table';
1490
        }
1491
        $table = new HTML_Table($attributes);
1492
        $row = 0;
1493
        $column = 0;
1494
1495
        // Course headers
1496
        if (!empty($headers)) {
1497
            foreach ($headers as $item) {
1498
                $table->setHeaderContents($row, $column, $item);
1499
                $column++;
1500
            }
1501
            $row = 1;
1502
            $column = 0;
1503
        }
1504
1505
        if (!empty($rows)) {
1506
            foreach ($rows as $content) {
1507
                $table->setCellContents($row, $column, $content);
1508
                $row++;
1509
            }
1510
        }
1511
1512
        return $table->toHtml();
1513
    }
1514
1515
    /**
1516
     * Returns the "what's new" icon notifications.
1517
     *
1518
     * The general logic of this function is to track the last time the user
1519
     * entered the course and compare to what has changed inside this course
1520
     * since then, based on the item_property table inside this course. Note that,
1521
     * if the user never entered the course before, he will not see notification
1522
     * icons. This function takes session ID into account (if any) and only shows
1523
     * the corresponding notifications.
1524
     *
1525
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1526
     * @param bool  $loadAjax
1527
     *
1528
     * @return string The HTML link to be shown next to the course
1529
     */
1530
    public static function show_notification($courseInfo, $loadAjax = true)
1531
    {
1532
        if (empty($courseInfo)) {
1533
            return '';
1534
        }
1535
1536
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1537
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1538
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1539
        $course_code = Database::escape_string($courseInfo['code']);
1540
1541
        $user_id = api_get_user_id();
1542
        $course_id = (int) $courseInfo['real_id'];
1543
        $sessionId = (int) $courseInfo['id_session'];
1544
        $status = (int) $courseInfo['status'];
1545
1546
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1547
1548
        if ($loadNotificationsByAjax) {
1549
            if ($loadAjax) {
1550
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1551
                Session::write($id, true);
1552
1553
                return '<span id ="'.$id.'" class="course_notification"></span>';
1554
            }
1555
        }
1556
1557
        // Get the user's last access dates to all tools of this course
1558
        $sql = "SELECT *
1559
                FROM $t_track_e_access
1560
                WHERE
1561
                    c_id = $course_id AND
1562
                    access_user_id = '$user_id' AND
1563
                    access_session_id ='".$sessionId."'
1564
                ORDER BY access_date DESC
1565
                LIMIT 1
1566
                ";
1567
        $result = Database::query($sql);
1568
1569
        // latest date by default is the creation date
1570
        $latestDate = $courseInfo['creation_date'];
1571
        if (Database::num_rows($result)) {
1572
            $row = Database::fetch_array($result, 'ASSOC');
1573
            $latestDate = $row['access_date'];
1574
        }
1575
1576
        $sessionCondition = api_get_session_condition(
1577
            $sessionId,
1578
            true,
1579
            false,
1580
            'session_id'
1581
        );
1582
1583
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1584
        // Get current tools in course
1585
        $sql = "SELECT name, link, image
1586
                FROM $course_tool_table
1587
                WHERE
1588
                    c_id = $course_id AND
1589
                    visibility = '1' AND
1590
                    name NOT IN ('".implode("','", $hideTools)."')
1591
                ";
1592
        $result = Database::query($sql);
1593
        $tools = Database::store_result($result);
1594
1595
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1596
        $group_ids[] = 0; //add group 'everyone'
1597
        $notifications = [];
1598
        if ($tools) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tools 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...
1599
            foreach ($tools as $tool) {
1600
                $toolName = $tool['name'];
1601
                $toolName = Database::escape_string($toolName);
1602
                // Fix to get student publications
1603
                $toolCondition = " tool = '$toolName' AND ";
1604
                if ($toolName == 'student_publication' || $toolName == 'work') {
1605
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1606
                }
1607
1608
                $toolName = addslashes($toolName);
1609
1610
                $sql = "SELECT * FROM $tool_edit_table
1611
                        WHERE
1612
                            c_id = $course_id AND
1613
                            $toolCondition
1614
                            lastedit_type NOT LIKE '%Deleted%' AND
1615
                            lastedit_type NOT LIKE '%deleted%' AND
1616
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1617
                            lastedit_date > '$latestDate' AND
1618
                            lastedit_user_id != $user_id $sessionCondition AND
1619
                            visibility != 2 AND
1620
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1621
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1622
                        ORDER BY lastedit_date DESC
1623
                        LIMIT 1";
1624
                $result = Database::query($sql);
1625
1626
                $latestChange = Database::fetch_array($result, 'ASSOC');
1627
1628
                if ($latestChange) {
1629
                    $latestChange['link'] = $tool['link'];
1630
                    $latestChange['image'] = $tool['image'];
1631
                    $latestChange['tool'] = $tool['name'];
1632
                    $notifications[$toolName] = $latestChange;
1633
                }
1634
            }
1635
        }
1636
1637
        // Show all tool icons where there is something new.
1638
        $return = '';
1639
        foreach ($notifications as $notification) {
1640
            $toolName = $notification['tool'];
1641
            if (!(
1642
                    $notification['visibility'] == '1' ||
1643
                    ($status == '1' && $notification['visibility'] == '0') ||
1644
                    !isset($notification['visibility'])
1645
                )
1646
            ) {
1647
                continue;
1648
            }
1649
1650
            if ($toolName == TOOL_SURVEY) {
1651
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1652
                if (!empty($survey_info)) {
1653
                    $invited_users = SurveyUtil::get_invited_users(
1654
                        $survey_info['code'],
1655
                        $course_code
1656
                    );
1657
                    if (!in_array($user_id, $invited_users['course_users'])) {
1658
                        continue;
1659
                    }
1660
                }
1661
            }
1662
1663
            if ($notification['tool'] == TOOL_LEARNPATH) {
1664
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1665
                    continue;
1666
                }
1667
            }
1668
1669
            if ($notification['tool'] == TOOL_DROPBOX) {
1670
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1671
            }
1672
1673
            if ($notification['tool'] == 'work' &&
1674
                $notification['lastedit_type'] == 'DirectoryCreated'
1675
            ) {
1676
                $notification['lastedit_type'] = 'WorkAdded';
1677
            }
1678
1679
            $lastDate = api_get_local_time($notification['lastedit_date']);
1680
            $type = $notification['lastedit_type'];
1681
            if ($type == 'CalendareventVisible') {
1682
                $type = 'Visible';
1683
            }
1684
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1685
1686
            if (strpos($notification['link'], '?') === false) {
1687
                $notification['link'] = $notification['link'].'?notification=1';
1688
            } else {
1689
                $notification['link'] = $notification['link'].'&notification=1';
1690
            }
1691
1692
            $image = substr($notification['image'], 0, -4).'.png';
1693
1694
            $return .= self::url(
1695
                self::return_icon($image, $label),
1696
                api_get_path(WEB_CODE_PATH).
1697
                $notification['link'].'&cidReq='.$course_code.
1698
                '&ref='.$notification['ref'].
1699
                '&gidReq='.$notification['to_group_id'].
1700
                '&id_session='.$sessionId
1701
            ).PHP_EOL;
1702
        }
1703
1704
        return $return;
1705
    }
1706
1707
    /**
1708
     * Get the session box details as an array.
1709
     *
1710
     * @param int       Session ID
1711
     *
1712
     * @return array Empty array or session array
1713
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1714
     */
1715
    public static function getSessionTitleBox($session_id)
1716
    {
1717
        global $nosession;
1718
1719
        if (!$nosession) {
1720
            global $now, $date_start, $date_end;
1721
        }
1722
        $output = [];
1723
        if (!$nosession) {
1724
            $session_info = api_get_session_info($session_id);
1725
            $coachInfo = [];
1726
            if (!empty($session_info['id_coach'])) {
1727
                $coachInfo = api_get_user_info($session_info['id_coach']);
1728
            }
1729
1730
            $session = [];
1731
            $session['category_id'] = $session_info['session_category_id'];
1732
            $session['title'] = $session_info['name'];
1733
            $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1734
            $session['dates'] = '';
1735
            $session['coach'] = '';
1736
            if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1737
                $session['coach'] = get_lang('GeneralCoach').': '.$coachInfo['complete_name'];
1738
            }
1739
1740
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1741
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1742
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1743
            ) {
1744
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1745
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1746
                    $session['duration'] = $daysLeft >= 0
1747
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1748
                        : get_lang('YourSessionTimeHasExpired');
1749
                }
1750
                $active = true;
1751
            } else {
1752
                $dates = SessionManager::parseSessionDates($session_info, true);
1753
                $session['dates'] = $dates['access'];
1754
                if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1755
                    $session['coach'] = $coachInfo['complete_name'];
1756
                }
1757
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_end does not seem to be defined for all execution paths leading up to this point.
Loading history...
1758
            }
1759
            $session['active'] = $active;
1760
            $session['session_category_id'] = $session_info['session_category_id'];
1761
            $session['visibility'] = $session_info['visibility'];
1762
            $session['num_users'] = $session_info['nbr_users'];
1763
            $session['num_courses'] = $session_info['nbr_courses'];
1764
            $session['description'] = $session_info['description'];
1765
            $session['show_description'] = $session_info['show_description'];
1766
1767
            $entityManager = Database::getManager();
1768
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1769
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1770
                ExtraField::SESSION_FIELD_TYPE,
1771
                $session_id
1772
            );
1773
1774
            $session['extra_fields'] = [];
1775
            foreach ($extraFieldValues as $value) {
1776
                $session['extra_fields'][] = [
1777
                    'field' => [
1778
                        'variable' => $value->getField()->getVariable(),
1779
                        'display_text' => $value->getField()->getDisplayText(),
1780
                    ],
1781
                    'value' => $value->getValue(),
1782
                ];
1783
            }
1784
1785
            $output = $session;
1786
        }
1787
1788
        return $output;
1789
    }
1790
1791
    /**
1792
     * Return the five star HTML.
1793
     *
1794
     * @param string $id              of the rating ul element
1795
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1796
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1797
     * @param bool   $add_div_wrapper add a div wrapper
1798
     *
1799
     * @return string
1800
     */
1801
    public static function return_rating_system(
1802
        $id,
1803
        $url,
1804
        $point_info = [],
1805
        $add_div_wrapper = true
1806
    ) {
1807
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1808
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1809
1810
        if (!empty($percentage)) {
1811
            $percentage = $percentage * 125 / 100;
1812
        }
1813
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1814
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1815
1816
        $html = '<ul id="'.$id.'" class="star-rating">
1817
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1818
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1819
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1820
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1821
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1822
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1823
                </ul>';
1824
1825
        $labels = [];
1826
1827
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1828
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1829
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1830
1831
        if (!$add_div_wrapper && api_is_anonymous()) {
1832
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1833
        }
1834
1835
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1836
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1837
1838
        if ($add_div_wrapper) {
1839
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1840
        }
1841
1842
        return $html;
1843
    }
1844
1845
    /**
1846
     * @param string $title
1847
     * @param string $second_title
1848
     * @param string $size
1849
     * @param bool   $filter
1850
     *
1851
     * @return string
1852
     */
1853
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1854
    {
1855
        if ($filter) {
1856
            $title = Security::remove_XSS($title);
1857
        }
1858
1859
        if (!empty($second_title)) {
1860
            if ($filter) {
1861
                $second_title = Security::remove_XSS($second_title);
1862
            }
1863
            $title .= "<small> $second_title</small>";
1864
        }
1865
1866
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1867
    }
1868
1869
    public static function page_header_and_translate($title, $second_title = null)
1870
    {
1871
        $title = get_lang($title);
1872
1873
        return self::page_header($title, $second_title);
1874
    }
1875
1876
    public static function page_subheader_and_translate($title, $second_title = null)
1877
    {
1878
        $title = get_lang($title);
1879
1880
        return self::page_subheader($title, $second_title);
1881
    }
1882
1883
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1884
    {
1885
        if (!empty($second_title)) {
1886
            $second_title = Security::remove_XSS($second_title);
1887
            $title .= "<small> $second_title<small>";
1888
        }
1889
        $attributes['class'] = 'page-header';
1890
1891
        return self::tag($size, Security::remove_XSS($title), $attributes);
1892
    }
1893
1894
    public static function page_subheader2($title, $second_title = null)
1895
    {
1896
        return self::page_header($title, $second_title, 'h4');
1897
    }
1898
1899
    public static function page_subheader3($title, $second_title = null)
1900
    {
1901
        return self::page_header($title, $second_title, 'h5');
1902
    }
1903
1904
    /**
1905
     * @param array $list
1906
     *
1907
     * @return string|null
1908
     */
1909
    public static function description($list)
1910
    {
1911
        $html = null;
1912
        if (!empty($list)) {
1913
            $html = '<dl class="dl-horizontal">';
1914
            foreach ($list as $item) {
1915
                $html .= '<dt>'.$item['title'].'</dt>';
1916
                $html .= '<dd>'.$item['content'].'</dd>';
1917
            }
1918
            $html .= '</dl>';
1919
        }
1920
1921
        return $html;
1922
    }
1923
1924
    /**
1925
     * @param int    $percentage      int value between 0 and 100
1926
     * @param bool   $show_percentage
1927
     * @param string $extra_info
1928
     * @param string $class           danger/success/infowarning
1929
     *
1930
     * @return string
1931
     */
1932
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1933
    {
1934
        $percentage = (int) $percentage;
1935
        $class = empty($class) ? '' : "progress-bar-$class";
1936
1937
        $div = '<div class="progress">
1938
                <div
1939
                    class="progress-bar progress-bar-striped '.$class.'"
1940
                    role="progressbar"
1941
                    aria-valuenow="'.$percentage.'"
1942
                    aria-valuemin="0"
1943
                    aria-valuemax="100"
1944
                    style="width: '.$percentage.'%;"
1945
                >';
1946
        if ($show_percentage) {
1947
            $div .= $percentage.'%';
1948
        } else {
1949
            if (!empty($extra_info)) {
1950
                $div .= $extra_info;
1951
            }
1952
        }
1953
        $div .= '</div></div>';
1954
1955
        return $div;
1956
    }
1957
1958
    /**
1959
     * @param string $count
1960
     * @param string $type
1961
     *
1962
     * @return string|null
1963
     */
1964
    public static function badge($count, $type = "warning")
1965
    {
1966
        $class = '';
1967
1968
        switch ($type) {
1969
            case 'success':
1970
                $class = 'badge-success';
1971
                break;
1972
            case 'warning':
1973
                $class = 'badge-warning';
1974
                break;
1975
            case 'important':
1976
                $class = 'badge-important';
1977
                break;
1978
            case 'info':
1979
                $class = 'badge-info';
1980
                break;
1981
            case 'inverse':
1982
                $class = 'badge-inverse';
1983
                break;
1984
        }
1985
1986
        if (!empty($count)) {
1987
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1988
        }
1989
1990
        return null;
1991
    }
1992
1993
    /**
1994
     * @param array $badge_list
1995
     *
1996
     * @return string
1997
     */
1998
    public static function badge_group($badge_list)
1999
    {
2000
        $html = '<div class="badge-group">';
2001
        foreach ($badge_list as $badge) {
2002
            $html .= $badge;
2003
        }
2004
        $html .= '</div>';
2005
2006
        return $html;
2007
    }
2008
2009
    /**
2010
     * @param string $content
2011
     * @param string $type
2012
     *
2013
     * @return string
2014
     */
2015
    public static function label($content, $type = 'default')
2016
    {
2017
        switch ($type) {
2018
            case 'success':
2019
                $class = 'label-success';
2020
                break;
2021
            case 'warning':
2022
                $class = 'label-warning';
2023
                break;
2024
            case 'important':
2025
            case 'danger':
2026
                $class = 'label-danger';
2027
                break;
2028
            case 'info':
2029
                $class = 'label-info';
2030
                break;
2031
            case 'primary':
2032
                $class = 'label-primary';
2033
                break;
2034
            default:
2035
                $class = 'label-default';
2036
                break;
2037
        }
2038
2039
        $html = '';
2040
        if (!empty($content)) {
2041
            $html = '<span class="label '.$class.'">';
2042
            $html .= $content;
2043
            $html .= '</span>';
2044
        }
2045
2046
        return $html;
2047
    }
2048
2049
    /**
2050
     * @param array  $items
2051
     * @param string $class
2052
     *
2053
     * @return string|null
2054
     */
2055
    public static function actions($items, $class = 'new_actions')
2056
    {
2057
        $html = null;
2058
        if (!empty($items)) {
2059
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2060
            foreach ($items as $value) {
2061
                $class = null;
2062
                if (isset($value['active']) && $value['active']) {
2063
                    $class = 'class ="active"';
2064
                }
2065
2066
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2067
                    $class = 'class ="active"';
2068
                }
2069
                $html .= "<li $class >";
2070
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2071
                $html .= self::url($value['content'], $value['url'], $attributes);
2072
                $html .= '</li>';
2073
            }
2074
            $html .= '</ul></div>';
2075
            $html .= '<br />';
2076
        }
2077
2078
        return $html;
2079
    }
2080
2081
    /**
2082
     * Prints a tooltip.
2083
     *
2084
     * @param string $text
2085
     * @param string $tip
2086
     *
2087
     * @return string
2088
     */
2089
    public static function tip($text, $tip, string $tag = 'span')
2090
    {
2091
        if (empty($tip)) {
2092
            return $text;
2093
        }
2094
2095
        return self::tag(
2096
            $tag,
2097
            $text,
2098
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2099
        );
2100
    }
2101
2102
    /**
2103
     * @param array  $items
2104
     * @param string $type
2105
     * @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...
2106
     *
2107
     * @return string|null
2108
     */
2109
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2110
    {
2111
        $html = null;
2112
        if (!empty($items)) {
2113
            if (empty($id)) {
2114
                $id = api_get_unique_id();
2115
            }
2116
            if ($type == 'jquery') {
2117
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2118
            } else {
2119
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2120
            }
2121
2122
            $count = 1;
2123
            foreach ($items as $item) {
2124
                $html .= '<div class="accordion-my-group">';
2125
                $html .= '<div class="accordion-heading">
2126
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2127
                            '.$item['title'].'
2128
                            </a>
2129
                          </div>';
2130
2131
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2132
                $html .= '<div class="accordion-my-inner">
2133
                            '.$item['content'].'
2134
                            </div>
2135
                          </div>';
2136
            }
2137
            $html .= '</div>';
2138
        }
2139
2140
        return $html;
2141
    }
2142
2143
    /**
2144
     * @param array $buttons
2145
     *
2146
     * @return string
2147
     */
2148
    public static function groupButton($buttons)
2149
    {
2150
        $html = '<div class="btn-group" role="group">';
2151
        foreach ($buttons as $button) {
2152
            $html .= $button;
2153
        }
2154
        $html .= '</div>';
2155
2156
        return $html;
2157
    }
2158
2159
    /**
2160
     * @todo use twig
2161
     *
2162
     * @param string $title
2163
     * @param array  $elements
2164
     * @param bool   $alignToRight
2165
     *
2166
     * @return string
2167
     */
2168
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2169
    {
2170
        $html = '<div class="btn-group">
2171
                <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
2172
                '.$title.'
2173
                <span class="caret"></span></button>
2174
                <ul class="dropdown-menu '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2175
        foreach ($elements as $item) {
2176
            $html .= self::tag('li', self::url($item['title'], $item['href']));
2177
        }
2178
        $html .= '</ul>
2179
            </div>';
2180
2181
        return $html;
2182
    }
2183
2184
    /**
2185
     * @param string $file
2186
     * @param array  $params
2187
     *
2188
     * @return string|null
2189
     */
2190
    public static function getMediaPlayer($file, $params = [])
2191
    {
2192
        $fileInfo = pathinfo($file);
2193
2194
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2195
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2196
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2197
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2198
2199
        switch ($fileInfo['extension']) {
2200
            case 'mp3':
2201
            case 'webm':
2202
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'">';
2203
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2204
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2205
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2206
                          </object>';
2207
                $html .= '</audio>';
2208
2209
                return $html;
2210
                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...
2211
            case 'wav':
2212
            case 'ogg':
2213
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'"></audio>';
2214
2215
                return $html;
2216
                break;
2217
        }
2218
2219
        return null;
2220
    }
2221
2222
    /**
2223
     * @param int    $nextValue
2224
     * @param array  $list
2225
     * @param int    $current
2226
     * @param int    $fixedValue
2227
     * @param array  $conditions
2228
     * @param string $link
2229
     * @param bool   $isMedia
2230
     * @param bool   $addHeaders
2231
     * @param array  $linkAttributes
2232
     *
2233
     * @return string
2234
     */
2235
    public static function progressPaginationBar(
2236
        $nextValue,
2237
        $list,
2238
        $current,
2239
        $fixedValue = null,
2240
        $conditions = [],
2241
        $link = null,
2242
        $isMedia = false,
2243
        $addHeaders = true,
2244
        $linkAttributes = []
2245
    ) {
2246
        if ($addHeaders) {
2247
            $pagination_size = 'pagination-mini';
2248
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2249
        } else {
2250
            $html = null;
2251
        }
2252
        $affectAllItems = false;
2253
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2254
            $affectAllItems = true;
2255
        }
2256
        $localCounter = 0;
2257
        foreach ($list as $itemId) {
2258
            $isCurrent = false;
2259
            if ($affectAllItems) {
2260
                $isCurrent = true;
2261
            } else {
2262
                if (!$isMedia) {
2263
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2264
                }
2265
            }
2266
            $html .= self::parsePaginationItem(
2267
                $itemId,
2268
                $isCurrent,
2269
                $conditions,
2270
                $link,
2271
                $nextValue,
2272
                $isMedia,
2273
                $localCounter,
2274
                $fixedValue,
2275
                $linkAttributes
2276
            );
2277
            $localCounter++;
2278
        }
2279
        if ($addHeaders) {
2280
            $html .= '</ul></div>';
2281
        }
2282
2283
        return $html;
2284
    }
2285
2286
    /**
2287
     * @param int    $itemId
2288
     * @param bool   $isCurrent
2289
     * @param array  $conditions
2290
     * @param string $link
2291
     * @param int    $nextValue
2292
     * @param bool   $isMedia
2293
     * @param int    $localCounter
2294
     * @param int    $fixedValue
2295
     * @param array  $linkAttributes
2296
     *
2297
     * @return string
2298
     */
2299
    public static function parsePaginationItem(
2300
        $itemId,
2301
        $isCurrent,
2302
        $conditions,
2303
        $link,
2304
        $nextValue = 0,
2305
        $isMedia = false,
2306
        $localCounter = null,
2307
        $fixedValue = null,
2308
        $linkAttributes = []
2309
    ) {
2310
        $defaultClass = 'before';
2311
        $class = $defaultClass;
2312
        foreach ($conditions as $condition) {
2313
            $array = isset($condition['items']) ? $condition['items'] : [];
2314
            $class_to_applied = $condition['class'];
2315
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2316
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2317
            switch ($type) {
2318
                case 'positive':
2319
                    if (in_array($itemId, $array)) {
2320
                        if ($mode == 'overwrite') {
2321
                            $class = " $defaultClass $class_to_applied";
2322
                        } else {
2323
                            $class .= " $class_to_applied";
2324
                        }
2325
                    }
2326
                    break;
2327
                case 'negative':
2328
                    if (!in_array($itemId, $array)) {
2329
                        if ($mode == 'overwrite') {
2330
                            $class = " $defaultClass $class_to_applied";
2331
                        } else {
2332
                            $class .= " $class_to_applied";
2333
                        }
2334
                    }
2335
                    break;
2336
            }
2337
        }
2338
        if ($isCurrent) {
2339
            $class = 'before current';
2340
        }
2341
        if ($isMedia && $isCurrent) {
2342
            $class = 'before current';
2343
        }
2344
        if (empty($link)) {
2345
            $link_to_show = '#';
2346
        } else {
2347
            $link_to_show = $link.($nextValue + $localCounter);
2348
        }
2349
        $label = $nextValue + $localCounter + 1;
2350
        if ($isMedia) {
2351
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2352
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2353
        }
2354
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2355
2356
        return '<li class = "'.$class.'">'.$link.'</li>';
2357
    }
2358
2359
    /**
2360
     * @param int $current
2361
     * @param int $total
2362
     *
2363
     * @return string
2364
     */
2365
    public static function paginationIndicator($current, $total)
2366
    {
2367
        $html = null;
2368
        if (!empty($current) && !empty($total)) {
2369
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2370
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2371
        }
2372
2373
        return $html;
2374
    }
2375
2376
    /**
2377
     * @param $url
2378
     * @param $currentPage
2379
     * @param $pagesCount
2380
     * @param $totalItems
2381
     *
2382
     * @return string
2383
     */
2384
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2385
    {
2386
        $pagination = '';
2387
        if ($totalItems > 1 && $pagesCount > 1) {
2388
            $pagination .= '<ul class="pagination">';
2389
            for ($i = 0; $i < $pagesCount; $i++) {
2390
                $newPage = $i + 1;
2391
                if ($currentPage == $newPage) {
2392
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2393
                } else {
2394
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2395
                }
2396
            }
2397
            $pagination .= '</ul>';
2398
        }
2399
2400
        return $pagination;
2401
    }
2402
2403
    /**
2404
     * Adds a message in the queue.
2405
     *
2406
     * @param string $message
2407
     */
2408
    public static function addFlash($message)
2409
    {
2410
        $messages = Session::read('flash_messages');
2411
        if (empty($messages)) {
2412
            $messages[] = $message;
2413
        } else {
2414
            array_push($messages, $message);
2415
        }
2416
        Session::write('flash_messages', $messages);
2417
    }
2418
2419
    /**
2420
     * @return string
2421
     */
2422
    public static function getFlashToString()
2423
    {
2424
        $messages = Session::read('flash_messages');
2425
        $messageToString = '';
2426
        if (!empty($messages)) {
2427
            foreach ($messages as $message) {
2428
                $messageToString .= $message;
2429
            }
2430
        }
2431
2432
        return $messageToString;
2433
    }
2434
2435
    /**
2436
     * Shows the message from the session.
2437
     */
2438
    public static function showFlash()
2439
    {
2440
        echo self::getFlashToString();
2441
    }
2442
2443
    /**
2444
     * Destroys the message session.
2445
     */
2446
    public static function cleanFlashMessages()
2447
    {
2448
        Session::erase('flash_messages');
2449
    }
2450
2451
    /**
2452
     * Get the profile edition link for a user.
2453
     *
2454
     * @param int  $userId  The user id
2455
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2456
     *
2457
     * @return string The link
2458
     */
2459
    public static function getProfileEditionLink($userId, $asAdmin = false)
2460
    {
2461
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2462
        if ($asAdmin) {
2463
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2464
        }
2465
2466
        if (api_get_setting('sso_authentication') === 'true') {
2467
            $subSSOClass = api_get_setting('sso_authentication_subclass');
2468
            $objSSO = null;
2469
2470
            if (!empty($subSSOClass)) {
2471
                $file = api_get_path(SYS_CODE_PATH)."auth/sso/sso.$subSSOClass.class.php";
2472
                if (file_exists($file)) {
2473
                    require_once $file;
2474
                    $subSSOClass = 'sso'.$subSSOClass;
2475
                    $objSSO = new $subSSOClass();
2476
                } else {
2477
                    throw new Exception("$subSSOClass file not set");
2478
                }
2479
            } else {
2480
                $objSSO = new sso();
2481
            }
2482
2483
            $editProfileUrl = $objSSO->generateProfileEditingURL(
2484
                $userId,
2485
                $asAdmin
2486
            );
2487
        }
2488
2489
        return $editProfileUrl;
2490
    }
2491
2492
    /**
2493
     * Get the vCard for a user.
2494
     *
2495
     * @param int $userId The user id
2496
     *
2497
     * @return string *.*vcf file
2498
     */
2499
    public static function getVCardUserLink($userId)
2500
    {
2501
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2502
2503
        return $vCardUrl;
2504
    }
2505
2506
    /**
2507
     * @param string $content
2508
     * @param string $title
2509
     * @param string $footer
2510
     * @param string $type            primary|success|info|warning|danger
2511
     * @param string $extra
2512
     * @param string $id
2513
     * @param string $backgroundColor
2514
     * @param string $extraClass
2515
     *
2516
     * @return string
2517
     */
2518
    public static function panel(
2519
        $content,
2520
        $title = '',
2521
        $footer = '',
2522
        $type = 'default',
2523
        $extra = '',
2524
        $id = '',
2525
        $backgroundColor = '',
2526
        $extraClass = ''
2527
    ) {
2528
        $headerStyle = '';
2529
        if (!empty($backgroundColor)) {
2530
            $headerStyle = 'style = "color: white; background-color: '.$backgroundColor.'" ';
2531
        }
2532
2533
        $title = !empty($title) ? '<div class="panel-heading" '.$headerStyle.' ><h3 class="panel-title">'.$title.'</h3>'.$extra.'</div>' : '';
2534
2535
        if (empty($title) && !empty($extra)) {
2536
            $title = '<div class="panel-heading" '.$headerStyle.' >'.$extra.'</div>';
2537
        }
2538
2539
        $footer = !empty($footer) ? '<div class="panel-footer">'.$footer.'</div>' : '';
2540
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2541
        $style = !in_array($type, $typeList) ? 'default' : $type;
2542
2543
        if (!empty($id)) {
2544
            $id = " id='$id'";
2545
        }
2546
2547
        return '
2548
            <div '.$id.' class="panel panel-'.$style.' '.$extraClass.' ">
2549
                '.$title.'
2550
                '.self::contentPanel($content).'
2551
                '.$footer.'
2552
            </div>'
2553
        ;
2554
    }
2555
2556
    /**
2557
     * @param string $content
2558
     *
2559
     * @return string
2560
     */
2561
    public static function contentPanel($content)
2562
    {
2563
        if (empty($content)) {
2564
            return '';
2565
        }
2566
2567
        return '<div class="panel-body">'.$content.'</div>';
2568
    }
2569
2570
    /**
2571
     * Get the button HTML with an Awesome Font icon.
2572
     *
2573
     * @param string $text        The button content
2574
     * @param string $url         The url to button
2575
     * @param string $icon        The Awesome Font class for icon
2576
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2577
     * @param array  $attributes  The additional attributes
2578
     * @param bool   $includeText
2579
     *
2580
     * @return string The button HTML
2581
     */
2582
    public static function toolbarButton(
2583
        $text,
2584
        $url,
2585
        $icon = 'check',
2586
        $type = 'default',
2587
        array $attributes = [],
2588
        $includeText = true
2589
    ) {
2590
        $buttonClass = "btn btn-$type";
2591
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2592
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2593
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2594
2595
        if (!$includeText) {
2596
            $text = '<span class="sr-only">'.$text.'</span>';
2597
        }
2598
2599
        return self::url("$icon $text", $url, $attributes);
2600
    }
2601
2602
    /**
2603
     * @param string $id
2604
     * @param array  $content
2605
     * @param array  $colsWidth Optional. Columns width
2606
     *
2607
     * @return string
2608
     */
2609
    public static function toolbarAction($id, $content, $colsWidth = [])
2610
    {
2611
        $col = count($content);
2612
2613
        if (!$colsWidth) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $colsWidth of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2614
            $width = 12 / $col;
2615
            array_walk($content, function () use ($width, &$colsWidth) {
2616
                $colsWidth[] = $width;
2617
            });
2618
        }
2619
2620
        $html = '<div id="'.$id.'" class="actions">';
2621
        $html .= '<div class="row">';
2622
2623
        for ($i = 0; $i < $col; $i++) {
2624
            $class = 'col-sm-'.$colsWidth[$i];
2625
2626
            if ($col > 1) {
2627
                if ($i > 0 && $i < count($content) - 1) {
2628
                    $class .= ' text-center';
2629
                } elseif ($i === count($content) - 1) {
2630
                    $class .= ' text-right';
2631
                }
2632
            }
2633
2634
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2635
        }
2636
2637
        $html .= '</div>';
2638
        $html .= '</div>';
2639
2640
        return $html;
2641
    }
2642
2643
    /**
2644
     * Get a HTML code for a icon by Font Awesome.
2645
     *
2646
     * @param string     $name            The icon name. Example: "mail-reply"
2647
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2648
     * @param bool       $fixWidth        Optional. Whether add the fw class
2649
     * @param string     $additionalClass
2650
     * @param string     $title
2651
     *
2652
     * @return string
2653
     */
2654
    public static function returnFontAwesomeIcon(
2655
        $name,
2656
        $size = '',
2657
        $fixWidth = false,
2658
        $additionalClass = '',
2659
        $title = ''
2660
    ) {
2661
        $className = "fa fa-$name";
2662
2663
        if ($fixWidth) {
2664
            $className .= ' fa-fw';
2665
        }
2666
2667
        switch ($size) {
2668
            case 'lg':
2669
                $className .= ' fa-lg';
2670
                break;
2671
            case 2:
2672
            case 3:
2673
            case 4:
2674
            case 5:
2675
                $className .= " fa-{$size}x";
2676
                break;
2677
        }
2678
2679
        if (!empty($additionalClass)) {
2680
            $className .= " $additionalClass";
2681
        }
2682
2683
        $icon = self::tag('em', null, ['class' => $className, 'title' => $title]);
2684
2685
        return "$icon ";
2686
    }
2687
2688
    /**
2689
     * @param string     $title
2690
     * @param string     $content
2691
     * @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...
2692
     * @param array      $params
2693
     * @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...
2694
     * @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...
2695
     * @param bool|true  $open
2696
     * @param bool|false $fullClickable
2697
     *
2698
     * @return string|null
2699
     *
2700
     * @todo rework function to easy use
2701
     */
2702
    public static function panelCollapse(
2703
        $title,
2704
        $content,
2705
        $id = null,
2706
        $params = [],
2707
        $idAccordion = null,
2708
        $idCollapse = null,
2709
        $open = true,
2710
        $fullClickable = false
2711
    ) {
2712
        if (!empty($idAccordion)) {
2713
            $headerClass = '';
2714
            $headerClass .= $fullClickable ? 'center-block ' : '';
2715
            $headerClass .= $open ? '' : 'collapsed';
2716
            $contentClass = 'panel-collapse collapse ';
2717
            $contentClass .= $open ? 'in ' : '';
2718
            $contentClass .= $params['class'] ?? '';
2719
            $ariaExpanded = $open ? 'true' : 'false';
2720
2721
            $attributes = [
2722
                'id' => $idCollapse,
2723
                'class' => $contentClass,
2724
                'role' => 'tabpanel',
2725
            ];
2726
2727
            if (!empty($params)) {
2728
                $attributes = array_merge(
2729
                    $params,
2730
                    $attributes
2731
                );
2732
            }
2733
2734
            $collapseDiv = self::div('<div class="panel-body">'.$content.'</div>', $attributes);
2735
2736
            $html = <<<HTML
2737
                <div class="panel-group" id="$idAccordion" role="tablist" aria-multiselectable="true">
2738
                    <div class="panel panel-default" id="$id">
2739
                        <div class="panel-heading" role="tab">
2740
                            <h4 class="panel-title">
2741
                                <a
2742
                                    class="$headerClass"
2743
                                    role="button" data-toggle="collapse"
2744
                                    data-parent="#$idAccordion" href="#$idCollapse"
2745
                                    aria-expanded="$ariaExpanded"
2746
                                    aria-controls="$idCollapse">$title</a>
2747
                            </h4>
2748
                        </div>
2749
                        $collapseDiv
2750
                    </div>
2751
                </div>
2752
HTML;
2753
        } else {
2754
            if (!empty($id)) {
2755
                $params['id'] = $id;
2756
            }
2757
            $params['class'] = 'panel panel-default';
2758
            $html = null;
2759
            if (!empty($title)) {
2760
                $html .= '<div class="panel-heading">'.$title.'</div>'.PHP_EOL;
2761
            }
2762
            $html .= '<div class="panel-body">'.$content.'</div>'.PHP_EOL;
2763
            $html = self::div($html, $params);
2764
        }
2765
2766
        return $html;
2767
    }
2768
2769
    /**
2770
     * Returns the string "1 day ago" with a link showing the exact date time.
2771
     *
2772
     * @param string $dateTime in UTC or a DateTime in UTC
2773
     *
2774
     * @return string
2775
     */
2776
    public static function dateToStringAgoAndLongDate($dateTime)
2777
    {
2778
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2779
            return '';
2780
        }
2781
2782
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2783
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2784
        }
2785
2786
        return self::tip(
2787
            date_to_str_ago($dateTime),
2788
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2789
            //api_get_local_time($dateTime)
2790
        );
2791
    }
2792
2793
    /**
2794
     * @param array  $userInfo
2795
     * @param string $status
2796
     * @param string $toolbar
2797
     *
2798
     * @return string
2799
     */
2800
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2801
    {
2802
        if (empty($userInfo)) {
2803
            return '';
2804
        }
2805
2806
        if (!empty($status)) {
2807
            $status = '<div class="items-user-status">'.$status.'</div>';
2808
        }
2809
2810
        if (!empty($toolbar)) {
2811
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2812
        }
2813
2814
        return '<div id="user_card_'.$userInfo['id'].'" class="col-md-12">
2815
                    <div class="row">
2816
                        <div class="col-md-2">
2817
                            <img src="'.$userInfo['avatar'].'" class="img-responsive img-circle">
2818
                        </div>
2819
                        <div class="col-md-10">
2820
                           <p>'.$userInfo['complete_name'].'</p>
2821
                           <div class="row">
2822
                           <div class="col-md-2">
2823
                           '.$status.'
2824
                           </div>
2825
                           <div class="col-md-10">
2826
                           '.$toolbar.'
2827
                           </div>
2828
                           </div>
2829
                        </div>
2830
                    </div>
2831
                    <hr />
2832
              </div>';
2833
    }
2834
2835
    /**
2836
     * @param string $fileName
2837
     * @param string $fileUrl
2838
     *
2839
     * @return string
2840
     */
2841
    public static function fileHtmlGuesser($fileName, $fileUrl)
2842
    {
2843
        $data = pathinfo($fileName);
2844
2845
        //$content = self::url($data['basename'], $fileUrl);
2846
        $content = '';
2847
        switch ($data['extension']) {
2848
            case 'webm':
2849
            case 'mp4':
2850
            case 'ogg':
2851
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2852
                // Allows video to play when loading during an ajax call
2853
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2854
                break;
2855
            case 'jpg':
2856
            case 'jpeg':
2857
            case 'gif':
2858
            case 'png':
2859
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2860
                break;
2861
            default:
2862
                //$html = self::url($data['basename'], $fileUrl);
2863
                break;
2864
        }
2865
        //$html = self::url($content, $fileUrl, ['ajax']);
2866
2867
        return $content;
2868
    }
2869
2870
    public static function getFrameReadyBlock(
2871
        string $frameName,
2872
        string $itemType = '',
2873
        string $jsConditionalFunction = 'function () { return false; }'
2874
    ): string {
2875
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2876
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
2877
2878
        $videoFeatures = [
2879
            'playpause',
2880
            'current',
2881
            'progress',
2882
            'duration',
2883
            'tracks',
2884
            'volume',
2885
            'fullscreen',
2886
            'vrview',
2887
            'markersrolls',
2888
        ];
2889
        $features = api_get_configuration_value('video_features');
2890
        $videoPluginsJS = [];
2891
        $videoPluginCSS = [];
2892
        if (!empty($features) && isset($features['features'])) {
2893
            foreach ($features['features'] as $feature) {
2894
                if ($feature === 'vrview') {
2895
                    continue;
2896
                }
2897
                $defaultFeatures[] = $feature;
2898
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.min.js";
2899
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.min.css";
2900
            }
2901
        }
2902
2903
        $videoPluginFiles = '';
2904
        foreach ($videoPluginsJS as $file) {
2905
            $videoPluginFiles .= '{type: "script", src: "'.$webJsPath.$file.'"},';
2906
        }
2907
2908
        $videoPluginCssFiles = '';
2909
        foreach ($videoPluginCSS as $file) {
2910
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webJsPath.$file.'"},';
2911
        }
2912
2913
        if ($renderers = api_get_configuration_sub_value('video_player_renderers/renderers')) {
2914
            foreach ($renderers as $renderName) {
2915
                if ('youtube' === $renderName) {
2916
                    continue;
2917
                }
2918
2919
                $file = $webPublicPath."assets/mediaelement/build/renderers/$renderName.min.js";
2920
                $videoPluginFiles .= '{type: "script", src: "'.$file.'"},';
2921
            }
2922
        }
2923
2924
        $translateHtml = '';
2925
        $translate = api_get_configuration_value('translate_html');
2926
        if ($translate) {
2927
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2928
        }
2929
2930
        $fixLinkSetting = api_get_configuration_value('lp_fix_embed_content');
2931
        $fixLink = '';
2932
        if ($fixLinkSetting) {
2933
            $fixLink = '{type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'fixlinks.js"},';
2934
        }
2935
2936
        $videoContextMenyHiddenNative = '';
2937
        $videoContextMenyHiddenMejs = '';
2938
        if (api_get_configuration_value('video_context_menu_hidden')) {
2939
            $videoContextMenyHiddenNative = '$("video").on("contextmenu", function(e) {
2940
                e.preventDefault();
2941
            });';
2942
            $videoContextMenyHiddenMejs = '$(".mejs__container").on("contextmenu", function(e) {
2943
                e.preventDefault();
2944
            });';
2945
        }
2946
2947
        $videoFeatures = implode("','", $videoFeatures);
2948
        $frameReady = '
2949
        $.frameReady(function() {
2950
             $(function () {
2951
                '.$videoContextMenyHiddenNative.'
2952
2953
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2954
                    pluginPath: "'.$webJsPath.'mediaelement/plugins/",
2955
                    features: [\''.$videoFeatures.'\'],
2956
                    success: function(mediaElement, originalNode, instance) {
2957
                        '.$videoContextMenyHiddenMejs.PHP_EOL.ChamiloApi::getQuizMarkersRollsJS().'
2958
                    },
2959
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2960
                });
2961
            });
2962
        },
2963
        "'.$frameName.'",
2964
        ';
2965
2966
        if ('quiz' === $itemType) {
2967
            $jquery = '
2968
                '.$fixLink.'
2969
                {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2970
                {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2971
                {type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
2972
                    deps: [
2973
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.js"},
2974
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/markersrolls/markersrolls.min.js"},
2975
                    '.$videoPluginFiles.'
2976
                ]},
2977
                '.$translateHtml.'
2978
            ';
2979
        } else {
2980
            $jquery = '
2981
                {type:"script", src:"'.api_get_jquery_web_path().'", deps: [
2982
                '.$fixLink.'
2983
                {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2984
                {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2985
                {type:"script", src:"'.$webPublicPath.'assets/jquery-ui/jquery-ui.min.js"},
2986
                {type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
2987
                    deps: [
2988
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.js"},
2989
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/markersrolls/markersrolls.min.js"},
2990
                    '.$videoPluginFiles.'
2991
                ]},
2992
                '.$translateHtml.'
2993
            ]},';
2994
        }
2995
2996
        $frameReady .= '
2997
        [
2998
            '.$jquery.'
2999
            '.$videoPluginCssFiles.'
3000
            {type:"script", src:"'.$webPublicPath.'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
3001
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
3002
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/theme.css"},
3003
            {type:"stylesheet", src:"'.$webPublicPath.'css/dialog.css"},
3004
            {type:"stylesheet", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelementplayer.min.css"},
3005
            {type:"stylesheet", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.css"},
3006
        ], '.$jsConditionalFunction.');';
3007
3008
        return $frameReady;
3009
    }
3010
3011
    /**
3012
     * @param string $image
3013
     * @param int    $size
3014
     *
3015
     * @return string
3016
     */
3017
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
3018
    {
3019
        return self::return_icon($image, '', [], $size, false, true);
3020
    }
3021
3022
    /**
3023
     * @param string $image
3024
     * @param int    $size
3025
     * @param string $name
3026
     *
3027
     * @return string
3028
     */
3029
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
3030
    {
3031
        return self::return_icon($image, $name, [], $size);
3032
    }
3033
3034
    public static function returnHeaderWithPercentage($header, $percentage)
3035
    {
3036
        $percentHtml = sprintf(
3037
            get_lang('XPercent'),
3038
            round($percentage, 2)
3039
        );
3040
3041
        return "$header<br><small>$percentHtml</small>";
3042
    }
3043
}
3044