Passed
Pull Request — preprodparkur (#4101)
by
unknown
11:59
created

Display::icon_mailto_link()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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

948
            error_log('No image provided in Display::img(). Caller info: './** @scrutinizer ignore-type */ print_r($caller, 1));
Loading history...
949
950
            return '';
951
        }
952
        // Sanitizing the parameter $image_path
953
        if ($filterPath) {
954
            $image_path = Security::filter_img_path($image_path);
955
        }
956
957
        // alt text = the image name if there is none provided (for XHTML compliance)
958
        if ($alt_text == '') {
959
            $alt_text = basename($image_path);
960
        }
961
962
        if (empty($additional_attributes)) {
963
            $additional_attributes = [];
964
        }
965
966
        $additional_attributes['src'] = $image_path;
967
968
        if (empty($additional_attributes['alt'])) {
969
            $additional_attributes['alt'] = $alt_text;
970
        }
971
        if (empty($additional_attributes['title'])) {
972
            $additional_attributes['title'] = $alt_text;
973
        }
974
975
        return self::tag('img', '', $additional_attributes);
976
    }
977
978
    /**
979
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
980
     *
981
     * @param string $tag                   the tag name
982
     * @param string $content               the tag's content
983
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
984
     *
985
     * @return string
986
     *
987
     * @author Julio Montoya 2010
988
     */
989
    public static function tag($tag, $content, $additional_attributes = [])
990
    {
991
        $attribute_list = '';
992
        // Managing the additional attributes
993
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
994
            $attribute_list = '';
995
            foreach ($additional_attributes as $key => &$value) {
996
                $attribute_list .= $key.'="'.$value.'" ';
997
            }
998
        }
999
        //some tags don't have this </XXX>
1000
        if (in_array($tag, ['img', 'input', 'br'])) {
1001
            $return_value = '<'.$tag.' '.$attribute_list.' />';
1002
        } else {
1003
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
1004
        }
1005
1006
        return $return_value;
1007
    }
1008
1009
    /**
1010
     * Creates a URL anchor.
1011
     *
1012
     * @param string $name
1013
     * @param string $url
1014
     * @param array  $attributes
1015
     *
1016
     * @return string
1017
     */
1018
    public static function url($name, $url, $attributes = [])
1019
    {
1020
        if (!empty($url)) {
1021
            $url = preg_replace('#&amp;#', '&', $url);
1022
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
1023
            $attributes['href'] = $url;
1024
        }
1025
1026
        return self::tag('a', $name, $attributes);
1027
    }
1028
1029
    /**
1030
     * Creates a div tag.
1031
     *
1032
     * @param string $content
1033
     * @param array  $attributes
1034
     *
1035
     * @return string
1036
     */
1037
    public static function div($content, $attributes = [])
1038
    {
1039
        return self::tag('div', $content, $attributes);
1040
    }
1041
1042
    /**
1043
     * Creates a span tag.
1044
     */
1045
    public static function span($content, $attributes = [])
1046
    {
1047
        return self::tag('span', $content, $attributes);
1048
    }
1049
1050
    /**
1051
     * Displays an HTML input tag.
1052
     */
1053
    public static function input($type, $name, $value, $attributes = [])
1054
    {
1055
        if (isset($type)) {
1056
            $attributes['type'] = $type;
1057
        }
1058
        if (isset($name)) {
1059
            $attributes['name'] = $name;
1060
        }
1061
        if (isset($value)) {
1062
            $attributes['value'] = $value;
1063
        }
1064
1065
        return self::tag('input', '', $attributes);
1066
    }
1067
1068
    /**
1069
     * @param $name
1070
     * @param $value
1071
     * @param array $attributes
1072
     *
1073
     * @return string
1074
     */
1075
    public static function button($name, $value, $attributes = [])
1076
    {
1077
        if (!empty($name)) {
1078
            $attributes['name'] = $name;
1079
        }
1080
1081
        return self::tag('button', $value, $attributes);
1082
    }
1083
1084
    /**
1085
     * Displays an HTML select tag.
1086
     *
1087
     * @param string $name
1088
     * @param array  $values
1089
     * @param int    $default
1090
     * @param array  $extra_attributes
1091
     * @param bool   $show_blank_item
1092
     * @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...
1093
     *
1094
     * @return string
1095
     */
1096
    public static function select(
1097
        $name,
1098
        $values,
1099
        $default = -1,
1100
        $extra_attributes = [],
1101
        $show_blank_item = true,
1102
        $blank_item_text = ''
1103
    ) {
1104
        $html = '';
1105
        $extra = '';
1106
        $default_id = 'id="'.$name.'" ';
1107
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1108
        foreach ($extra_attributes as $key => $parameter) {
1109
            if ($key == 'id') {
1110
                $default_id = '';
1111
            }
1112
            $extra .= $key.'="'.$parameter.'" ';
1113
        }
1114
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1115
1116
        if ($show_blank_item) {
1117
            if (empty($blank_item_text)) {
1118
                $blank_item_text = get_lang('Select');
1119
            } else {
1120
                $blank_item_text = Security::remove_XSS($blank_item_text);
1121
            }
1122
            $html .= self::tag(
1123
                'option',
1124
                '-- '.$blank_item_text.' --',
1125
                ['value' => '-1']
1126
            );
1127
        }
1128
        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...
1129
            foreach ($values as $key => $value) {
1130
                if (is_array($value) && isset($value['name'])) {
1131
                    $value = $value['name'];
1132
                }
1133
                $html .= '<option value="'.$key.'"';
1134
1135
                if (is_array($default)) {
1136
                    foreach ($default as $item) {
1137
                        if ($item == $key) {
1138
                            $html .= ' selected="selected"';
1139
                            break;
1140
                        }
1141
                    }
1142
                } else {
1143
                    if ($default == $key) {
1144
                        $html .= ' selected="selected"';
1145
                    }
1146
                }
1147
1148
                $html .= '>'.$value.'</option>';
1149
            }
1150
        }
1151
        $html .= '</select>';
1152
1153
        return $html;
1154
    }
1155
1156
    /**
1157
     * Creates a tab menu
1158
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1159
     * in the $htmlHeadXtra variable before the display_header
1160
     * Add this script.
1161
     *
1162
     * @example
1163
     * <script>
1164
                </script>
1165
     * @param array  $headers       list of the tab titles
1166
     * @param array  $items
1167
     * @param string $id            id of the container of the tab in the example "tabs"
1168
     * @param array  $attributes    for the ul
1169
     * @param array  $ul_attributes
1170
     * @param int    $selected
1171
     *
1172
     * @return string
1173
     */
