Passed
Push — 1.11.x ( 666525...690611 )
by Julito
10:04
created

Display::getFrameReadyBlock()   C

Complexity

Conditions 10
Paths 64

Size

Total Lines 112
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 75
nc 64
nop 2
dl 0
loc 112
rs 6.6787
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* 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' || $origin == 'mobileapp')) {
68
            $showHeader = false;
69
        }
70
71
        if (Session::read('origin') == 'mobileapp') {
72
            $showHeader = false;
73
        }
74
75
        /* USER_IN_ANON_SURVEY is defined in fillsurvey.php when survey is marked as anonymous survey */
76
        $userInAnonSurvey = defined('USER_IN_ANON_SURVEY') && USER_IN_ANON_SURVEY;
77
78
        self::$global_template = new Template($tool_name, $showHeader, $showHeader, false, $userInAnonSurvey);
79
        self::$global_template->assign('user_in_anon_survey', $userInAnonSurvey);
80
81
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
82
        if (empty($help)) {
83
            $currentURL = api_get_self();
84
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
85
            $toolList = self::toolList();
86
            if (!empty($matches)) {
87
                foreach ($matches as $match) {
88
                    if (in_array($match, $toolList)) {
89
                        $help = explode('_', $match);
90
                        $help = array_map('ucfirst', $help);
91
                        $help = implode('', $help);
92
                        break;
93
                    }
94
                }
95
            }
96
        }
97
98
        self::$global_template->setHelp($help);
99
100
        if (!empty(self::$preview_style)) {
101
            self::$global_template->preview_theme = self::$preview_style;
102
            self::$global_template->set_system_parameters();
103
            self::$global_template->setCssFiles();
104
            self::$global_template->set_js_files();
105
            self::$global_template->setCssCustomFiles();
106
        }
107
108
        if (!empty($page_header)) {
109
            self::$global_template->assign('header', $page_header);
110
        }
111
112
        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...
113
    }
114
115
    /**
116
     * Displays the reduced page header (without banner).
117
     */
118
    public static function display_reduced_header()
119
    {
120
        global $show_learnpath, $tool_name;
121
        self::$global_template = new Template(
122
            $tool_name,
123
            false,
124
            false,
125
            $show_learnpath
126
        );
127
        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...
128
    }
129
130
    /**
131
     * Display no header.
132
     */
133
    public static function display_no_header()
134
    {
135
        global $tool_name, $show_learnpath;
136
        $disable_js_and_css_files = true;
137
        self::$global_template = new Template(
138
            $tool_name,
139
            false,
140
            false,
141
            $show_learnpath
142
        );
143
    }
144
145
    /**
146
     * Displays the reduced page header (without banner).
147
     */
148
    public static function set_header()
149
    {
150
        global $show_learnpath, $tool_name;
151
        self::$global_template = new Template(
152
            $tool_name,
153
            false,
154
            false,
155
            $show_learnpath
156
        );
157
    }
158
159
    /**
160
     * Display the page footer.
161
     */
162
    public static function display_footer()
163
    {
164
        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...
165
    }
166
167
    /**
168
     * Display the page footer.
169
     */
170
    public static function display_reduced_footer()
171
    {
172
        echo '</body></html>';
173
    }
174
175
    /**
176
     * Displays the tool introduction of a tool.
177
     *
178
     * @author Patrick Cool <[email protected]>, Ghent University
179
     *
180
     * @param string $tool          these are the constants that are used for indicating the tools
181
     * @param array  $editor_config Optional configuration settings for the online editor.
182
     *                              return: $tool return a string array list with the "define" in main_api.lib
183
     *
184
     * @return string html code for adding an introduction
185
     */
186
    public static function display_introduction_section(
187
        $tool,
188
        $editor_config = null
189
    ) {
190
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::return_introductio...($tool, $editor_config) targeting Display::return_introduction_section() seems to always return null.

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

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

}

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

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

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

Loading history...
191
    }
192
193
    /**
194
     * @param string $tool
195
     * @param array  $editor_config
196
     */
