Completed
Push — master ( 8b2aa0...562606 )
by Julito
09:06
created

Display::progressPaginationBar()   B

Complexity

Conditions 10
Paths 40

Size

Total Lines 49
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 30
nc 40
nop 9
dl 0
loc 49
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
        /* USER_IN_ANON_SURVEY is defined in fillsurvey.php when survey is marked as anonymous survey */
78
        $userInAnonSurvey = defined('USER_IN_ANON_SURVEY') && USER_IN_ANON_SURVEY;
79
80
        self::$global_template = new Template($tool_name, $showHeader, $showHeader, false, $userInAnonSurvey);
81
        self::$global_template->assign('user_in_anon_survey', $userInAnonSurvey);
82
83
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
84
        if (empty($help)) {
85
            $currentURL = api_get_self();
86
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
87
            $toolList = self::toolList();
88
            if (!empty($matches)) {
89
                foreach ($matches as $match) {
90
                    if (in_array($match, $toolList)) {
91
                        $help = explode('_', $match);
92
                        $help = array_map('ucfirst', $help);
93
                        $help = implode('', $help);
94
                        break;
95
                    }
96
                }
97
            }
98
        }
99
100
        self::$global_template->setHelp($help);
101
102
        if (!empty(self::$preview_style)) {
103
            self::$global_template->preview_theme = self::$preview_style;
104
            self::$global_template->set_system_parameters();
105
            self::$global_template->setCssFiles();
106
            self::$global_template->set_js_files();
107
            self::$global_template->setCssCustomFiles();
108
        }
109
110
        if (!empty($page_header)) {
111
            self::$global_template->assign('header', $page_header);
112
        }
113
114
        echo self::$global_template->show_header_template();
115
    }
116
117
    /**
118
     * Displays the reduced page header (without banner).
119
     */
120
    public static function display_reduced_header()