1174
    public static function tabs(
1175
        $headers,
1176
        $items,
1177
        $id = 'tabs',
1178
        $attributes = [],
1179
        $ul_attributes = [],
1180
        $selected = ''
1181
    ) {
1182
        if (empty($headers) || count($headers) == 0) {
1183
            return '';
1184
        }
1185
1186
        $lis = '';
1187
        $i = 1;
1188
        foreach ($headers as $item) {
1189
            $active = '';
1190
            if ($i == 1) {
1191
                $active = ' active';
1192
            }
1193
1194
            if (!empty($selected)) {
1195
                $active = '';
1196
                if ($selected == $i) {
1197
                    $active = ' active';
1198
                }
1199
            }
1200
1201
            $item = self::tag(
1202
                'a',
1203
                $item,
1204
                [
1205
                    'href' => '#'.$id.'-'.$i,
1206
                    'role' => 'tab',
1207
                    'data-toggle' => 'tab',
1208
                    'id' => $id.$i,
1209
                ]
1210
            );
1211
            $ul_attributes['role'] = 'presentation';
1212
            $ul_attributes['class'] = $active;
1213
            $lis .= self::tag('li', $item, $ul_attributes);
1214
            $i++;
1215
        }
1216
1217
        $ul = self::tag(
1218
            'ul',
1219
            $lis,
1220
            [
1221
                'class' => 'nav nav-tabs tabs-margin',
1222
                'role' => 'tablist',
1223
                'id' => 'ul_'.$id,
1224
            ]
1225
        );
1226
1227
        $i = 1;
1228
        $divs = '';
1229
        foreach ($items as $content) {
1230
            $active = '';
1231
            if ($i == 1) {
1232
                $active = ' active';
1233
            }
1234
1235
            if (!empty($selected)) {
1236
                $active = '';
1237
                if ($selected == $i) {
1238
                    $active = ' active';
1239
                }
1240
            }
1241
1242
            $divs .= self::tag(
1243
                'div',
1244
                $content,
1245
                ['id' => $id.'-'.$i, 'class' => 'tab-pane '.$active, 'role' => 'tabpanel']
1246
            );
1247
            $i++;
1248
        }
1249
1250
        $attributes['id'] = $id;
1251
        $attributes['role'] = 'tabpanel';
1252
        $attributes['class'] = 'tab-wrapper';
1253
1254
        $main_div = self::tag(
1255
            'div',
1256
            $ul.self::tag('div', $divs, ['class' => 'tab-content']),
1257
            $attributes
1258
        );
1259
1260
        return $main_div;
1261
    }
1262
1263
    /**
1264
     * @param $headers
1265
     * @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...
1266
     *
1267
     * @return string
1268
     */
1269
    public static function tabsOnlyLink($headers, $selected = null)
1270
    {
1271
        $id = uniqid();
1272
        $i = 1;
1273
        $lis = null;
1274
        foreach ($headers as $item) {
1275
            $class = null;
1276
            if ($i == $selected) {
1277
                $class = 'active';
1278
            }
1279
            $item = self::tag(
1280
                'a',
1281
                $item['content'],
1282
                ['id' => $id.'-'.$i, 'href' => $item['url']]
1283
            );
1284
            $lis .= self::tag('li', $item, ['class' => $class]);
1285
            $i++;
1286
        }
1287
1288
        return self::tag(
1289
            'ul',
1290
            $lis,
1291
            ['class' => 'nav nav-tabs tabs-margin']
1292
        );
1293
    }
1294
1295
    /**
1296
     * In order to display a grid using jqgrid you have to:.
1297
     *
1298
     * @example
1299
     * After your Display::display_header function you have to add the nex javascript code:
1300
     * <script>
1301
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1302
     *   // for more information of this function check the grid_js() function
1303
     * </script>
1304
     * //Then you have to call the grid_html
1305
     * echo Display::grid_html('my_grid_name');
1306
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1307
     *
1308
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1309
     *
1310
     * @return string html
1311
     */
1312
    public static function grid_html($div_id)
1313
    {
1314
        $table = self::tag('table', '', ['id' => $div_id]);
1315
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1316
1317
        return $table;
1318
    }
1319
1320
    /**
1321
     * @param string $label
1322
     * @param string $form_item
1323
     *
1324
     * @return string
1325
     */
1326
    public static function form_row($label, $form_item)
1327
    {
1328
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1329
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1330
1331
        return self::div($label.$form_item, ['class' => 'form-group']);
1332
    }
1333
1334
    /**
1335
     * This is a wrapper to use the jqgrid in Chamilo.
1336
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1337
     * This function need to be in the ready jquery function
1338
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1339
     * In order to work this function needs the Display::grid_html function with the same div id.
1340
     *
1341
     * @param string $div_id       div id
1342
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1343
     * @param array  $column_names Visible columns (you should use get_lang).
1344
     *                             An array in which we place the names of the columns.
1345
     *                             This is the text that appears in the head of the grid (Header layer).
1346
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1347
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1348
     *                             This is the most important part of the grid.
1349
     *                             For a full description of all valid values see colModel API. See the url above.
1350
     * @param array  $extra_params extra parameters
1351
     * @param array  $data         data that will be loaded
1352
     * @param string $formatter    A string that will be appended to the JSON returned
1353
     * @param bool   $fixed_width  not implemented yet
1354
     *
1355
     * @return string the js code
1356
     */
1357
    public static function grid_js(
1358
        $div_id,
1359
        $url,
1360
        $column_names,
1361
        $column_model,
1362
        $extra_params,
1363
        $data = [],
1364
        $formatter = '',
1365
        $fixed_width = false
1366
    ) {
1367
        $obj = new stdClass();
1368
        $obj->first = 'first';
1369
1370
        if (!empty($url)) {
1371
            $obj->url = $url;
1372
        }
1373
1374
        //This line should only be used/modified in case of having characters
1375
        // encoding problems - see #6159
1376
        //$column_names = array_map("utf8_encode", $column_names);
1377
        $obj->colNames = $column_names;
1378
        $obj->colModel = $column_model;
1379
        $obj->pager = '#'.$div_id.'_pager';
1380
        $obj->datatype = 'json';
1381
        $obj->viewrecords = 'true';
1382
        $all_value = 10000000;
1383
1384
        // Sets how many records we want to view in the grid
1385
        $obj->rowNum = 20;
1386
1387
        // Default row quantity
1388
        if (!isset($extra_params['rowList'])) {
1389
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1390
            $rowList = api_get_configuration_value('table_row_list');
1391
            if (!empty($rowList) && isset($rowList['options'])) {
1392
                $rowList = $rowList['options'];
1393
                $rowList[] = $all_value;
1394
            }
1395
            $extra_params['rowList'] = $rowList;
1396
        }
1397
1398
        $defaultRow = api_get_configuration_value('table_default_row');
1399
        if (!empty($defaultRow)) {
1400
            $obj->rowNum = (int) $defaultRow;
1401
        }
1402
1403
        $json = '';
1404
        if (!empty($extra_params['datatype'])) {
1405
            $obj->datatype = $extra_params['datatype'];
1406
        }
1407
1408
        // Row even odd style.
1409
        $obj->altRows = true;
1410
        if (!empty($extra_params['altRows'])) {
1411
            $obj->altRows = $extra_params['altRows'];
1412
        }
1413
1414
        if (!empty($extra_params['sortname'])) {
1415
            $obj->sortname = $extra_params['sortname'];
1416
        }
1417
1418
        if (!empty($extra_params['sortorder'])) {
1419
            $obj->sortorder = $extra_params['sortorder'];
1420
        }
1421
1422
        if (!empty($extra_params['rowList'])) {
1423
            $obj->rowList = $extra_params['rowList'];
1424
        }
1425
1426
        if (!empty($extra_params['rowNum'])) {
1427
            $obj->rowNum = $extra_params['rowNum'];
1428
        } else {
1429
            // Try to load max rows from Session
1430
            $urlInfo = parse_url($url);
1431
            if (isset($urlInfo['query'])) {
1432
                parse_str($urlInfo['query'], $query);
1433
                if (isset($query['a'])) {
1434
                    $action = $query['a'];
1435
                    // This value is set in model.ajax.php
1436
                    $savedRows = Session::read('max_rows_'.$action);
1437
                    if (!empty($savedRows)) {
1438
                        $obj->rowNum = $savedRows;
1439
                    }
1440
                }
1441
            }
1442
        }
1443
1444
        if (!empty($extra_params['viewrecords'])) {
1445
            $obj->viewrecords = $extra_params['viewrecords'];
1446
        }
1447
1448
        $beforeSelectRow = null;
1449
        if (isset($extra_params['beforeSelectRow'])) {
1450
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1451
            unset($extra_params['beforeSelectRow']);
1452
        }
1453
1454
        $beforeProcessing = '';
1455
        if (isset($extra_params['beforeProcessing'])) {
1456
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1457
            unset($extra_params['beforeProcessing']);
1458
        }
1459
1460
        $beforeRequest = '';
1461
        if (isset($extra_params['beforeRequest'])) {
1462
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1463
            unset($extra_params['beforeRequest']);
1464
        }
1465
1466
        $gridComplete = '';
1467
        if (isset($extra_params['gridComplete'])) {
1468
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1469
            unset($extra_params['gridComplete']);
1470
        }
1471
1472
        // Adding extra params
1473
        if (!empty($extra_params)) {
1474
            foreach ($extra_params as $key => $element) {
1475
                // the groupHeaders key gets a special treatment
1476
                if ($key != 'groupHeaders') {
1477
                    $obj->$key = $element;
1478
                }
1479
            }
1480
        }
1481
1482
        // Adding static data.
1483
        if (!empty($data)) {
1484
            $data_var = $div_id.'_data';
1485
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1486
            $obj->data = $data_var;
1487
            $obj->datatype = 'local';
1488
            $json .= "\n";
1489
        }
1490
1491
        $obj->end = 'end';
1492
1493
        $json_encode = json_encode($obj);
1494
1495
        if (!empty($data)) {
1496
            //Converts the "data":"js_variable" to "data":js_variable,
1497
            // otherwise it will not work
1498
            $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...
1499
        }
1500
1501
        // Fixing true/false js values that doesn't need the ""
1502
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1503
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1504
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1505
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1506
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1507
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1508
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1509
1510
        if (api_get_configuration_value('allow_compilatio_tool') &&
1511
            (strpos($_SERVER['REQUEST_URI'], 'work/work.php') !== false ||
1512
             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...
1513
            )
1514
        ) {
1515
            $json_encode = str_replace('"function () { compilatioInit() }"',
1516
                'function () { compilatioInit() }',
1517
                $json_encode
1518
            );
1519
        }
1520
        // Creating the jqgrid element.
1521
        $json .= '$("#'.$div_id.'").jqGrid({';
1522
        //$json .= $beforeSelectRow;
1523
        $json .= $gridComplete;
1524
        $json .= $beforeProcessing;
1525
        $json .= $beforeRequest;
1526
        $json .= $json_encode;
1527
        $json .= '});';
1528
1529
        // Grouping headers option
1530
        if (isset($extra_params['groupHeaders'])) {
1531
            $groups = '';
1532
            foreach ($extra_params['groupHeaders'] as $group) {
1533
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1534
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1535
            }
1536
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1537
                "useColSpanStyle" : false,
1538
                "groupHeaders"    : [
1539
                    '.$groups.'
1540
                ]
1541
            });';
