Passed
Push — master ( df67a3...c6e3ba )
by Julito
08:42
created

Display::img()   B

Complexity

Conditions 7
Paths 33

Size

Total Lines 39
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 33
nop 4
dl 0
loc 39
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
5
use Chamilo\CoreBundle\Entity\ExtraField;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ExtraField. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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

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

63
        /** @scrutinizer ignore-unused */ $tool_name = '',

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

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

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

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

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

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

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

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

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

Loading history...
66
    ) {
67
        ob_start();
68
69
        return true;
70
71
        $origin = api_get_origin();
0 ignored issues
show
Unused Code introduced by
$origin = api_get_origin() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
72
        $showHeader = true;
73
        if (isset($origin) && $origin == 'learnpath') {
74
            $showHeader = false;
75
        }
76
77
        self::$global_template = new Template($tool_name, $showHeader, $showHeader);
78
79
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
80
        if (empty($help)) {
81
            $currentURL = api_get_self();
82
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
83
            $toolList = self::toolList();
84
            if (!empty($matches)) {
85
                foreach ($matches as $match) {
86
                    if (in_array($match, $toolList)) {
87
                        $help = explode('_', $match);
88
                        $help = array_map('ucfirst', $help);
89
                        $help = implode('', $help);
90
                        break;
91
                    }
92
                }
93
            }
94
        }
95
96
        self::$global_template->setHelp($help);
97
98
        if (!empty(self::$preview_style)) {
99
            self::$global_template->preview_theme = self::$preview_style;
100
            self::$global_template->set_system_parameters();
101
            self::$global_template->setCssFiles();
102
            self::$global_template->set_js_files();
103
            self::$global_template->setCssCustomFiles();
104
        }
105
106
        if (!empty($page_header)) {
107
            self::$global_template->assign('header', $page_header);
108
        }
109
110
        echo self::$global_template->show_header_template();
111
    }
112
113
    /**
114
     * Displays the reduced page header (without banner).
115
     */
116
    public static function display_reduced_header()
117
    {
118
        global $show_learnpath, $tool_name;
119
        self::$global_template = new Template(
120
            $tool_name,
121
            false,
122
            false,
123
            $show_learnpath
124
        );
125
        echo self::$global_template->show_header_template();
0 ignored issues
show
Bug introduced by
The method show_header_template() does not exist on Template. ( Ignorable by Annotation )

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

125
        echo self::$global_template->/** @scrutinizer ignore-call */ show_header_template();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
126
    }
127
128
    /**
129
     * Display no header.
130
     */
131
    public static function display_no_header()
132
    {
133
        global $tool_name, $show_learnpath;
134
        $disable_js_and_css_files = true;
135
        self::$global_template = new Template(
136
            $tool_name,
137
            false,
138
            false,
139
            $show_learnpath
140
        );
141
    }
142
143
    /**
144
     * Display the page footer.
145
     */
146
    public static function display_footer()
147
    {
148
        $contents = ob_get_contents();
149
        if (ob_get_length()) {
150
            ob_end_clean();
151
        }
152
        $tpl = '@ChamiloTheme/Layout/layout_one_col.html.twig';
153
        $response = new Response();
154
        $params['content'] = $contents;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
155
        global $interbreadcrumb, $htmlHeadXtra;
156
        $params['legacy_javascript'] = $htmlHeadXtra;
157
        $params['legacy_breadcrumb'] = $interbreadcrumb;
158
159
        $flash = Display::getFlashToString();
160
        Display::cleanFlashMessages();
161
        $params['flash_messages'] = $flash;
162
163
        $content = Container::getTemplating()->render($tpl, $params);
164
        $response->setContent($content);
165
        $response->send();
166
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
167
    }
168
169
    /**
170
     * Display the page footer.
171
     */
172
    public static function display_reduced_footer()
173
    {
174
        echo self::$global_template->show_footer_js_template();
175
        echo '</body></html>';
176
    }
177
178
    /**
179
     * Displays the tool introduction of a tool.
180
     *
181
     * @author Patrick Cool <[email protected]>, Ghent University
182
     *
183
     * @param string $tool          these are the constants that are used for indicating the tools
184
     * @param array  $editor_config Optional configuration settings for the online editor.
185
     *                              return: $tool return a string array list with the "define" in main_api.lib
186
     *
187
     * @return string html code for adding an introduction
188
     */
189
    public static function display_introduction_section(
190
        $tool,
191
        $editor_config = null
192
    ) {
193
        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...
194
    }
195
196
    /**
197
     * @param string $tool
198
     * @param array  $editor_config
199
     */
200
    public static function return_introduction_section(
201
        $tool,
202
        $editor_config = null
203
    ) {
204
        $moduleId = $tool;
205
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
206
            $introduction_section = null;
207
            require api_get_path(SYS_INC_PATH).'introductionSection.inc.php';
208
209
            return $introduction_section;
210
        }
211
    }