121
    {
122
        global $show_learnpath, $tool_name;
123
        self::$global_template = new Template(
124
            $tool_name,
125
            false,
126
            false,
127
            $show_learnpath
128
        );
129
        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

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

384
        /** @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...
385
        $content,
386
        $paging_options = [],
387
        $query_vars = null,
388
        $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

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

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

1290
        /** @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...
1291
    ) {
1292
        $obj = new stdClass();
1293
        $obj->first = 'first';
1294
1295
        if (!empty($url)) {
1296
            $obj->url = $url;
1297
        }
1298
1299
        // Needed it in order to render the links/html in the grid
1300
        foreach ($column_model as &$columnModel) {
1301
            if (!isset($columnModel['formatter'])) {
1302
                $columnModel['formatter'] = '';
1303
            }
1304
        }
1305
1306
        //This line should only be used/modified in case of having characters
1307
        // encoding problems - see #6159
1308
        //$column_names = array_map("utf8_encode", $column_names);
1309
        $obj->colNames = $column_names;
1310
        $obj->colModel = $column_model;
1311
        $obj->pager = '#'.$div_id.'_pager';
1312
        $obj->datatype = 'json';
1313
        $obj->viewrecords = 'true';
1314
        $obj->guiStyle = 'bootstrap4';
1315
        $obj->iconSet = 'fontAwesomeSolid';
1316
        $all_value = 10000000;
1317
1318
        // Sets how many records we want to view in the grid
1319
        $obj->rowNum = 20;
1320
1321
        // Default row quantity
1322
        if (!isset($extra_params['rowList'])) {
1323
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1324
            $rowList = api_get_configuration_value('table_row_list');
1325
            if (!empty($rowList) && isset($rowList['options'])) {
1326
                $rowList = $rowList['options'];
1327
                $rowList[] = $all_value;
1328
            }
1329
            $extra_params['rowList'] = $rowList;
1330
        }
1331
1332
        $defaultRow = api_get_configuration_value('table_default_row');
1333
        if (!empty($defaultRow)) {
1334
            $obj->rowNum = (int) $defaultRow;
1335
        }
1336
1337
        $json = '';
1338
        if (!empty($extra_params['datatype'])) {
1339
            $obj->datatype = $extra_params['datatype'];
1340
        }
1341
1342
        // Row even odd style.
1343
        $obj->altRows = true;
1344
        if (!empty($extra_params['altRows'])) {
1345
            $obj->altRows = $extra_params['altRows'];
1346
        }
1347
1348
        if (!empty($extra_params['sortname'])) {
1349
            $obj->sortname = $extra_params['sortname'];
1350
        }
1351
1352
        if (!empty($extra_params['sortorder'])) {
1353
            $obj->sortorder = $extra_params['sortorder'];
1354
        }
1355
1356
        if (!empty($extra_params['rowList'])) {
1357
            $obj->rowList = $extra_params['rowList'];
1358
        }
1359
1360
        if (!empty($extra_params['rowNum'])) {
1361
            $obj->rowNum = $extra_params['rowNum'];
1362
        } else {
1363
            // Try to load max rows from Session
1364
            $urlInfo = parse_url($url);
1365
            if (isset($urlInfo['query'])) {
1366
                parse_str($urlInfo['query'], $query);
1367
                if (isset($query['a'])) {
1368
                    $action = $query['a'];
1369
                    // This value is set in model.ajax.php
1370
                    $savedRows = Session::read('max_rows_'.$action);
1371
                    if (!empty($savedRows)) {
1372
                        $obj->rowNum = $savedRows;
1373
                    }
1374
                }
1375
            }
1376
        }
1377
1378
        if (!empty($extra_params['viewrecords'])) {
1379
            $obj->viewrecords = $extra_params['viewrecords'];
1380
        }
1381
1382
        $beforeSelectRow = null;
1383
        if (isset($extra_params['beforeSelectRow'])) {
1384
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1385
            unset($extra_params['beforeSelectRow']);
1386
        }
1387
1388
        $beforeProcessing = '';
1389
        if (isset($extra_params['beforeProcessing'])) {
1390
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1391
            unset($extra_params['beforeProcessing']);
1392
        }
1393
1394
        $beforeRequest = '';
1395
        if (isset($extra_params['beforeRequest'])) {
1396
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1397
            unset($extra_params['beforeRequest']);
1398
        }
1399
1400
        $gridComplete = '';
1401
        if (isset($extra_params['gridComplete'])) {
1402
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1403
            unset($extra_params['gridComplete']);
1404
        }
1405
1406
        // Adding extra params
1407
        if (!empty($extra_params)) {
1408
            foreach ($extra_params as $key => $element) {
1409
                // the groupHeaders key gets a special treatment
1410
                if ($key != 'groupHeaders') {
1411
                    $obj->$key = $element;
1412
                }
1413
            }
1414
        }
1415
1416
        // Adding static data.
1417
        if (!empty($data)) {
1418
            $data_var = $div_id.'_data';
1419
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1420
            $obj->data = $data_var;
1421
            $obj->datatype = 'local';
1422
            $json .= "\n";
1423
        }
1424
1425
        $obj->end = 'end';
1426
1427
        $json_encode = json_encode($obj);
1428
1429
        if (!empty($data)) {
1430
            //Converts the "data":"js_variable" to "data":js_variable,
1431
            // otherwise it will not work
1432
            $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...
1433
        }
1434
1435
        // Fixing true/false js values that doesn't need the ""
1436
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1437
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1438
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1439
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1440
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1441
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1442
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1443
1444
        if (api_get_configuration_value('allow_compilatio_tool') &&
1445
            (strpos($_SERVER['REQUEST_URI'], 'work/work.php') !== false ||
1446
             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...
1447
            )
1448
        ) {
1449
            $json_encode = str_replace('"function () { compilatioInit() }"',
1450
                'function () { compilatioInit() }',
1451
                $json_encode
1452
            );
1453
        }
1454
        // Creating the jqgrid element.
1455
        $json .= '$("#'.$div_id.'").jqGrid({';
1456
        //$json .= $beforeSelectRow;
1457
        $json .= $gridComplete;
1458
        $json .= $beforeProcessing;
1459
        $json .= $beforeRequest;
1460
        $json .= $json_encode;
1461
        $json .= '});';
1462
1463
        // Grouping headers option
1464
        if (isset($extra_params['groupHeaders'])) {
1465
            $groups = '';
1466
            foreach ($extra_params['groupHeaders'] as $group) {
1467
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1468
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1469
            }
1470
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1471
                "useColSpanStyle" : false,
1472
                "groupHeaders"    : [
1473
                    '.$groups.'
1474
                ]
1475
            });';
1476
        }
1477
1478
        $all_text = addslashes(get_lang('All'));
1479
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1480
        $json .= "\n";
1481
        // Adding edit/delete icons.
1482
        $json .= $formatter;
1483
1484
        return $json;
1485
    }
1486
1487
    /**
1488
     * @param array $headers
1489
     * @param array $rows
1490
     * @param array $attributes
1491
     *
1492
     * @return string
1493
     */
1494
    public static function table($headers, $rows, $attributes = [])
1495
    {
1496
        if (empty($attributes)) {
1497
            $attributes['class'] = 'data_table';
1498
        }
1499
        $table = new HTML_Table($attributes);
1500
        $row = 0;
1501
        $column = 0;
1502
1503
        // Course headers
1504
        if (!empty($headers)) {
1505
            foreach ($headers as $item) {
1506
                $table->setHeaderContents($row, $column, $item);
1507
                $column++;
1508
            }
1509
            $row = 1;
1510
            $column = 0;
1511
        }
1512
1513
        if (!empty($rows)) {
1514
            foreach ($rows as $content) {
1515
                $table->setCellContents($row, $column, $content);
1516
                $row++;
1517
            }
1518
        }
1519
1520
        return $table->toHtml();
1521
    }
1522
1523
    /**
1524
     * Returns the "what's new" icon notifications.
1525
     *
1526
     * The general logic of this function is to track the last time the user
1527
     * entered the course and compare to what has changed inside this course
1528
     * since then, based on the item_property table inside this course. Note that,
1529
     * if the user never entered the course before, he will not see notification
1530
     * icons. This function takes session ID into account (if any) and only shows
1531
     * the corresponding notifications.
1532
     *
1533
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1534
     * @param bool  $loadAjax
1535
     *
1536
     * @return string The HTML link to be shown next to the course
1537
     */
1538
    public static function show_notification($courseInfo, $loadAjax = true)
1539
    {
1540
        if (empty($courseInfo)) {
1541
            return '';
1542
        }
1543
1544
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1545
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1546
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1547
        $course_code = Database::escape_string($courseInfo['code']);
1548
1549
        $user_id = api_get_user_id();
1550
        $course_id = (int) $courseInfo['real_id'];
1551
        $sessionId = (int) $courseInfo['id_session'];
1552
        $status = (int) $courseInfo['status'];
1553
1554
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1555
1556
        if ($loadNotificationsByAjax) {
1557
            if ($loadAjax) {
1558
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1559
                Session::write($id, true);
1560
1561
                return '<span id ="'.$id.'" class="course_notification"></span>';
1562
            }
1563
        }
1564
1565
        // Get the user's last access dates to all tools of this course
1566
        $sql = "SELECT *
1567
                FROM $t_track_e_access
1568
                WHERE
1569
                    c_id = $course_id AND
1570
                    access_user_id = '$user_id' AND
1571
                    access_session_id ='".$sessionId."'
1572
                ORDER BY access_date DESC 
1573
                LIMIT 1
1574
                ";
1575
        $result = Database::query($sql);
1576
1577
        // latest date by default is the creation date
1578
        $latestDate = $courseInfo['creation_date'];
1579
        if (Database::num_rows($result)) {
1580
            $row = Database::fetch_array($result, 'ASSOC');
1581
            $latestDate = $row['access_date'];
1582
        }
1583
1584
        $sessionCondition = api_get_session_condition(
1585
            $sessionId,
1586
            true,
1587
            false,
1588
            'session_id'
1589
        );
1590
1591
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1592
        // Get current tools in course
1593
        $sql = "SELECT name, link, image 
1594
                FROM $course_tool_table 
1595
                WHERE 
1596
                    c_id = $course_id AND 
1597
                    visibility = '1' AND
1598
                    name NOT IN ('".implode("','", $hideTools)."')
1599
                ";
1600
        $result = Database::query($sql);
1601
        $tools = Database::store_result($result);
1602
1603
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1604
        $group_ids[] = 0; //add group 'everyone'
1605
        $notifications = [];
1606
        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...
1607
            foreach ($tools as $tool) {
1608
                $toolName = $tool['name'];
1609
                $toolName = Database::escape_string($toolName);
1610
                // Fix to get student publications
1611
                $toolCondition = " tool = '$toolName' AND ";
1612
                if ($toolName == 'student_publication' || $toolName == 'work') {
1613
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1614
                }
1615
1616
                $toolName = addslashes($toolName);
1617
1618
                $sql = "SELECT * FROM $tool_edit_table 
1619
                        WHERE
1620
                            c_id = $course_id AND
1621
                            $toolCondition
1622
                            lastedit_type NOT LIKE '%Deleted%' AND
1623
                            lastedit_type NOT LIKE '%deleted%' AND
1624
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1625
                            lastedit_date > '$latestDate' AND
1626
                            lastedit_user_id != $user_id $sessionCondition AND
1627
                            visibility != 2 AND
1628
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1629
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1630
                        ORDER BY lastedit_date DESC
1631
                        LIMIT 1";
1632
                $result = Database::query($sql);
1633
1634
                $latestChange = Database::fetch_array($result, 'ASSOC');
1635
1636
                if ($latestChange) {
1637
                    $latestChange['link'] = $tool['link'];
1638
                    $latestChange['image'] = $tool['image'];
1639
                    $latestChange['tool'] = $tool['name'];
1640
                    $notifications[$toolName] = $latestChange;
1641
                }
1642
            }
1643
        }
1644
1645
        // Show all tool icons where there is something new.
1646
        $return = '';
1647
        foreach ($notifications as $notification) {
1648
            $toolName = $notification['tool'];
1649
            if (!(
1650
                    $notification['visibility'] == '1' ||
1651
                    ($status == '1' && $notification['visibility'] == '0') ||
1652
                    !isset($notification['visibility'])
1653
                )
1654
            ) {
1655
                continue;
1656
            }
1657
1658
            if ($toolName == TOOL_SURVEY) {
1659
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1660
                if (!empty($survey_info)) {
1661
                    $invited_users = SurveyUtil::get_invited_users(
1662
                        $survey_info['code'],
1663
                        $course_code
1664
                    );
1665
                    if (!in_array($user_id, $invited_users['course_users'])) {
1666
                        continue;
1667
                    }
1668
                }
1669
            }
1670
1671
            if ($notification['tool'] == TOOL_LEARNPATH) {
1672
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1673
                    continue;
1674
                }
1675
            }
1676
1677
            if ($notification['tool'] == TOOL_DROPBOX) {
1678
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1679
            }
1680
1681
            if ($notification['tool'] == 'work' &&
1682
                $notification['lastedit_type'] == 'DirectoryCreated'
1683
            ) {
1684
                $notification['lastedit_type'] = 'WorkAdded';
1685
            }
1686
1687
            $lastDate = api_get_local_time($notification['lastedit_date']);
1688
            $type = $notification['lastedit_type'];
1689
            if ($type == 'CalendareventVisible') {
1690
                $type = 'Visible';
1691
            }
1692
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1693
1694
            if (strpos($notification['link'], '?') === false) {
1695
                $notification['link'] = $notification['link'].'?notification=1';
1696
            } else {
1697
                $notification['link'] = $notification['link'].'&notification=1';
1698
            }
1699
1700
            $image = substr($notification['image'], 0, -4).'.png';
1701
1702
            $return .= self::url(
1703
                self::return_icon($image, $label),
1704
                api_get_path(WEB_CODE_PATH).
1705
                $notification['link'].'&cidReq='.$course_code.
1706
                '&ref='.$notification['ref'].
1707
                '&gidReq='.$notification['to_group_id'].
1708
                '&id_session='.$sessionId
1709
            ).PHP_EOL;
1710
        }