197
    public static function return_introduction_section(
198
        $tool,
199
        $editor_config = null
200
    ) {
201
        $moduleId = $tool;
202
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
203
            $introduction_section = null;
204
            require api_get_path(SYS_INC_PATH).'introductionSection.inc.php';
205
206
            return $introduction_section;
207
        }
208
    }
209
210
    /**
211
     * Displays a table.
212
     *
213
     * @param array  $header          Titles for the table header
214
     *                                each item in this array can contain 3 values
215
     *                                - 1st element: the column title
216
     *                                - 2nd element: true or false (column sortable?)
217
     *                                - 3th element: additional attributes for
218
     *                                th-tag (eg for column-width)
219
     *                                - 4the element: additional attributes for the td-tags
220
     * @param array  $content         2D-array with the tables content
221
     * @param array  $sorting_options Keys are:
222
     *                                'column' = The column to use as sort-key
223
     *                                'direction' = SORT_ASC or SORT_DESC
224
     * @param array  $paging_options  Keys are:
225
     *                                'per_page_default' = items per page when switching from
226
     *                                full-    list to per-page-view
227
     *                                'per_page' = number of items to show per page
228
     *                                'page_nr' = The page to display
229
     * @param array  $query_vars      Additional variables to add in the query-string
230
     * @param array  $form_actions
231
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
232
     * @param string $tableName
233
     * @param string $tableId
234
     *
235
     * @author [email protected]
236
     */
237
    public static function display_sortable_table(
238
        $header,
239
        $content,
240
        $sorting_options = [],
241
        $paging_options = [],
242
        $query_vars = null,
243
        $form_actions = [],
244
        $style = 'table',
245
        $tableName = 'tablename',
246
        $tableId = ''
247
    ) {
248
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
249
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
250
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
251
        if (is_array($query_vars)) {
252
            $table->set_additional_parameters($query_vars);
253
        }
254
        if ($style === 'table') {
255
            if (is_array($header) && count($header) > 0) {
256
                foreach ($header as $index => $header_item) {
257
                    $table->set_header(
258
                        $index,
259
                        isset($header_item[0]) ? $header_item[0] : null,
260
                        isset($header_item[1]) ? $header_item[1] : null,
261
                        isset($header_item[2]) ? $header_item[2] : null,
262
                        isset($header_item[3]) ? $header_item[3] : null
263
                    );
264
                }
265
            }
266
            $table->set_form_actions($form_actions);
267
            $table->display();
268
        } else {
269
            $table->display_grid();
270
        }
271
    }
272
273
    /**
274
     * Returns an HTML table with sortable column (through complete page refresh).
275
     *
276
     * @param array  $header
277
     * @param array  $content         Array of row arrays
278
     * @param array  $sorting_options
279
     * @param array  $paging_options
280
     * @param array  $query_vars
281
     * @param array  $form_actions
282
     * @param string $style
283
     *
284
     * @return string HTML string for array
285
     */
286
    public static function return_sortable_table(
287
        $header,
288
        $content,
289
        $sorting_options = [],
290
        $paging_options = [],
291
        $query_vars = null,
292
        $form_actions = [],
293
        $style = 'table'
294
    ) {
295
        ob_start();
296
        self::display_sortable_table(
297
            $header,
298
            $content,
299
            $sorting_options,
300
            $paging_options,
301
            $query_vars,
302
            $form_actions,
303
            $style
304
        );
305
        $content = ob_get_contents();
306
        ob_end_clean();
307
308
        return $content;
309
    }
310
311
    /**
312
     * Shows a nice grid.
313
     *
314
     * @param string grid name (important to create css)
315
     * @param array header content
316
     * @param array array with the information to show
317
     * @param array $paging_options Keys are:
318
     *                              'per_page_default' = items per page when switching from
319
     *                              full-    list to per-page-view
320
     *                              'per_page' = number of items to show per page
321
     *                              'page_nr' = The page to display
322
     *                              'hide_navigation' =  true to hide the navigation
323
     * @param array $query_vars     Additional variables to add in the query-string
324
     * @param array $form_actions   actions Additional variables to add in the query-string
325
     * @param mixed An array with bool values to know which columns show.
326
     * i.e: $visibility_options= array(true, false) we will only show the first column
327
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
328
     */