212
213
    /**
214
     * Displays a table.
215
     *
216
     * @param array  $header          Titles for the table header
217
     *                                each item in this array can contain 3 values
218
     *                                - 1st element: the column title
219
     *                                - 2nd element: true or false (column sortable?)
220
     *                                - 3th element: additional attributes for
221
     *                                th-tag (eg for column-width)
222
     *                                - 4the element: additional attributes for the td-tags
223
     * @param array  $content         2D-array with the tables content
224
     * @param array  $sorting_options Keys are:
225
     *                                'column' = The column to use as sort-key
226
     *                                'direction' = SORT_ASC or SORT_DESC
227
     * @param array  $paging_options  Keys are:
228
     *                                'per_page_default' = items per page when switching from
229
     *                                full-    list to per-page-view
230
     *                                'per_page' = number of items to show per page
231
     *                                'page_nr' = The page to display
232
     * @param array  $query_vars      Additional variables to add in the query-string
233
     * @param array  $form_actions
234
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
235
     * @param string $tableName
236
     * @param string $tableId
237
     *
238
     * @author [email protected]
239
     */
240
    public static function display_sortable_table(
241
        $header,
242
        $content,
243
        $sorting_options = [],
244
        $paging_options = [],
245
        $query_vars = null,
246
        $form_actions = [],
247
        $style = 'table',
248
        $tableName = 'tablename',
249
        $tableId = ''
250
    ) {
251
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
252
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
253
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
254
        if (is_array($query_vars)) {
255
            $table->set_additional_parameters($query_vars);
256
        }
257
        if ($style == 'table') {
258
            if (is_array($header) && count($header) > 0) {
259
                foreach ($header as $index => $header_item) {
260
                    $table->set_header(
261
                        $index,
262
                        isset($header_item[0]) ? $header_item[0] : null,
263
                        isset($header_item[1]) ? $header_item[1] : null,
264
                        isset($header_item[2]) ? $header_item[2] : null,
265
                        isset($header_item[3]) ? $header_item[3] : null
266
                    );
267
                }
268
            }
269
            $table->set_form_actions($form_actions);
270
            $table->display();
271
        } else {
272
            $table->display_grid();
273
        }
274
    }
275
276
    /**
277
     * Returns an HTML table with sortable column (through complete page refresh).
278
     *
279
     * @param array  $header
280
     * @param array  $content         Array of row arrays
281
     * @param array  $sorting_options
282
     * @param array  $paging_options
283
     * @param array  $query_vars
284
     * @param array  $form_actions
285
     * @param string $style
286
     *
287
     * @return string HTML string for array
288
     */
289
    public static function return_sortable_table(
290
        $header,
291
        $content,
292
        $sorting_options = [],
293
        $paging_options = [],
294
        $query_vars = null,
295
        $form_actions = [],
296
        $style = 'table'
297
    ) {
298
        ob_start();
299
        self::display_sortable_table(
300
            $header,
301
            $content,
302
            $sorting_options,
303
            $paging_options,
304
            $query_vars,
305
            $form_actions,
306
            $style
307
        );
308
        $content = ob_get_contents();
309
        ob_end_clean();
310
311
        return $content;
312
    }
313
314
    /**
315
     * Shows a nice grid.
316
     *
317
     * @param string grid name (important to create css)
318
     * @param array header content
319
     * @param array array with the information to show
320
     * @param array $paging_options Keys are:
321
     *                              'per_page_default' = items per page when switching from
322
     *                              full-    list to per-page-view
323
     *                              'per_page' = number of items to show per page
324
     *                              'page_nr' = The page to display
325
     *                              'hide_navigation' =  true to hide the navigation
326
     * @param array $query_vars     Additional variables to add in the query-string
327
     * @param array $form           actions Additional variables to add in the query-string
328
     * @param mixed An array with bool values to know which columns show.
329
     * i.e: $visibility_options= array(true, false) we will only show the first column
330
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
331
     */
332
    public static function display_sortable_grid(
333
        $name,
334
        $header,
335
        $content,
336
        $paging_options = [],
337
        $query_vars = null,
338
        $form_actions = [],
339
        $visibility_options = true,
340
        $sort_data = true,
341
        $grid_class = []
342
    ) {
343
        echo self::return_sortable_grid(
344
            $name,
345
            $header,
346
            $content,
347
            $paging_options,
348
            $query_vars,
349
            $form_actions,
350
            $visibility_options,
351
            $sort_data,
352
            $grid_class
353
        );
354
    }
355
356
    /**
357
     * Gets a nice grid in html string.
358
     *
359
     * @param string grid name (important to create css)
360
     * @param array header content
361
     * @param array array with the information to show
362
     * @param array $paging_options Keys are:
363
     *                              'per_page_default' = items per page when switching from
364
     *                              full-    list to per-page-view
365
     *                              'per_page' = number of items to show per page
366
     *                              'page_nr' = The page to display
367
     *                              'hide_navigation' =  true to hide the navigation
368
     * @param array $query_vars     Additional variables to add in the query-string
369
     * @param array $form           actions Additional variables to add in the query-string
370
     * @param mixed An array with bool values to know which columns show. i.e:
371
     *  $visibility_options= array(true, false) we will only show the first column
372
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
373
     * @param bool  true for sorting data or false otherwise
374
     * @param array grid classes
375
     *
376
     * @return string html grid
377
     */
378
    public static function return_sortable_grid(
379
        $name,
380
        $header,
0 ignored issues
show
Unused Code introduced by
The parameter $header is not used and could be removed. ( Ignorable by Annotation )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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