1711
1712
        return $return;
1713
    }
1714
1715
    /**
1716
     * Get the session box details as an array.
1717
     *
1718
     * @param int $session_id
1719
     *
1720
     * @return array Empty array or session array
1721
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1722
     */
1723
    public static function getSessionTitleBox($session_id)
1724
    {
1725
        global $nosession;
1726
1727
        if (!$nosession) {
1728
            global $now, $date_start, $date_end;
1729
        }
1730
        $output = [];
1731
        if (!$nosession) {
1732
            $session_info = api_get_session_info($session_id);
1733
            $coachInfo = [];
1734
            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...
1735
                $coachInfo = api_get_user_info($session['id_coach']);
1736
            }
1737
1738
            $session = [];
1739
            $session['category_id'] = $session_info['session_category_id'];
1740
            $session['title'] = $session_info['name'];
1741
            $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1742
            $session['dates'] = '';
1743
            $session['coach'] = '';
1744
            if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1745
                $session['coach'] = get_lang('GeneralCoach').': '.$coachInfo['complete_name'];
1746
            }
1747
1748
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1749
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1750
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1751
            ) {
1752
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1753
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1754
                    $session['duration'] = $daysLeft >= 0
1755
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1756
                        : get_lang('YourSessionTimeHasExpired');
1757
                }