329
    public static function display_sortable_grid(
330
        $name,
331
        $header,
332
        $content,
333
        $paging_options = [],
334
        $query_vars = null,
335
        $form_actions = [],
336
        $visibility_options = true,
337
        $sort_data = true,
338
        $grid_class = []
339
    ) {
340
        echo self::return_sortable_grid(
341
            $name,
342
            $header,
343
            $content,
344
            $paging_options,
345
            $query_vars,
346
            $form_actions,
347
            $visibility_options,
348
            $sort_data,
349
            $grid_class
350
        );
351
    }
352
353
    /**
354
     * Gets a nice grid in html string.
355
     *
356
     * @param string grid name (important to create css)
357
     * @param array header content
358
     * @param array array with the information to show
359
     * @param array $paging_options Keys are:
360
     *                              'per_page_default' = items per page when switching from
361
     *                              full-    list to per-page-view
362
     *                              'per_page' = number of items to show per page
363
     *                              'page_nr' = The page to display
364
     *                              'hide_navigation' =  true to hide the navigation
365
     * @param array $query_vars     Additional variables to add in the query-string
366
     * @param mixed An array with bool values to know which columns show. i.e:
367
     *  $visibility_options= array(true, false) we will only show the first column
368
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
369
     * @param bool  true for sorting data or false otherwise
370
     * @param array grid classes
371
     *
372
     * @return string html grid
373
     */
374
    public static function return_sortable_grid(
375
        $name,
376
        $header,
377
        $content,
378
        $paging_options = [],
379
        $query_vars = null,
380
        $form_actions = [],
381
        $visibility_options = true,
382
        $sort_data = true,
383
        $grid_class = [],
384
        $elementCount = 0
385
    ) {
386
        $column = 0;
387
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
388
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
389
        $table->total_number_of_items = intval($elementCount);
390
        if (is_array($query_vars)) {
391
            $table->set_additional_parameters($query_vars);
392
        }
393
394
        return $table->display_simple_grid(
395
            $visibility_options,
396
            $paging_options['hide_navigation'],
397
            $default_items_per_page,
398
            $sort_data,
399
            $grid_class
400
        );
401
    }
402
403
    /**
404
     * Displays a table with a special configuration.
405
     *
406
     * @param array $header          Titles for the table header
407
     *                               each item in this array can contain 3 values
408
     *                               - 1st element: the column title
409
     *                               - 2nd element: true or false (column sortable?)
410
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
411
     *                               - 4the element: additional attributes for the td-tags
412
     * @param array $content         2D-array with the tables content
413
     * @param array $sorting_options Keys are:
414
     *                               'column' = The column to use as sort-key
415
     *                               'direction' = SORT_ASC or SORT_DESC
416
     * @param array $paging_options  Keys are:
417
     *                               'per_page_default' = items per page when switching from full list to per-page-view
418
     *                               'per_page' = number of items to show per page
419
     *                               'page_nr' = The page to display
420
     * @param array $query_vars      Additional variables to add in the query-string
421
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
422
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
423
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
424
     * @param array $form_actions    Set optional forms actions
425
     *
426
     * @author Julio Montoya
427
     */
428
    public static function display_sortable_config_table(
429
        $table_name,
430
        $header,
431
        $content,
432
        $sorting_options = [],
433
        $paging_options = [],
434
        $query_vars = null,
435
        $column_show = [],
436
        $column_order = [],
437
        $form_actions = []
438
    ) {
439
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
440
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
441
442
        $table = new SortableTableFromArrayConfig(
443
            $content,
444
            $column,
445
            $default_items_per_page,
446
            $table_name,
447
            $column_show,
448
            $column_order
449
        );
450
451
        if (is_array($query_vars)) {
452
            $table->set_additional_parameters($query_vars);
453
        }
454
        // Show or hide the columns header
455
        if (is_array($column_show)) {
456
            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...
457
                if (!empty($column_show[$i])) {
458
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
459
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
460
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
461
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
462
                    $table->set_header($i, $val0, $val1, $val2, $val3);
463
                }
464
            }
465
        }