1542
        }
1543
1544
        $all_text = addslashes(get_lang('All'));
1545
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1546
        $json .= "\n";
1547
        // Adding edit/delete icons.
1548
        $json .= $formatter;
1549
1550
        return $json;
1551
    }
1552
1553
    /**
1554
     * @param array $headers
1555
     * @param array $rows
1556
     * @param array $attributes
1557
     *
1558
     * @return string
1559
     */
1560
    public static function table($headers, $rows, $attributes = [])
1561
    {
1562
        if (empty($attributes)) {
1563
            $attributes['class'] = 'data_table';
1564
        }
1565
        $table = new HTML_Table($attributes);
1566
        $row = 0;
1567
        $column = 0;
1568
1569
        // Course headers
1570
        if (!empty($headers)) {
1571
            foreach ($headers as $item) {
1572
                $table->setHeaderContents($row, $column, $item);
1573
                $column++;
1574
            }
1575
            $row = 1;
1576
            $column = 0;
1577
        }
1578
1579
        if (!empty($rows)) {
1580
            foreach ($rows as $content) {
1581
                $table->setCellContents($row, $column, $content);
1582
                $row++;
1583
            }
1584
        }
1585
1586
        return $table->toHtml();
1587
    }
1588
1589
    /**
1590
     * Returns the "what's new" icon notifications.
1591
     *
1592
     * The general logic of this function is to track the last time the user
1593
     * entered the course and compare to what has changed inside this course
1594
     * since then, based on the item_property table inside this course. Note that,
1595
     * if the user never entered the course before, he will not see notification
1596
     * icons. This function takes session ID into account (if any) and only shows
1597
     * the corresponding notifications.
1598
     *
1599
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1600
     * @param bool  $loadAjax
1601
     *
1602
     * @return string The HTML link to be shown next to the course
1603
     */
1604
    public static function show_notification($courseInfo, $loadAjax = true)
1605
    {
1606
        if (empty($courseInfo)) {
1607
            return '';
1608
        }
1609
1610
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1611
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1612
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1613
        $course_code = Database::escape_string($courseInfo['code']);
1614
1615
        $user_id = api_get_user_id();
1616
        $course_id = (int) $courseInfo['real_id'];
1617
        $sessionId = (int) $courseInfo['id_session'];
1618
        $status = (int) $courseInfo['status'];
1619
1620
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1621
1622
        if ($loadNotificationsByAjax) {
1623
            if ($loadAjax) {
1624
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1625
                Session::write($id, true);
1626
1627
                return '<span id ="'.$id.'" class="course_notification"></span>';
1628
            }
1629
        }
1630
1631
        // Get the user's last access dates to all tools of this course
1632
        $sql = "SELECT *
1633
                FROM $t_track_e_access
1634
                WHERE
1635
                    c_id = $course_id AND
1636
                    access_user_id = '$user_id' AND
1637
                    access_session_id ='".$sessionId."'
1638
                ORDER BY access_date DESC
1639
                LIMIT 1
1640
                ";
1641
        $result = Database::query($sql);
1642
1643
        // latest date by default is the creation date
1644
        $latestDate = $courseInfo['creation_date'];
1645
        if (Database::num_rows($result)) {
1646
            $row = Database::fetch_array($result, 'ASSOC');
1647
            $latestDate = $row['access_date'];
1648
        }
1649
1650
        $sessionCondition = api_get_session_condition(
1651
            $sessionId,
1652
            true,
1653
            false,
1654
            'session_id'
1655
        );
1656
1657
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1658
        // Get current tools in course
1659
        $sql = "SELECT name, link, image
1660
                FROM $course_tool_table
1661
                WHERE
1662
                    c_id = $course_id AND
1663
                    visibility = '1' AND
1664
                    name NOT IN ('".implode("','", $hideTools)."')
1665
                ";
1666
        $result = Database::query($sql);
1667
        $tools = Database::store_result($result);
1668
1669
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1670
        $group_ids[] = 0; //add group 'everyone'
1671
        $notifications = [];
1672
        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...
1673
            foreach ($tools as $tool) {
1674
                $toolName = $tool['name'];
1675
                $toolName = Database::escape_string($toolName);
1676
                // Fix to get student publications
1677
                $toolCondition = " tool = '$toolName' AND ";
1678
                if ($toolName == 'student_publication' || $toolName == 'work') {
1679
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1680
                }
1681
1682
                $toolName = addslashes($toolName);
1683
1684
                $sql = "SELECT * FROM $tool_edit_table
1685
                        WHERE
1686
                            c_id = $course_id AND
1687
                            $toolCondition
1688
                            lastedit_type NOT LIKE '%Deleted%' AND
1689
                            lastedit_type NOT LIKE '%deleted%' AND
1690
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1691
                            lastedit_date > '$latestDate' AND
1692
                            lastedit_user_id != $user_id $sessionCondition AND
1693
                            visibility != 2 AND
1694
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1695
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1696
                        ORDER BY lastedit_date DESC
1697
                        LIMIT 1";
1698
                $result = Database::query($sql);
1699
1700
                $latestChange = Database::fetch_array($result, 'ASSOC');
1701
1702
                if ($latestChange) {
1703
                    $latestChange['link'] = $tool['link'];
1704
                    $latestChange['image'] = $tool['image'];
1705
                    $latestChange['tool'] = $tool['name'];
1706
                    $notifications[$toolName] = $latestChange;
1707
                }
1708
            }
1709
        }