1758
                $active = true;
1759
            } else {
1760
                $dates = SessionManager::parseSessionDates($session_info, true);
1761
                $session['dates'] = $dates['access'];
1762
                if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1763
                    $session['coach'] = $coachInfo['complete_name'];
1764
                }
1765
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $date_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $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 $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
1766
            }
1767
            $session['active'] = $active;
1768
            $session['session_category_id'] = $session_info['session_category_id'];
1769
            $session['visibility'] = $session_info['visibility'];
1770
            $session['num_users'] = $session_info['nbr_users'];
1771
            $session['num_courses'] = $session_info['nbr_courses'];
1772
            $session['description'] = $session_info['description'];
1773
            $session['show_description'] = $session_info['show_description'];
1774
            $session['image'] = SessionManager::getSessionImage($session_info['id']);
0 ignored issues
show
Bug introduced by
The method getSessionImage() does not exist on SessionManager. ( Ignorable by Annotation )

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

1774
            /** @scrutinizer ignore-call */ 
1775
            $session['image'] = SessionManager::getSessionImage($session_info['id']);

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...
1775
            $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1776
1777
            $entityManager = Database::getManager();
1778
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1779
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1780
                ExtraField::SESSION_FIELD_TYPE,
1781
                $session_id
1782
            );
1783
1784
            $session['extra_fields'] = [];
1785
            /** @var \Chamilo\CoreBundle\Entity\ExtraFieldValues $value */
1786
            foreach ($extraFieldValues as $value) {
1787
                if (empty($value)) {
1788
                    continue;
1789
                }
1790
                $session['extra_fields'][] = [
1791
                    'field' => [
1792
                        'variable' => $value->getField()->getVariable(),
1793
                        'display_text' => $value->getField()->getDisplayText(),
1794
                    ],
1795
                    'value' => $value->getValue(),
1796
                ];
1797
            }
1798
1799
            $output = $session;
1800
        }
1801
1802
        return $output;
1803
    }
1804
1805
    /**
1806
     * Return the five star HTML.
1807
     *
1808
     * @param string $id              of the rating ul element
1809
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1810
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1811
     * @param bool   $add_div_wrapper add a div wrapper
1812
     *
1813
     * @return string
1814
     */
1815
    public static function return_rating_system(
1816
        $id,
1817
        $url,
1818
        $point_info = [],
1819
        $add_div_wrapper = true
1820
    ) {
1821
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1822
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1823
1824
        if (!empty($percentage)) {
1825
            $percentage = $percentage * 125 / 100;
1826
        }
1827
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1828
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1829
1830
        $html = '<section class="rating-widget">';
1831
        $html .= '<div class="rating-stars"><ul id="stars">';
1832
        $html .= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1833
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1834
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1835
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1836
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1837
        ';
1838
        $html .= '</ul></div>';
1839
        $html .= '</section>';
1840
        $labels = [];
1841
1842
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1843
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1844
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1845
1846
        if (!$add_div_wrapper && api_is_anonymous()) {
1847
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1848
        }
1849
1850
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1851
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1852
1853
        if ($add_div_wrapper) {
1854
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1855
        }
1856
1857
        return $html;
1858
    }
1859
1860
    /**
1861
     * @param string $title
1862
     * @param string $second_title
1863
     * @param string $size
1864
     * @param bool   $filter
1865
     *
1866
     * @return string
1867
     */
1868
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1869
    {
1870
        if ($filter) {
1871
            $title = Security::remove_XSS($title);
1872
        }
1873
1874
        if (!empty($second_title)) {
1875
            if ($filter) {
1876
                $second_title = Security::remove_XSS($second_title);
1877
            }
1878
            $title .= "<small> $second_title</small>";
1879
        }
1880
1881
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1882
    }
1883
1884
    public static function page_header_and_translate($title, $second_title = null)
1885
    {
1886
        $title = get_lang($title);
1887
1888
        return self::page_header($title, $second_title);
1889
    }