466
        $table->set_form_actions($form_actions);
467
        $table->display();
468
    }
469
470
    /**
471
     * @param string $message
472
     * @param string $type
473
     * @param bool   $filter
474
     */
475
    public static function return_message_and_translate(
476
        $message,
477
        $type = 'normal',
478
        $filter = true
479
    ) {
480
        $message = get_lang($message);
481
        echo self::return_message($message, $type, $filter);
482
    }
483
484
    /**
485
     * Returns a div html string with.
486
     *
487
     * @param string $message
488
     * @param string $type    Example: confirm, normal, warning, error
489
     * @param bool   $filter  Whether to XSS-filter or not
490
     *
491
     * @return string Message wrapped into an HTML div
492
     */
493
    public static function return_message(
494
        $message,
495
        $type = 'normal',
496
        $filter = true
497
    ) {
498
        if (empty($message)) {
499
            return '';
500
        }
501
502
        if ($filter) {
503
            $message = api_htmlentities(
504
                $message,
505
                ENT_QUOTES,
506
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
507
            );
508
        }
509
510
        $class = '';
511
        switch ($type) {
512
            case 'warning':
513
                $class .= 'alert alert-warning';
514
                break;
515
            case 'error':
516
                $class .= 'alert alert-danger';
517
                break;
518
            case 'confirmation':
519
            case 'confirm':
520
            case 'success':
521
                $class .= 'alert alert-success';
522
                break;
523
            case 'normal':
524
            default:
525
                $class .= 'alert alert-info';
526
        }
527
528
        return self::div($message, ['class' => $class]);
529
    }
530
531
    /**
532
     * Returns an encrypted mailto hyperlink.
533
     *
534
     * @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...
535
     * @param string  clickable text
536
     * @param string  optional, class from stylesheet
537
     * @param bool $addExtraContent
538
     *
539
     * @return string encrypted mailto hyperlink
540
     */
541
    public static function encrypted_mailto_link(
542
        $email,
543
        $clickable_text = null,
544
        $style_class = '',
545
        $addExtraContent = false
546
    ) {
547
        if (is_null($clickable_text)) {
548
            $clickable_text = $email;
549
        }
550
551
        // "mailto:" already present?
552
        if (substr($email, 0, 7) !== 'mailto:') {
553
            $email = 'mailto:'.$email;
554
        }
555
556
        // Class (stylesheet) defined?
557
        if ($style_class !== '') {
558
            $style_class = ' class="'.$style_class.'"';
559
        }
560
561
        // Encrypt email
562
        $hmail = '';
563
        for ($i = 0; $i < strlen($email); $i++) {
564
            $hmail .= '&#'.ord($email[$i]).';';
565
        }
566
567
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
568
569
        if ($value) {
570
            if (api_get_setting('allow_email_editor') === 'false') {
571
                $hmail .= '?';
572
            }
573
574
            if (!api_is_anonymous()) {
575
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
576
            }
577
            if ($addExtraContent) {
578
                $content = '';
579
                if (!api_is_anonymous()) {
580
                    $userInfo = api_get_user_info();
581
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
582
583
                    $courseInfo = api_get_course_info();
584
                    if (!empty($courseInfo)) {
585
                        $content .= get_lang('Course').': ';
586
                        $content .= $courseInfo['name'];
587
                        $sessionInfo = api_get_session_info(api_get_session_id());
588
                        if (!empty($sessionInfo)) {
589
                            $content .= ' '.$sessionInfo['name'].' <br />';
590
                        }
591
                    }
592
                }
593
594
                if (!empty($content)) {
595
                    $hmail .= '&body='.rawurlencode($content);
596
                }
597
            }
598
        }
599
600
        $hclickable_text = '';
601
        // Encrypt clickable text if @ is present
602
        if (strpos($clickable_text, '@')) {
603
            for ($i = 0; $i < strlen($clickable_text); $i++) {
604
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
605
            }
606
        } else {
607
            $hclickable_text = @htmlspecialchars(
608
                $clickable_text,
609
                ENT_QUOTES,
610
                api_get_system_encoding()
611
            );
612
        }
613
        // Return encrypted mailto hyperlink
614
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
615
    }