1710
1711
        // Show all tool icons where there is something new.
1712
        $return = '';
1713
        foreach ($notifications as $notification) {
1714
            $toolName = $notification['tool'];
1715
            if (!(
1716
                    $notification['visibility'] == '1' ||
1717
                    ($status == '1' && $notification['visibility'] == '0') ||
1718
                    !isset($notification['visibility'])
1719
                )
1720
            ) {
1721
                continue;
1722
            }
1723
1724
            if ($toolName == TOOL_SURVEY) {
1725
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1726
                if (!empty($survey_info)) {
1727
                    $invited_users = SurveyUtil::get_invited_users(
1728
                        $survey_info['code'],
1729
                        $course_code
1730
                    );
1731
                    if (!in_array($user_id, $invited_users['course_users'])) {
1732
                        continue;
1733
                    }
1734
                }
1735
            }
1736
1737
            if ($notification['tool'] == TOOL_LEARNPATH) {
1738
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1739
                    continue;
1740
                }
1741
            }
1742
1743
            if ($notification['tool'] == TOOL_DROPBOX) {
1744
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1745
            }
1746
1747
            if ($notification['tool'] == 'work' &&
1748
                $notification['lastedit_type'] == 'DirectoryCreated'
1749
            ) {
1750
                $notification['lastedit_type'] = 'WorkAdded';
1751
            }
1752
1753
            $lastDate = api_get_local_time($notification['lastedit_date']);
1754
            $type = $notification['lastedit_type'];
1755
            if ($type == 'CalendareventVisible') {
1756
                $type = 'Visible';
1757
            }
1758
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1759
1760
            if (strpos($notification['link'], '?') === false) {
1761
                $notification['link'] = $notification['link'].'?notification=1';
1762
            } else {
1763
                $notification['link'] = $notification['link'].'&notification=1';
1764
            }
1765
1766
            $image = substr($notification['image'], 0, -4).'.png';
1767
1768
            $return .= self::url(
1769
                self::return_icon($image, $label),
1770
                api_get_path(WEB_CODE_PATH).
1771
                $notification['link'].'&cidReq='.$course_code.
1772
                '&ref='.$notification['ref'].
1773
                '&gidReq='.$notification['to_group_id'].
1774
                '&id_session='.$sessionId
1775
            ).PHP_EOL;
1776
        }
1777
1778
        return $return;
1779
    }
1780
1781
    /**
1782
     * Get the session box details as an array.
1783
     *
1784
     * @param int       Session ID
1785
     *
1786
     * @return array Empty array or session array
1787
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1788
     */
1789
    public static function getSessionTitleBox($session_id)
1790
    {
1791
        global $nosession;
1792
1793
        if (!$nosession) {
1794
            global $now, $date_start, $date_end;
1795
        }
1796
        $output = [];
1797
        if (!$nosession) {
1798
            $session_info = api_get_session_info($session_id);
1799
            $coachInfo = [];
1800
            if (!empty($session['id_coach'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $session does not exist. Did you maybe mean $session_info?
Loading history...
1801
                $coachInfo = api_get_user_info($session['id_coach']);
1802
            }
1803
1804
            $session = [];
1805
            $session['category_id'] = $session_info['session_category_id'];
1806
            $session['title'] = $session_info['name'];
1807
            $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1808
            $session['dates'] = '';
1809
            $session['coach'] = '';
1810
            if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1811
                $session['coach'] = get_lang('GeneralCoach').': '.$coachInfo['complete_name'];
1812
            }
1813
1814
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1815
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1816
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1817
            ) {
1818
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1819
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1820
                    $session['duration'] = $daysLeft >= 0
1821
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1822
                        : get_lang('YourSessionTimeHasExpired');
1823
                }
1824
                $active = true;
1825
            } else {
1826
                $dates = SessionManager::parseSessionDates($session_info, true);
1827
                $session['dates'] = $dates['access'];
1828
                if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1829
                    $session['coach'] = $coachInfo['complete_name'];
1830
                }
1831
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
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 $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_end does not seem to be defined for all execution paths leading up to this point.
Loading history...
1832
            }
1833
            $session['active'] = $active;
1834
            $session['session_category_id'] = $session_info['session_category_id'];
1835
            $session['visibility'] = $session_info['visibility'];
1836
            $session['num_users'] = $session_info['nbr_users'];
1837
            $session['num_courses'] = $session_info['nbr_courses'];
1838
            $session['description'] = $session_info['description'];
1839
            $session['show_description'] = $session_info['show_description'];
1840
1841
            $entityManager = Database::getManager();
1842
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1843
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1844
                ExtraField::SESSION_FIELD_TYPE,
1845
                $session_id
1846
            );
1847
1848
            $session['extra_fields'] = [];
1849
            foreach ($extraFieldValues as $value) {
1850
                $session['extra_fields'][] = [
1851
                    'field' => [
1852
                        'variable' => $value->getField()->getVariable(),
1853
                        'display_text' => $value->getField()->getDisplayText(),
1854
                    ],
1855
                    'value' => $value->getValue(),
1856
                ];
1857
            }
1858
1859
            $output = $session;
1860
        }
1861
1862
        return $output;
1863
    }
1864
1865
    /**
1866
     * Return the five star HTML.
1867
     *
1868
     * @param string $id              of the rating ul element
1869
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1870
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1871
     * @param bool   $add_div_wrapper add a div wrapper
1872
     *
1873
     * @return string
1874
     */
1875
    public static function return_rating_system(
1876
        $id,
1877
        $url,
1878
        $point_info = [],
1879
        $add_div_wrapper = true
1880
    ) {
1881
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1882
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1883
1884
        if (!empty($percentage)) {
1885
            $percentage = $percentage * 125 / 100;
1886
        }
1887
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1888
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1889
1890
        $html = '<ul id="'.$id.'" class="star-rating">
1891
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1892
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1893
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1894
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1895
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1896
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1897
                </ul>';
1898
1899
        $labels = [];
1900
1901
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1902
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1903
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1904
1905
        if (!$add_div_wrapper && api_is_anonymous()) {
1906
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1907
        }
1908
1909
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1910
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1911
1912
        if ($add_div_wrapper) {
1913
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1914
        }
1915
1916
        return $html;
1917
    }
1918
1919
    /**
1920
     * @param string $title
1921
     * @param string $second_title
1922
     * @param string $size
1923
     * @param bool   $filter
1924
     *
1925
     * @return string
1926
     */
1927
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1928
    {
1929
        if ($filter) {
1930
            $title = Security::remove_XSS($title);
1931
        }
1932
1933
        if (!empty($second_title)) {
1934
            if ($filter) {
1935
                $second_title = Security::remove_XSS($second_title);
1936
            }
1937
            $title .= "<small> $second_title</small>";
1938
        }
1939
1940
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1941
    }
1942
1943
    public static function page_header_and_translate($title, $second_title = null)
1944
    {
1945
        $title = get_lang($title);
1946
1947
        return self::page_header($title, $second_title);
1948
    }
1949
1950
    public static function page_subheader_and_translate($title, $second_title = null)
1951
    {
1952
        $title = get_lang($title);
1953
1954
        return self::page_subheader($title, $second_title);
1955
    }