1890
1891
    public static function page_subheader_and_translate($title, $second_title = null)
1892
    {
1893
        $title = get_lang($title);
1894
1895
        return self::page_subheader($title, $second_title);
1896
    }
1897
1898
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1899
    {
1900
        if (!empty($second_title)) {
1901
            $second_title = Security::remove_XSS($second_title);
1902
            $title .= "<small> $second_title<small>";
1903
        }
1904
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1905
1906
        return $subTitle;
1907
    }
1908
1909
    public static function page_subheader2($title, $second_title = null)
1910
    {
1911
        return self::page_header($title, $second_title, 'h4');
1912
    }
1913
1914
    public static function page_subheader3($title, $second_title = null)
1915
    {
1916
        return self::page_header($title, $second_title, 'h5');
1917
    }
1918
1919
    /**
1920
     * @param array $list
1921
     *
1922
     * @return string|null
1923
     */
1924
    public static function description($list)
1925
    {
1926
        $html = null;
1927
        if (!empty($list)) {
1928
            $html = '<dl class="dl-horizontal">';
1929
            foreach ($list as $item) {
1930
                $html .= '<dt>'.$item['title'].'</dt>';
1931
                $html .= '<dd>'.$item['content'].'</dd>';
1932
            }
1933
            $html .= '</dl>';
1934
        }
1935
1936
        return $html;
1937
    }
1938
1939
    /**
1940
     * @param int    $percentage      int value between 0 and 100
1941
     * @param bool   $show_percentage
1942
     * @param string $extra_info
1943
     * @param string $class           danger/success/infowarning
1944
     *
1945
     * @return string
1946
     */
1947
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1948
    {
1949
        $percentage = (int) $percentage;
1950
        $class = empty($class) ? '' : "progress-bar-$class";
1951
1952
        $div = '<div class="progress">
1953
                <div
1954
                    class="progress-bar progress-bar-striped '.$class.'"
1955
                    role="progressbar"
1956
                    aria-valuenow="'.$percentage.'"
1957
                    aria-valuemin="0"
1958
                    aria-valuemax="100"
1959
                    style="width: '.$percentage.'%;"
1960
                >';
1961
        if ($show_percentage) {
1962
            $div .= $percentage.'%';
1963
        } else {
1964
            if (!empty($extra_info)) {
1965
                $div .= $extra_info;
1966
            }
1967
        }
1968
        $div .= '</div></div>';
1969
1970
        return $div;
1971
    }
1972
1973
    /**
1974
     * @param string $count
1975
     * @param string $type
1976
     *
1977
     * @return string|null
1978
     */
1979
    public static function badge($count, $type = "warning")
1980
    {
1981
        $class = '';
1982
1983
        switch ($type) {
1984
            case 'success':
1985
                $class = 'badge-success';
1986
                break;
1987
            case 'warning':
1988
                $class = 'badge-warning';
1989
                break;
1990
            case 'important':
1991
                $class = 'badge-important';
1992
                break;
1993
            case 'info':
1994
                $class = 'badge-info';
1995
                break;
1996
            case 'inverse':
1997
                $class = 'badge-inverse';
1998
                break;
1999
        }
2000
2001
        if (!empty($count)) {
2002
            return ' <span class="badge '.$class.'">'.$count.'</span>';
2003
        }
2004
2005
        return null;
2006
    }
2007
2008
    /**
2009
     * @param array $badge_list
2010
     *
2011
     * @return string
2012
     */
2013
    public static function badge_group($badge_list)
2014
    {
2015
        $html = '<div class="badge-group">';
2016
        foreach ($badge_list as $badge) {
2017
            $html .= $badge;
2018
        }
2019
        $html .= '</div>';
2020
2021
        return $html;
2022
    }
2023
2024
    /**
2025
     * @param string $content
2026
     * @param string $type
2027
     *
2028
     * @return string
2029
     */
2030
    public static function label($content, $type = 'default')
2031
    {
2032
        switch ($type) {
2033
            case 'success':
2034
                $class = 'success';
2035
                break;
2036
            case 'warning':
2037
                $class = 'warning';
2038
                break;
2039
            case 'important':
2040
            case 'danger':
2041
                $class = 'danger';
2042
                break;
2043
            case 'info':
2044
                $class = 'info';
2045
                break;
2046
            case 'primary':
2047
                $class = 'primary';
2048
                break;
2049
            default:
2050
                $class = 'secondary';
2051
                break;
2052
        }
2053
2054
        $html = '';
2055
        if (!empty($content)) {
2056
            $html = '<span class="badge badge-'.$class.'">';
2057
            $html .= $content;
2058
            $html .= '</span>';
2059
        }
2060
2061
        return $html;
2062
    }
2063
2064
    /**
2065
     * @param array  $items
2066
     * @param string $class
2067
     *
2068
     * @return string|null
2069
     */
2070
    public static function actions($items, $class = 'new_actions')
2071
    {
2072
        $html = null;
2073
        if (!empty($items)) {
2074
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2075
            foreach ($items as $value) {
2076
                $class = null;
2077
                if (isset($value['active']) && $value['active']) {
2078
                    $class = 'class ="active"';
2079
                }
2080
2081
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2082
                    $class = 'class ="active"';
2083
                }
2084
                $html .= "<li $class >";
2085
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2086
                $html .= self::url($value['content'], $value['url'], $attributes);
2087
                $html .= '</li>';
2088
            }
2089
            $html .= '</ul></div>';
2090
            $html .= '<br />';
2091
        }