616
617
    /**
618
     * Returns an mailto icon hyperlink.
619
     *
620
     * @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...
621
     * @param string  icon source file from the icon lib
622
     * @param int  icon size from icon lib
623
     * @param string  optional, class from stylesheet
624
     *
625
     * @return string encrypted mailto hyperlink
626
     */
627
    public static function icon_mailto_link(
628
        $email,
629
        $icon_file = "mail.png",
630
        $icon_size = 22,
631
        $style_class = ''
632
    ) {
633
        // "mailto:" already present?
634
        if (substr($email, 0, 7) != 'mailto:') {
635
            $email = 'mailto:'.$email;
636
        }
637
        // Class (stylesheet) defined?
638
        if ($style_class != '') {
639
            $style_class = ' class="'.$style_class.'"';
640
        }
641
        // Encrypt email
642
        $hmail = '';
643
        for ($i = 0; $i < strlen($email); $i++) {
644
            $hmail .= '&#'.ord($email[
645
            $i]).';';
646
        }
647
        // icon html code
648
        $icon_html_source = self::return_icon(
649
            $icon_file,
650
            $hmail,
651
            '',
652
            $icon_size
653
        );
654
        // Return encrypted mailto hyperlink
655
656
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
657
    }
658
659
    /**
660
     * Prints an <option>-list with all letters (A-Z).
661
     *
662
     * @todo This is English language specific implementation.
663
     * It should be adapted for the other languages.
664
     *
665
     * @return string
666
     */
667
    public static function get_alphabet_options($selectedLetter = '')
668
    {
669
        $result = '';
670
        for ($i = 65; $i <= 90; $i++) {
671
            $letter = chr($i);
672
            $result .= '<option value="'.$letter.'"';
673
            if ($selectedLetter == $letter) {
674
                $result .= ' selected="selected"';
675
            }
676
            $result .= '>'.$letter.'</option>';
677
        }
678
679
        return $result;
680
    }
681
682
    /**
683
     * Get the options withing a select box within the given values.
684
     *
685
     * @param int   Min value
686
     * @param int   Max value
687
     * @param int   Default value
688
     *
689
     * @return string HTML select options
690
     */
691
    public static function get_numeric_options($min, $max, $selected_num = 0)
692
    {
693
        $result = '';
694
        for ($i = $min; $i <= $max; $i++) {
695
            $result .= '<option value="'.$i.'"';
696
            if (is_int($selected_num)) {
697
                if ($selected_num == $i) {
698
                    $result .= ' selected="selected"';
699
                }
700
            }
701
            $result .= '>'.$i.'</option>';
702
        }
703
704
        return $result;
705
    }
706
707
    /**
708
     * This public function displays an icon.
709
     *
710
     * @param string   The filename of the file (in the main/img/ folder
711
     * @param string   The alt text (probably a language variable)
712
     * @param array    additional attributes (for instance height, width, onclick, ...)
713
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
714
     */
715
    public static function display_icon(
716
        $image,
717
        $alt_text = '',
718
        $additional_attributes = [],
719
        $size = null
720
    ) {
721
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
722
    }
723
724
    /**
725
     * Gets the path of an icon.
726
     *
727
     * @param string $icon
728
     * @param int    $size
729
     *
730
     * @return string
731
     */
732
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
733
    {
734
        return self::return_icon($icon, null, null, $size, null, true, false);
735
    }