1956
1957
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1958
    {
1959
        if (!empty($second_title)) {
1960
            $second_title = Security::remove_XSS($second_title);
1961
            $title .= "<small> $second_title<small>";
1962
        }
1963
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1964
1965
        return $subTitle;
1966
    }
1967
1968
    public static function page_subheader2($title, $second_title = null)
1969
    {
1970
        return self::page_header($title, $second_title, 'h4');
1971
    }
1972
1973
    public static function page_subheader3($title, $second_title = null)
1974
    {
1975
        return self::page_header($title, $second_title, 'h5');
1976
    }
1977
1978
    /**
1979
     * @param array $list
1980
     *
1981
     * @return string|null
1982
     */
1983
    public static function description($list)
1984
    {
1985
        $html = null;
1986
        if (!empty($list)) {
1987
            $html = '<dl class="dl-horizontal">';
1988
            foreach ($list as $item) {
1989
                $html .= '<dt>'.$item['title'].'</dt>';
1990
                $html .= '<dd>'.$item['content'].'</dd>';
1991
            }
1992
            $html .= '</dl>';
1993
        }
1994
1995
        return $html;
1996
    }
1997
1998
    /**
1999
     * @param int    $percentage      int value between 0 and 100
2000
     * @param bool   $show_percentage
2001
     * @param string $extra_info
2002
     * @param string $class           danger/success/infowarning
2003
     *
2004
     * @return string
2005
     */
2006
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
2007
    {
2008
        $percentage = (int) $percentage;
2009
        $class = empty($class) ? '' : "progress-bar-$class";
2010
2011
        $div = '<div class="progress">
2012
                <div
2013
                    class="progress-bar progress-bar-striped '.$class.'"
2014
                    role="progressbar"
2015
                    aria-valuenow="'.$percentage.'"
2016
                    aria-valuemin="0"
2017
                    aria-valuemax="100"
2018
                    style="width: '.$percentage.'%;"
2019
                >';
2020
        if ($show_percentage) {
2021
            $div .= $percentage.'%';
2022
        } else {
2023
            if (!empty($extra_info)) {
2024
                $div .= $extra_info;
2025
            }
2026
        }
2027
        $div .= '</div></div>';
2028
2029
        return $div;
2030
    }
2031
2032
    /**
2033
     * @param string $count
2034
     * @param string $type
2035
     *
2036
     * @return string|null
2037
     */
2038
    public static function badge($count, $type = "warning")
2039
    {
2040
        $class = '';
2041
2042
        switch ($type) {
2043
            case 'success':
2044
                $class = 'badge-success';
2045
                break;
2046
            case 'warning':
2047
                $class = 'badge-warning';
2048
                break;
2049
            case 'important':
2050
                $class = 'badge-important';
2051
                break;
2052
            case 'info':
2053
                $class = 'badge-info';
2054
                break;
2055
            case 'inverse':
2056
                $class = 'badge-inverse';
2057
                break;
2058
        }
2059
2060
        if (!empty($count)) {
2061
            return ' <span class="badge '.$class.'">'.$count.'</span>';
2062
        }
2063
2064
        return null;
2065
    }
2066
2067
    /**
2068
     * @param array $badge_list
2069
     *
2070
     * @return string
2071
     */
2072
    public static function badge_group($badge_list)
2073
    {
2074
        $html = '<div class="badge-group">';
2075
        foreach ($badge_list as $badge) {
2076
            $html .= $badge;
2077
        }
2078
        $html .= '</div>';
2079
2080
        return $html;
2081
    }
2082
2083
    /**
2084
     * @param string $content
2085
     * @param string $type
2086
     *
2087
     * @return string
2088
     */
2089
    public static function label($content, $type = 'default')
2090
    {
2091
        switch ($type) {
2092
            case 'success':
2093
                $class = 'label-success';
2094
                break;
2095
            case 'warning':
2096
                $class = 'label-warning';
2097
                break;
2098
            case 'important':
2099
            case 'danger':
2100
                $class = 'label-danger';
2101
                break;
2102
            case 'info':
2103
                $class = 'label-info';
2104
                break;
2105
            case 'primary':
2106
                $class = 'label-primary';
2107
                break;
2108
            default:
2109
                $class = 'label-default';
2110
                break;
2111
        }
2112
2113
        $html = '';
2114
        if (!empty($content)) {
2115
            $html = '<span class="label '.$class.'">';
2116
            $html .= $content;
2117
            $html .= '</span>';
2118
        }
2119
2120
        return $html;
2121
    }
2122
2123
    /**
2124
     * @param array  $items
2125
     * @param string $class
2126
     *
2127
     * @return string|null
2128
     */
2129
    public static function actions($items, $class = 'new_actions')
2130
    {
2131
        $html = null;
2132
        if (!empty($items)) {
2133
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2134
            foreach ($items as $value) {
2135
                $class = null;
2136
                if (isset($value['active']) && $value['active']) {
2137
                    $class = 'class ="active"';
2138
                }
2139
2140
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2141
                    $class = 'class ="active"';
2142
                }
2143
                $html .= "<li $class >";
2144
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2145
                $html .= self::url($value['content'], $value['url'], $attributes);
2146
                $html .= '</li>';
2147
            }
2148
            $html .= '</ul></div>';
2149
            $html .= '<br />';
2150
        }
2151
2152
        return $html;
2153
    }
2154
2155
    /**
2156
     * Prints a tooltip.
2157
     *
2158
     * @param string $text
2159
     * @param string $tip
2160
     *
2161
     * @return string
2162
     */
2163
    public static function tip($text, $tip)
2164
    {
2165
        if (empty($tip)) {
2166
            return $text;
2167
        }
2168
2169
        return self::span(
2170
            $text,
2171
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2172
        );
2173
    }
2174
2175
    /**
2176
     * @param array  $items
2177
     * @param string $type
2178
     * @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...
2179
     *
2180
     * @return string|null
2181
     */
2182
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2183
    {
2184
        $html = null;
2185
        if (!empty($items)) {
2186
            if (empty($id)) {
2187
                $id = api_get_unique_id();
2188
            }
2189
            if ($type == 'jquery') {
2190
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2191
            } else {
2192
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2193
            }
2194
2195
            $count = 1;
2196
            foreach ($items as $item) {
2197
                $html .= '<div class="accordion-my-group">';
2198
                $html .= '<div class="accordion-heading">
2199
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2200
                            '.$item['title'].'
2201
                            </a>
2202
                          </div>';
2203
2204
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2205
                $html .= '<div class="accordion-my-inner">
2206
                            '.$item['content'].'
2207
                            </div>
2208
                          </div>';
2209
            }
2210
            $html .= '</div>';
2211
        }
2212
2213
        return $html;
2214
    }
2215
2216
    /**
2217
     * @param array $buttons
2218
     *
2219
     * @return string
2220
     */
2221
    public static function groupButton($buttons)
2222
    {
2223
        $html = '<div class="btn-group" role="group">';
2224
        foreach ($buttons as $button) {
2225
            $html .= $button;
2226
        }
2227
        $html .= '</div>';
2228
2229
        return $html;
2230
    }
2231
2232
    /**
2233
     * @todo use twig
2234
     *
2235
     * @param string $title
2236
     * @param array  $elements
2237
     * @param bool   $alignToRight
2238
     *
2239
     * @return string
2240
     */
2241
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2242
    {
2243
        $html = '<div class="btn-group">
2244
                <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
2245
                '.$title.'
2246
                <span class="caret"></span></button>
2247
                <ul class="dropdown-menu '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2248
        foreach ($elements as $item) {
2249
            $html .= self::tag('li', self::url($item['title'], $item['href']));
2250
        }
2251
        $html .= '</ul>
2252
            </div>';
2253
2254
        return $html;
2255
    }