2092
2093
        return $html;
2094
    }
2095
2096
    /**
2097
     * Prints a tooltip.
2098
     *
2099
     * @param string $text
2100
     * @param string $tip
2101
     *
2102
     * @return string
2103
     */
2104
    public static function tip($text, $tip)
2105
    {
2106
        if (empty($tip)) {
2107
            return $text;
2108
        }
2109
2110
        return self::span(
2111
            $text,
2112
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2113
        );
2114
    }
2115
2116
    /**
2117
     * @param array  $items
2118
     * @param string $type
2119
     * @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...
2120
     *
2121
     * @return string|null
2122
     */
2123
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2124
    {
2125
        $html = null;
2126
        if (!empty($items)) {
2127
            if (empty($id)) {
2128
                $id = api_get_unique_id();
2129
            }
2130
            if ($type == 'jquery') {
2131
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2132
            } else {
2133
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2134
            }
2135
2136
            $count = 1;
2137
            foreach ($items as $item) {
2138
                $html .= '<div class="accordion-my-group">';
2139
                $html .= '<div class="accordion-heading">
2140
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2141
                            '.$item['title'].'
2142
                            </a>
2143
                          </div>';
2144
2145
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2146
                $html .= '<div class="accordion-my-inner">
2147
                            '.$item['content'].'
2148
                            </div>
2149
                          </div>';
2150
            }
2151
            $html .= '</div>';
2152
        }
2153
2154
        return $html;
2155
    }
2156
2157
    /**
2158
     * @param array $buttons
2159
     *
2160
     * @return string
2161
     */
2162
    public static function groupButton($buttons)
2163
    {
2164
        $html = '<div class="btn-group" role="group">';
2165
        foreach ($buttons as $button) {
2166
            $html .= $button;
2167
        }
2168
        $html .= '</div>';
2169
2170
        return $html;
2171
    }
2172
2173
    /**
2174
     * @todo use twig
2175
     *
2176
     * @param string $title
2177
     * @param array  $elements
2178
     * @param bool   $alignToRight
2179
     *
2180
     * @return string
2181
     */
2182
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2183
    {
2184
        $id = uniqid('dropdown', true);
2185
        $html = '<div class="btn-group" role="group">
2186
                <button id = "'.$id.'" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
2187
                '.$title.'
2188
                </button>
2189
                <div class="dropdown-menu aria-labelledby="'.$id.'" '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2190
        foreach ($elements as $item) {
2191
            $html .= self::tag('li', self::url($item['title'], $item['href'], ['class' => 'dropdown-item']));
2192
        }
2193
        $html .= '</div>
2194
            </div>';
2195
2196
        return $html;
2197
    }
2198
2199
    /**
2200
     * @param string $file
2201
     * @param array  $params
2202
     *
2203
     * @return string|null
2204
     */
2205
    public static function getMediaPlayer($file, $params = [])
2206
    {
2207
        $fileInfo = pathinfo($file);
2208
2209
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2210
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2211
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2212
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2213
2214
        switch ($fileInfo['extension']) {
2215
            case 'mp3':
2216
            case 'webm':
2217
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2218
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2219
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2220
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2221
                          </object>';
2222
                $html .= '</audio>';
2223
2224
                return $html;
2225
                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...
2226
            case 'wav':
2227
            case 'ogg':
2228
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2229
2230
                return $html;
2231
                break;
2232
        }
2233
2234
        return null;
2235
    }
2236
2237
    /**
2238
     * @param int    $nextValue
2239
     * @param array  $list
2240
     * @param int    $current
2241
     * @param int    $fixedValue
2242
     * @param array  $conditions
2243
     * @param string $link
2244
     * @param bool   $isMedia
2245
     * @param bool   $addHeaders
2246
     * @param array  $linkAttributes
2247
     *
2248
     * @return string
2249
     */
2250
    public static function progressPaginationBar(
2251
        $nextValue,
2252
        $list,
2253
        $current,
2254
        $fixedValue = null,
2255
        $conditions = [],
2256
        $link = null,
2257
        $isMedia = false,
2258
        $addHeaders = true,
2259
        $linkAttributes = []
2260
    ) {
2261
        if ($addHeaders) {
2262
            $pagination_size = 'pagination-mini';
2263
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2264
        } else {
2265
            $html = null;
2266
        }
2267
        $affectAllItems = false;
2268
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2269
            $affectAllItems = true;
2270
        }
2271
        $localCounter = 0;
2272
        foreach ($list as $itemId) {
2273
            $isCurrent = false;
2274
            if ($affectAllItems) {
2275
                $isCurrent = true;
2276
            } else {
2277
                if (!$isMedia) {
2278
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2279
                }
2280
            }
2281
            $html .= self::parsePaginationItem(
2282
                $itemId,
2283
                $isCurrent,
2284
                $conditions,
2285
                $link,
2286
                $nextValue,
2287
                $isMedia,
2288
                $localCounter,
2289
                $fixedValue,
2290
                $linkAttributes
2291
            );
2292
            $localCounter++;
2293
        }
2294
        if ($addHeaders) {
2295
            $html .= '</ul></div>';
2296
        }
2297
2298
        return $html;
2299
    }