736
737
    /**
738
     * This public function returns the HTML code for an icon.
739
     *
740
     * @param string $image                 The filename of the file (in the main/img/ folder
741
     * @param string $alt_text              The alt text (probably a language variable)
742
     * @param array  $additional_attributes Additional attributes (for instance height, width, onclick, ...)
743
     * @param int    $size                  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
744
     * @param bool   $show_text             Whether to show the text next (usually under) the icon
745
     * @param bool   $return_only_path      Whether we only want the path to the icon or the whole HTML tag
746
     * @param bool   $loadThemeIcon         Whether we want to allow an overloaded theme icon, if it exists, to replace the default icon
747
     *
748
     * @return string An HTML string of the right <img> tag
749
     *
750
     * @author Patrick Cool <[email protected]>, Ghent University 2006
751
     * @author Julio Montoya 2010 Function improved, adding image constants
752
     * @author Yannick Warnier 2011 Added size handler
753
     *
754
     * @version Feb 2011
755
     */
756
    public static function return_icon(
757
        $image,
758
        $alt_text = '',
759
        $additional_attributes = [],
760
        $size = ICON_SIZE_SMALL,
761
        $show_text = true,
762
        $return_only_path = false,
763
        $loadThemeIcon = true
764
    ) {
765
        $code_path = api_get_path(SYS_CODE_PATH);
766
        $w_code_path = api_get_path(WEB_CODE_PATH);
767
        // The following path is checked to see if the file exist. It's
768
        // important to use the public path (i.e. web/css/) rather than the
769
        // internal path (/app/Resource/public/css/) because the path used
770
        // in the end must be the public path
771
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
772
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
773
774
        // Avoid issues with illegal string offset for legacy calls to this
775
        // method with an empty string rather than null or an empty array
776
        if (empty($additional_attributes)) {
777
            $additional_attributes = [];
778
        }
779
780
        $image = trim($image);
781
782
        if (isset($size)) {
783
            $size = intval($size);
784
        } else {
785
            $size = ICON_SIZE_SMALL;
786
        }
787
788
        $size_extra = $size.'/';
789
        $icon = $w_code_path.'img/'.$image;
790
        $theme = 'themes/chamilo/icons/';
791
792
        if ($loadThemeIcon) {
793
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
794
            if (is_file($alternateCssPath.$theme.$image)) {
795
                $icon = $alternateWebCssPath.$theme.$image;
796
            }
797
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
798
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
799
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
800
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
801
                //Checking the main/img/icons/XXX/ folder
802
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
803
            }
804
        } else {
805
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
806
                // Checking the main/img/icons/XXX/ folder
807
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
808
            }
809
        }
810
811
        // Special code to enable SVG - refs #7359 - Needs more work
812
        // The code below does something else to "test out" SVG: for each icon,
813
        // it checks if there is an SVG version. If so, it uses it.
814
        // When moving this to production, the return_icon() calls should
815
        // ask for the SVG version directly
816
        $svgIcons = api_get_setting('icons_mode_svg');
817
        if ($svgIcons === 'true' && $return_only_path == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
818
            $svgImage = substr($image, 0, -3).'svg';
819
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
820
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
821
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
822
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
823
            }
824
825
            if (empty($additional_attributes['height'])) {
826
                $additional_attributes['height'] = $size;
827
            }
828
            if (empty($additional_attributes['width'])) {
829
                $additional_attributes['width'] = $size;
830
            }
831
        }
832
833
        $icon = api_get_cdn_path($icon);
834
835
        if ($return_only_path) {
836
            return $icon;
837
        }
838
839
        $img = self::img($icon, $alt_text, $additional_attributes);
840
        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...
841
            if ($show_text) {
842
                $img = "$img $alt_text";
843
            }
844
        }
845
846
        return $img;
847
    }
848
849
    /**
850
     * Returns the HTML code for an image.
851
     *
852
     * @param string $image_path            the filename of the file (in the main/img/ folder
853
     * @param string $alt_text              the alt text (probably a language variable)
854
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
855
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
856
     *
857
     * @return string
858
     *
859
     * @author Julio Montoya 2010
860
     */
861
    public static function img(
862
        $image_path,
863
        $alt_text = '',
864
        $additional_attributes = null,
865
        $filterPath = true
866
    ) {
867
        if (empty($image_path)) {
868
            // For some reason, the call to img() happened without a proper
869
            // image. Log the error and return an empty string to avoid
870
            // breaking the HTML
871
            $trace = debug_backtrace();
872
            $caller = $trace[1];
873
            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

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