2256
2257
    /**
2258
     * @param string $file
2259
     * @param array  $params
2260
     *
2261
     * @return string|null
2262
     */
2263
    public static function getMediaPlayer($file, $params = [])
2264
    {
2265
        $fileInfo = pathinfo($file);
2266
2267
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2268
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2269
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2270
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2271
2272
        switch ($fileInfo['extension']) {
2273
            case 'mp3':
2274
            case 'webm':
2275
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2276
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2277
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2278
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2279
                          </object>';
2280
                $html .= '</audio>';
2281
2282
                return $html;
2283
                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...
2284
            case 'wav':
2285
            case 'ogg':
2286
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2287
2288
                return $html;
2289
                break;
2290
        }
2291
2292
        return null;
2293
    }
2294
2295
    /**
2296
     * @param int    $nextValue
2297
     * @param array  $list
2298
     * @param int    $current
2299
     * @param int    $fixedValue
2300
     * @param array  $conditions
2301
     * @param string $link
2302
     * @param bool   $isMedia
2303
     * @param bool   $addHeaders
2304
     * @param array  $linkAttributes
2305
     *
2306
     * @return string
2307
     */
2308
    public static function progressPaginationBar(
2309
        $nextValue,
2310
        $list,
2311
        $current,
2312
        $fixedValue = null,
2313
        $conditions = [],
2314
        $link = null,
2315
        $isMedia = false,
2316
        $addHeaders = true,
2317
        $linkAttributes = []
2318
    ) {
2319
        if ($addHeaders) {
2320
            $pagination_size = 'pagination-mini';
2321
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2322
        } else {
2323
            $html = null;
2324
        }
2325
        $affectAllItems = false;
2326
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2327
            $affectAllItems = true;
2328
        }
2329
        $localCounter = 0;
2330
        foreach ($list as $itemId) {
2331
            $isCurrent = false;
2332
            if ($affectAllItems) {
2333
                $isCurrent = true;
2334
            } else {
2335
                if (!$isMedia) {
2336
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2337
                }
2338
            }
2339
            $html .= self::parsePaginationItem(
2340
                $itemId,
2341
                $isCurrent,
2342
                $conditions,
2343
                $link,
2344
                $nextValue,
2345
                $isMedia,
2346
                $localCounter,
2347
                $fixedValue,
2348
                $linkAttributes
2349
            );
2350
            $localCounter++;
2351
        }
2352
        if ($addHeaders) {
2353
            $html .= '</ul></div>';
2354
        }
2355
2356
        return $html;
2357
    }
2358
2359
    /**
2360
     * @param int    $itemId
2361
     * @param bool   $isCurrent
2362
     * @param array  $conditions
2363
     * @param string $link
2364
     * @param int    $nextValue
2365
     * @param bool   $isMedia
2366
     * @param int    $localCounter
2367
     * @param int    $fixedValue
2368
     * @param array  $linkAttributes
2369
     *
2370
     * @return string
2371
     */
2372
    public static function parsePaginationItem(
2373
        $itemId,
2374
        $isCurrent,
2375
        $conditions,
2376
        $link,
2377
        $nextValue = 0,
2378
        $isMedia = false,
2379
        $localCounter = null,
2380
        $fixedValue = null,
2381
        $linkAttributes = []
2382
    ) {
2383
        $defaultClass = 'before';
2384
        $class = $defaultClass;
2385
        foreach ($conditions as $condition) {
2386
            $array = isset($condition['items']) ? $condition['items'] : [];
2387
            $class_to_applied = $condition['class'];
2388
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2389
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2390
            switch ($type) {
2391
                case 'positive':
2392
                    if (in_array($itemId, $array)) {
2393
                        if ($mode == 'overwrite') {
2394
                            $class = " $defaultClass $class_to_applied";
2395
                        } else {
2396
                            $class .= " $class_to_applied";
2397
                        }
2398
                    }
2399
                    break;
2400
                case 'negative':
2401
                    if (!in_array($itemId, $array)) {
2402
                        if ($mode == 'overwrite') {
2403
                            $class = " $defaultClass $class_to_applied";
2404
                        } else {
2405
                            $class .= " $class_to_applied";
2406
                        }
2407
                    }
2408
                    break;
2409
            }
2410
        }
2411
        if ($isCurrent) {
2412
            $class = 'before current';
2413
        }
2414
        if ($isMedia && $isCurrent) {
2415
            $class = 'before current';
2416
        }
2417
        if (empty($link)) {
2418
            $link_to_show = '#';
2419
        } else {
2420
            $link_to_show = $link.($nextValue + $localCounter);
2421
        }
2422
        $label = $nextValue + $localCounter + 1;
2423
        if ($isMedia) {
2424
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2425
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2426
        }
2427
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2428
2429
        return  '<li class = "'.$class.'">'.$link.'</li>';
2430
    }
2431
2432
    /**
2433
     * @param int $current
2434
     * @param int $total
2435
     *
2436
     * @return string
2437
     */
2438
    public static function paginationIndicator($current, $total)
2439
    {
2440
        $html = null;
2441
        if (!empty($current) && !empty($total)) {
2442
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2443
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2444
        }
2445
2446
        return $html;
2447
    }
2448
2449
    /**
2450
     * Adds a message in the queue.
2451
     *
2452
     * @param string $message
2453
     */
2454
    public static function addFlash($message)
2455
    {
2456
        $messages = Session::read('flash_messages');
2457
        if (empty($messages)) {
2458
            $messages[] = $message;
2459
        } else {
2460
            array_push($messages, $message);
2461
        }
2462
        Session::write('flash_messages', $messages);
2463
    }
2464
2465
    /**
2466
     * @return string
2467
     */
2468
    public static function getFlashToString()
2469
    {
2470
        $messages = Session::read('flash_messages');
2471
        $messageToString = '';
2472
        if (!empty($messages)) {
2473
            foreach ($messages as $message) {
2474
                $messageToString .= $message;
2475
            }
2476
        }
2477
2478
        return $messageToString;
2479
    }
2480
2481
    /**
2482
     * Shows the message from the session.
2483
     */
2484
    public static function showFlash()
2485
    {
2486
        echo self::getFlashToString();
2487
    }
2488
2489
    /**
2490
     * Destroys the message session.
2491
     */
2492
    public static function cleanFlashMessages()
2493
    {
2494
        Session::erase('flash_messages');
2495
    }
2496
2497
    /**
2498
     * Get the profile edition link for a user.
2499
     *
2500
     * @param int  $userId  The user id
2501
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2502
     *
2503
     * @return string The link
2504
     */
2505
    public static function getProfileEditionLink($userId, $asAdmin = false)
2506
    {
2507
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2508
        if ($asAdmin) {
2509
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2510
        }
2511
2512
        if (api_get_setting('sso_authentication') === 'true') {
2513
            $subSSOClass = api_get_setting('sso_authentication_subclass');
2514
            $objSSO = null;
2515
2516
            if (!empty($subSSOClass)) {
2517
                $file = api_get_path(SYS_CODE_PATH)."auth/sso/sso.$subSSOClass.class.php";
2518
                if (file_exists($file)) {
2519
                    require_once $file;
2520
                    $subSSOClass = 'sso'.$subSSOClass;
2521
                    $objSSO = new $subSSOClass();
2522
                } else {
2523
                    throw new Exception("$subSSOClass file not set");
2524
                }
2525
            } else {
2526
                $objSSO = new sso();
2527
            }
2528
2529
            $editProfileUrl = $objSSO->generateProfileEditingURL(
2530
                $userId,
2531
                $asAdmin
2532
            );
2533
        }
2534
2535
        return $editProfileUrl;
2536
    }