2300
2301
    /**
2302
     * @param int    $itemId
2303
     * @param bool   $isCurrent
2304
     * @param array  $conditions
2305
     * @param string $link
2306
     * @param int    $nextValue
2307
     * @param bool   $isMedia
2308
     * @param int    $localCounter
2309
     * @param int    $fixedValue
2310
     * @param array  $linkAttributes
2311
     *
2312
     * @return string
2313
     */
2314
    public static function parsePaginationItem(
2315
        $itemId,
2316
        $isCurrent,
2317
        $conditions,
2318
        $link,
2319
        $nextValue = 0,
2320
        $isMedia = false,
2321
        $localCounter = null,
2322
        $fixedValue = null,
2323
        $linkAttributes = []
2324
    ) {
2325
        $defaultClass = 'before';
2326
        $class = $defaultClass;
2327
        foreach ($conditions as $condition) {
2328
            $array = isset($condition['items']) ? $condition['items'] : [];
2329
            $class_to_applied = $condition['class'];
2330
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2331
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2332
            switch ($type) {
2333
                case 'positive':
2334
                    if (in_array($itemId, $array)) {
2335
                        if ($mode == 'overwrite') {
2336
                            $class = " $defaultClass $class_to_applied";
2337
                        } else {
2338
                            $class .= " $class_to_applied";
2339
                        }
2340
                    }
2341
                    break;
2342
                case 'negative':
2343
                    if (!in_array($itemId, $array)) {
2344
                        if ($mode == 'overwrite') {
2345
                            $class = " $defaultClass $class_to_applied";
2346
                        } else {
2347
                            $class .= " $class_to_applied";
2348
                        }
2349
                    }
2350
                    break;
2351
            }
2352
        }
2353
        if ($isCurrent) {
2354
            $class = 'before current';
2355
        }
2356
        if ($isMedia && $isCurrent) {
2357
            $class = 'before current';
2358
        }
2359
        if (empty($link)) {
2360
            $link_to_show = '#';
2361
        } else {
2362
            $link_to_show = $link.($nextValue + $localCounter);
2363
        }
2364
        $label = $nextValue + $localCounter + 1;
2365
        if ($isMedia) {
2366
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2367
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2368
        }
2369
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2370
2371
        return  '<li class = "'.$class.'">'.$link.'</li>';
2372
    }
2373
2374
    /**
2375
     * @param int $current
2376
     * @param int $total
2377
     *
2378
     * @return string
2379
     */
2380
    public static function paginationIndicator($current, $total)
2381
    {
2382
        $html = null;
2383
        if (!empty($current) && !empty($total)) {
2384
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2385
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2386
        }
2387
2388
        return $html;
2389
    }
2390
2391
    /**
2392
     * @param $url
2393
     * @param $currentPage
2394
     * @param $pagesCount
2395
     * @param $totalItems
2396
     *
2397
     * @return string
2398
     */
2399
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2400
    {
2401
        $pagination = '';
2402
        if ($totalItems > 1 && $pagesCount > 1) {
2403
            $pagination .= '<ul class="pagination">';
2404
            for ($i = 0; $i < $pagesCount; $i++) {
2405
                $newPage = $i + 1;
2406
                if ($currentPage == $newPage) {
2407
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2408
                } else {
2409
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2410
                }
2411
            }
2412
            $pagination .= '</ul>';
2413
        }
2414
2415
        return $pagination;
2416
    }
2417
2418
    /**
2419
     * Adds a message in the queue.
2420
     *
2421
     * @param string $message
2422
     */
2423
    public static function addFlash($message)
2424
    {
2425
        $messages = Session::read('flash_messages');
2426
        if (empty($messages)) {
2427
            $messages[] = $message;
2428
        } else {
2429
            array_push($messages, $message);
2430
        }
2431
        Session::write('flash_messages', $messages);
2432
    }
2433
2434
    /**
2435
     * @return string
2436
     */
2437
    public static function getFlashToString()
2438
    {
2439
        $messages = Session::read('flash_messages');
2440
        $messageToString = '';
2441
        if (!empty($messages)) {
2442
            foreach ($messages as $message) {
2443
                $messageToString .= $message;
2444
            }
2445
        }
2446
2447
        return $messageToString;
2448
    }
2449
2450
    /**
2451
     * Shows the message from the session.
2452
     */
2453
    public static function showFlash()
2454
    {
2455
        echo self::getFlashToString();
2456
    }
2457
2458
    /**
2459
     * Destroys the message session.
2460
     */
2461
    public static function cleanFlashMessages()
2462
    {
2463
        Session::erase('flash_messages');
2464
    }
2465
2466
    /**
2467
     * Get the profile edition link for a user.
2468
     *
2469
     * @param int  $userId  The user id
2470
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2471
     *
2472
     * @return string The link
2473
     */
2474
    public static function getProfileEditionLink($userId, $asAdmin = false)
2475
    {
2476
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2477
        if ($asAdmin) {
2478
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2479
        }
2480
2481
        return $editProfileUrl;
2482
    }
2483
2484
    /**
2485
     * Get the vCard for a user.
2486
     *
2487
     * @param int $userId The user id
2488
     *
2489
     * @return string *.*vcf file
2490
     */
2491
    public static function getVCardUserLink($userId)
2492
    {
2493
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2494
2495
        return $vCardUrl;
2496
    }
2497
2498
    /**
2499
     * @param string $content
2500
     * @param string $title
2501
     * @param string $footer
2502
     * @param string $type        primary|success|info|warning|danger
2503
     * @param string $extra
2504
     * @param string $id
2505
     * @param string $customColor
2506
     * @param string $rightAction
2507
     *
2508
     * @return string
2509
     */