2537
2538
    /**
2539
     * Get the vCard for a user.
2540
     *
2541
     * @param int $userId The user id
2542
     *
2543
     * @return string *.*vcf file
2544
     */
2545
    public static function getVCardUserLink($userId)
2546
    {
2547
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2548
2549
        return $vCardUrl;
2550
    }
2551
2552
    /**
2553
     * @param string $content
2554
     * @param string $title
2555
     * @param string $footer
2556
     * @param string $type        primary|success|info|warning|danger
2557
     * @param string $extra
2558
     * @param string $id
2559
     * @param string $customColor
2560
     * @param string $extraClass
2561
     *
2562
     * @return string
2563
     */
2564
    public static function panel(
2565
        $content,
2566
        $title = '',
2567
        $footer = '',
2568
        $type = 'default',
2569
        $extra = '',
2570
        $id = '',
2571
        $customColor = '',
2572
        $extraClass = ''
2573
    ) {
2574
        $headerStyle = '';
2575
        if (!empty($customColor)) {
2576
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2577
        }
2578
2579
        $title = !empty($title) ? '<div class="panel-heading" '.$headerStyle.' ><h3 class="panel-title">'.$title.'</h3>'.$extra.'</div>' : '';
2580
        $footer = !empty($footer) ? '<div class="panel-footer">'.$footer.'</div>' : '';
2581
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2582
        $style = !in_array($type, $typeList) ? 'default' : $type;
2583
2584
        if (!empty($id)) {
2585
            $id = " id='$id'";
2586
        }
2587
2588
        return '
2589
            <div '.$id.' class="panel panel-'.$style.' '.$extraClass.' ">
2590
                '.$title.'
2591
                '.self::contentPanel($content).'
2592
                '.$footer.'
2593
            </div>'
2594
        ;
2595
    }
2596
2597
    /**
2598
     * @param string $content
2599
     *
2600
     * @return string
2601
     */
2602
    public static function contentPanel($content)
2603
    {
2604
        if (empty($content)) {
2605
            return '';
2606
        }
2607
2608
        return '<div class="panel-body">'.$content.'</div>';
2609
    }
2610
2611
    /**
2612
     * Get the button HTML with an Awesome Font icon.
2613
     *
2614
     * @param string $text        The button content
2615
     * @param string $url         The url to button
2616
     * @param string $icon        The Awesome Font class for icon
2617
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2618
     * @param array  $attributes  The additional attributes
2619
     * @param bool   $includeText
2620
     *
2621
     * @return string The button HTML
2622
     */
2623
    public static function toolbarButton(
2624
        $text,
2625
        $url,
2626
        $icon = 'check',
2627
        $type = 'default',
2628
        array $attributes = [],
2629
        $includeText = true
2630
    ) {
2631
        $buttonClass = "btn btn-$type";
2632
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2633
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2634
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2635
2636
        if (!$includeText) {
2637
            $text = '<span class="sr-only">'.$text.'</span>';
2638
        }
2639
2640
        return self::url("$icon $text", $url, $attributes);
2641
    }
2642
2643
    /**
2644
     * @param string $id
2645
     * @param array  $content
2646
     * @param array  $colsWidth Optional. Columns width
2647
     *
2648
     * @return string
2649
     */
2650
    public static function toolbarAction($id, $content, $colsWidth = [])
2651
    {
2652
        $col = count($content);
2653
2654
        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...
2655
            $width = 12 / $col;
2656
            array_walk($content, function () use ($width, &$colsWidth) {
2657
                $colsWidth[] = $width;
2658
            });
2659
        }
2660
2661
        $html = '<div id="'.$id.'" class="actions">';
2662
        $html .= '<div class="row">';
2663
2664
        for ($i = 0; $i < $col; $i++) {
2665
            $class = 'col-sm-'.$colsWidth[$i];
2666
2667
            if ($col > 1) {
2668
                if ($i > 0 && $i < count($content) - 1) {
2669
                    $class .= ' text-center';
2670
                } elseif ($i === count($content) - 1) {
2671
                    $class .= ' text-right';
2672
                }
2673
            }
2674
2675
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2676
        }
2677
2678
        $html .= '</div>';
2679
        $html .= '</div>';
2680
2681
        return $html;
2682
    }
2683
2684
    /**
2685
     * Get a HTML code for a icon by Font Awesome.
2686
     *
2687
     * @param string     $name            The icon name. Example: "mail-reply"
2688
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2689
     * @param bool       $fixWidth        Optional. Whether add the fw class
2690
     * @param string     $additionalClass Optional. Additional class
2691
     *
2692
     * @return string
2693
     */
2694
    public static function returnFontAwesomeIcon(
2695
        $name,
2696
        $size = '',
2697
        $fixWidth = false,
2698
        $additionalClass = ''
2699
    ) {
2700
        $className = "fa fa-$name";
2701
2702
        if ($fixWidth) {
2703
            $className .= ' fa-fw';
2704
        }
2705
2706
        switch ($size) {
2707
            case 'lg':
2708
                $className .= ' fa-lg';
2709
                break;
2710
            case 2:
2711
            case 3:
2712
            case 4:
2713
            case 5:
2714
                $className .= " fa-{$size}x";
2715
                break;
2716
        }
2717
2718
        if (!empty($additionalClass)) {
2719
            $className .= " $additionalClass";
2720
        }
2721
2722
        $icon = self::tag('em', null, ['class' => $className]);
2723
2724
        return "$icon ";
2725
    }
2726
2727
    /**
2728
     * @param string     $title
2729
     * @param string     $content
2730
     * @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...
2731
     * @param array      $params
2732
     * @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...
2733
     * @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...
2734
     * @param bool|true  $open
2735
     * @param bool|false $fullClickable
2736
     *
2737
     * @return string|null
2738
     *
2739
     * @todo rework function to easy use
2740
     */
2741
    public static function panelCollapse(
2742
        $title,
2743
        $content,
2744
        $id = null,
2745
        $params = [],
2746
        $idAccordion = null,
2747
        $idCollapse = null,
2748
        $open = true,
2749
        $fullClickable = false
2750
    ) {
2751
        if (!empty($idAccordion)) {
2752
            $headerClass = '';
2753
            $headerClass .= $fullClickable ? 'center-block ' : '';
2754
            $headerClass .= $open ? '' : 'collapsed';
2755
            $contentClass = 'panel-collapse collapse ';
2756
            $contentClass .= $open ? 'in' : '';
2757
            $ariaExpanded = $open ? 'true' : 'false';
2758
2759
            $html = <<<HTML
2760
                <div class="panel-group" id="$idAccordion" role="tablist" aria-multiselectable="true">
2761
                    <div class="panel panel-default" id="$id">
2762
                        <div class="panel-heading" role="tab">
2763
                            <h4 class="panel-title">
2764
                                <a class="$headerClass" role="button" data-toggle="collapse" data-parent="#$idAccordion" href="#$idCollapse" aria-expanded="$ariaExpanded" aria-controls="$idCollapse">$title</a>
2765
                            </h4>
2766
                        </div>
2767
                        <div id="$idCollapse" class="$contentClass" role="tabpanel">
2768
                            <div class="panel-body">$content</div>
2769
                        </div>
2770
                    </div>
2771
                </div>
2772
HTML;
2773
        } else {
2774
            if (!empty($id)) {
2775
                $params['id'] = $id;
2776
            }
2777
            $params['class'] = 'panel panel-default';
2778
            $html = null;
2779
            if (!empty($title)) {
2780
                $html .= '<div class="panel-heading">'.$title.'</div>'.PHP_EOL;
2781
            }
2782
            $html .= '<div class="panel-body">'.$content.'</div>'.PHP_EOL;
2783
            $html = self::div($html, $params);
2784
        }
2785
2786
        return $html;
2787
    }
2788
2789
    /**
2790
     * Returns the string "1 day ago" with a link showing the exact date time.
2791
     *
2792
     * @param string $dateTime in UTC or a DateTime in UTC
2793
     *
2794
     * @return string
2795
     */
2796
    public static function dateToStringAgoAndLongDate($dateTime)
2797
    {
2798
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2799
            return '';
2800
        }
2801
2802
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2803
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2804
        }
2805
2806
        return self::tip(
2807
            date_to_str_ago($dateTime),
2808
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2809
            //api_get_local_time($dateTime)
2810
        );
2811
    }
2812
2813
    /**
2814
     * @param array  $userInfo
2815
     * @param string $status
2816
     * @param string $toolbar
2817
     *
2818
     * @return string
2819
     */
2820
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2821
    {
2822
        if (empty($userInfo)) {
2823
            return '';
2824
        }
2825
2826
        if (!empty($status)) {
2827
            $status = '<div class="items-user-status">'.$status.'</div>';
2828
        }
2829
2830
        if (!empty($toolbar)) {
2831
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2832
        }
2833
2834
        return '<div id="user_card_'.$userInfo['id'].'" class="col-md-12">
2835
                    <div class="row">
2836
                        <div class="col-md-2">
2837
                            <img src="'.$userInfo['avatar'].'" class="img-responsive img-circle">
2838
                        </div>
2839
                        <div class="col-md-10">
2840
                           <p>'.$userInfo['complete_name'].'</p>
2841
                           <div class="row">
2842
                           <div class="col-md-2">
2843
                           '.$status.'
2844
                           </div>
2845
                           <div class="col-md-10">
2846
                           '.$toolbar.'
2847
                           </div>
2848
                           </div>
2849
                        </div>
2850
                    </div>
2851
                    <hr />
2852
              </div>';
2853
    }
2854
2855
    /**
2856
     * @param string $fileName
2857
     * @param string $fileUrl
2858
     *
2859
     * @return string
2860
     */
2861
    public static function fileHtmlGuesser($fileName, $fileUrl)
2862
    {
2863
        $data = pathinfo($fileName);
2864
2865
        //$content = self::url($data['basename'], $fileUrl);
2866
        $content = '';
2867
        switch ($data['extension']) {
2868
            case 'webm':
2869
            case 'mp4':
2870
            case 'ogg':
2871
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2872
                // Allows video to play when loading during an ajax call
2873
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2874
                break;
2875
            case 'jpg':
2876
            case 'jpeg':
2877
            case 'gif':
2878
            case 'png':
2879
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2880
                break;
2881
            default:
2882
                //$html = self::url($data['basename'], $fileUrl);
2883
                break;
2884
        }
2885
        //$html = self::url($content, $fileUrl, ['ajax']);
2886
2887
        return $content;
2888
    }
2889
2890
    /**
2891
     * @param string $frameName
2892
     *
2893
     * @return string
2894
     */
2895
    public static function getFrameReadyBlock($frameName)
2896
    {
2897
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2898
2899
        $videoFeatures = [
2900
            'playpause',
2901
            'current',
2902
            'progress',
2903
            'duration',
2904
            'tracks',
2905
            'volume',
2906
            'fullscreen',
2907
            'vrview',
2908
            'markersrolls',
2909
        ];
2910
        $features = api_get_configuration_value('video_features');
2911
        $videoPluginsJS = [];
2912
        $videoPluginCSS = [];
2913
        if (!empty($features) && isset($features['features'])) {
2914
            foreach ($features['features'] as $feature) {
2915
                if ($feature === 'vrview') {
2916
                    continue;
2917
                }
2918
                $defaultFeatures[] = $feature;
2919
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.js";
2920
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.css";
2921
            }
2922
        }
2923
2924
        $videoPluginFiles = '';
2925
        foreach ($videoPluginsJS as $file) {
2926
            $videoPluginFiles .= '{type: "script", src: "'.$webPublicPath.'assets/'.$file.'"},';
2927
        }
2928
2929
        $videoPluginCssFiles = '';
2930
        foreach ($videoPluginCSS as $file) {
2931
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webPublicPath.'assets/'.$file.'"},';
2932
        }
2933
2934
        $translateHtml = '';
2935
        $translateLoadFrame = '';
2936
        $translate = api_get_configuration_value('translate_html');
2937
        if ($translate) {
2938
            $translateHtml = '{type:"stylesheet", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2939
            $iframeId = 'mainFrame';
2940
            if (isset($_REQUEST['lp_id'])) {
2941
                // If it is iframe from lp view
2942
                $iframeId = 'content_id';
2943
            }
2944
            $translateLoadFrame = 'window.setTimeout(function () {
2945
                window.top.document.getElementById("'.$iframeId.'").style.display = "";
2946
            }, 1500);';
2947
        }
2948
2949
        $customCss = api_get_visual_theme();
2950
        $fileMedia = api_get_path(SYS_CSS_PATH).'themes/'.$customCss.'/mediaelement.css';
2951
        $fileCustomCssMedia = null;
2952
        if(file_exists($fileMedia)){
2953
            $fileCustomCssMedia = '{type:"stylesheet", src:"'.api_get_path(WEB_CSS_PATH).'themes/'.$customCss.'/mediaelement.css"}';
2954
        }
2955
2956
        $videoFeatures = implode("','", $videoFeatures);
2957
        $frameReady = '
2958
        $.frameReady(function() {
2959
             $(function () {
2960
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2961
                    pluginPath: "'.$webPublicPath.'assets/mediaelement/plugins/",
2962
                    features: [\''.$videoFeatures.'\'],
2963
                    success: function(mediaElement, originalNode, instance) {
2964
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2965
                    },
2966
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2967
                });
2968
                '.$translateLoadFrame.'
2969
            });
2970
        },
2971
        "'.$frameName.'",
2972
        [
2973
            {type:"script", src:"'.api_get_jquery_web_path().'", deps: [
2974
                {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2975
                {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2976
                {type:"script", src:"'.$webPublicPath.'assets/jquery-ui/jquery-ui.min.js"},
2977
                {type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
2978
                    deps: [
2979
                    {type:"script", src: "'.$webPublicPath.'assets/mediaelement/plugins/vrview/vrview.js"},
2980
                    {type:"script", src: "'.$webPublicPath.'assets/mediaelement/plugins/markersrolls/markersrolls.js"},
2981
                    '.$videoPluginFiles.'
2982
                ]}
2983
            ]},
2984
            '.$videoPluginCssFiles.'
2985
            {type:"script", src:"'.$webPublicPath.'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
2986
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
2987
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/theme.css"},
2988
            {type:"stylesheet", src:"'.$webPublicPath.'css/dialog.css"},
2989
            {type:"stylesheet", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelementplayer.min.css"},
2990
            {type:"stylesheet", src: "'.$webPublicPath.'assets/mediaelement/plugins/vrview/vrview.css"},
2991
            '.$fileCustomCssMedia.',
2992
            '.$translateHtml.'
2993
        ]);';
2994
2995
        return $frameReady;
2996
    }
2997
2998
    /**
2999
     * @param string $image
3000
     * @param int    $size
3001
     *
3002
     * @return string
3003
     */
3004
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
3005
    {
3006
        return self::return_icon($image, '', [], $size, false, true);
3007
    }
3008
3009
    /**
3010
     * @param string $image
3011
     * @param int    $size
3012
     * @param string $name
3013
     *
3014
     * @return string
3015
     */
3016
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
3017
    {
3018
        return self::return_icon($image, $name, [], $size);
3019
    }
3020
}
3021