2510
    public static function panel(
2511
        $content,
2512
        $title = '',
2513
        $footer = '',
2514
        $type = 'default',
2515
        $extra = '',
2516
        $id = '',
2517
        $customColor = '',
2518
        $rightAction = ''
2519
    ) {
2520
        $headerStyle = '';
2521
        if (!empty($customColor)) {
2522
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2523
        }
2524
2525
        if (!empty($rightAction)) {
2526
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2527
        }
2528
2529
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2530
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2531
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2532
        $style = !in_array($type, $typeList) ? 'default' : $type;
2533
2534
        if (!empty($id)) {
2535
            $id = " id='$id'";
2536
        }
2537
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2538
2539
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2540
2541
        return '
2542
            <div '.$id.' class="card">
2543
                '.$panel.'
2544
            </div>'
2545
        ;
2546
    }
2547
2548
    /**
2549
     * @param string $content
2550
     *
2551
     * @return string
2552
     */
2553
    public static function contentPanel($content): string
2554
    {
2555
        if (empty($content)) {
2556
            return '';
2557
        }
2558
2559
        return '<div class="card-text">'.$content.'</div>';
2560
    }
2561
2562
    /**
2563
     * Get the button HTML with an Awesome Font icon.
2564
     *
2565
     * @param string $text        The button content
2566
     * @param string $url         The url to button
2567
     * @param string $icon        The Awesome Font class for icon
2568
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2569
     * @param array  $attributes  The additional attributes
2570
     * @param bool   $includeText
2571
     *
2572
     * @return string The button HTML
2573
     */
2574
    public static function toolbarButton(
2575
        $text,
2576
        $url,
2577
        $icon = 'check',
2578
        $type = null,
2579
        array $attributes = [],
2580
        $includeText = true
2581
    ) {
2582
        $buttonClass = "btn btn-outline-secondary";
2583
        if (!empty($type)) {
2584
            $buttonClass = "btn btn-$type";
2585
        }
2586
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2587
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2588
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2589
2590
        if (!$includeText) {
2591
            $text = '<span class="sr-only">'.$text.'</span>';
2592
        }
2593
2594
        return self::url("$icon $text", $url, $attributes);
2595
    }
2596
2597
    /**
2598
     * @param string $id
2599
     * @param array  $content
2600
     * @param array  $colsWidth Optional. Columns width
2601
     *
2602
     * @return string
2603
     */
2604
    public static function toolbarAction($id, $content, $colsWidth = [])
2605
    {
2606
        $col = count($content);
2607
2608
        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...
2609
            $width = 12 / $col;
2610
            array_walk($content, function () use ($width, &$colsWidth) {
2611
                $colsWidth[] = $width;
2612
            });
2613
        }
2614
2615
        $html = '<div id="'.$id.'" class="actions">';
2616
        $html .= '<div class="row">';
2617
2618
        for ($i = 0; $i < $col; $i++) {
2619
            $class = 'col-sm-'.$colsWidth[$i];
2620
2621
            if ($col > 1) {
2622
                if ($i > 0 && $i < count($content) - 1) {
2623
                    $class .= ' text-center';
2624
                } elseif ($i === count($content) - 1) {
2625
                    $class .= ' text-right';
2626
                }
2627
            }
2628
2629
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2630
        }
2631
2632
        $html .= '</div>';
2633
        $html .= '</div>';
2634
2635
        return $html;
2636
    }
2637
2638
    /**
2639
     * Get a HTML code for a icon by Font Awesome.
2640
     *
2641
     * @param string     $name            The icon name. Example: "mail-reply"
2642
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2643
     * @param bool       $fixWidth        Optional. Whether add the fw class
2644
     * @param string     $additionalClass Optional. Additional class
2645
     *
2646
     * @return string
2647
     */
2648
    public static function returnFontAwesomeIcon(
2649
        $name,
2650
        $size = '',
2651
        $fixWidth = false,
2652
        $additionalClass = ''
2653
    ) {
2654
        $className = "fa fa-$name";
2655
2656
        if ($fixWidth) {
2657
            $className .= ' fa-fw';
2658
        }
2659
2660
        switch ($size) {
2661
            case 'xs':
2662
            case 'sm':
2663
            case 'lg':
2664
                $className .= " fa-{$size}";
2665
                break;
2666
            case 2:
2667
            case 3:
2668
            case 4:
2669
            case 5:
2670
                $className .= " fa-{$size}x";
2671
                break;
2672
        }
2673
2674
        if (!empty($additionalClass)) {
2675
            $className .= " $additionalClass";
2676
        }
2677
2678
        $icon = self::tag('em', null, ['class' => $className]);
2679
2680
        return "$icon ";
2681
    }
2682
2683
    /**
2684
     * @param string     $title
2685
     * @param string     $content
2686
     * @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...
2687
     * @param array      $params
2688
     * @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...
2689
     * @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...
2690
     * @param bool|true  $open
2691
     * @param bool|false $fullClickable
2692
     *
2693
     * @return string|null
2694
     *
2695
     * @todo rework function to easy use
2696
     */
2697
    public static function panelCollapse(
2698
        $title,
2699
        $content,
2700
        $id = null,
2701
        $params = [],
2702
        $idAccordion = null,
2703
        $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

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