Passed
Push — master ( f90561...9c0d13 )
by Julito
10:26
created

Display::display_reduced_header()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
8
use Chamilo\CoreBundle\Framework\Container;
9
use ChamiloSession as Session;
10
use Symfony\Component\HttpFoundation\Response;
11
12
/**
13
 * Class Display
14
 * Contains several public functions dealing with the display of
15
 * table data, messages, help topics, ...
16
 *
17
 * Include/require it in your code to use its public functionality.
18
 * There are also several display public functions in the main api library.
19
 *
20
 * All public functions static public functions inside a class called Display,
21
 * so you use them like this: e.g.
22
 * Display::return_message($message)
23
 */
24
class Display
25
{
26
    /** @var Template */
27
    public static $global_template;
28
    public static $preview_style = null;
29
    public static $legacyTemplate;
30
    public function __construct()
31
    {
32
    }
33
34
    /**
35
     * @return array
36
     */
37
    public static function toolList()
38
    {
39
        return [
40
            'group',
41
            'work',
42
            'glossary',
43
            'forum',
44
            'course_description',
45
            'gradebook',
46
            'attendance',
47
            'course_progress',
48
            'notebook',
49
        ];
50
    }
51
52
    /**
53
     * Displays the page header.
54
     *
55
     * @param string The name of the page (will be showed in the page title)
56
     * @param string Optional help file name
57
     * @param string $page_header
58
     */
59
    public static function display_header(
60
        $tool_name = '',
61
        $help = null,
62
        $page_header = null
63
    ) {
64
        global $interbreadcrumb;
65
        $interbreadcrumb[] = ['url' => '#', 'name' => $tool_name];
66
67
        ob_start();
68
69
        return true;
70
    }
71
72
    /**
73
     * Displays the reduced page header (without banner).
74
     */
75
    public static function display_reduced_header()
76
    {
77
        ob_start();
78
        self::$legacyTemplate = '@ChamiloCore/Layout/no_layout.html.twig';
79
80
        return true;
81
82
        global $show_learnpath, $tool_name;
0 ignored issues
show
Unused Code introduced by
GlobalNode 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...
83
        self::$global_template = new Template(
84
            $tool_name,
85
            false,
86
            false,
87
            $show_learnpath
88
        );
89
    }
90
91
    /**
92
     * Display no header.
93
     */
94
    public static function display_no_header()
95
    {
96
        global $tool_name, $show_learnpath;
97
        self::$global_template = new Template(
98
            $tool_name,
99
            false,
100
            false,
101
            $show_learnpath
102
        );
103
    }
104
105
    /**
106
     * Display the page footer.
107
     */
108
    public static function display_footer()
109
    {
110
        $contents = ob_get_contents();
111
        if (ob_get_length()) {
112
            ob_end_clean();
113
        }
114
        $tpl = '@ChamiloCore/Layout/layout_one_col.html.twig';
115
        if (!empty(self::$legacyTemplate)) {
116
            $tpl = self::$legacyTemplate;
117
        }
118
        $response = new Response();
119
        $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...
120
        global $interbreadcrumb, $htmlHeadXtra;
121
122
        $courseInfo = api_get_course_info();
123
        if (!empty($courseInfo)) {
124
            $url = $courseInfo['course_public_url'];
125
            $sessionId = api_get_session_id();
126
            if (!empty($sessionId)) {
127
                $url .= '?sid='.$sessionId;
128
            }
129
130
            array_unshift(
131
                $interbreadcrumb,
132
                ['name' => $courseInfo['title'], 'url' => $url]
133
            );
134
        }
135
136
        $params['legacy_javascript'] = $htmlHeadXtra;
137
        $params['legacy_breadcrumb'] = $interbreadcrumb;
138
139
        Template::setVueParams($params);
140
        $content = Container::getTwig()->render($tpl, $params);
141
        $response->setContent($content);
142
        $response->send();
143
        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...
144
    }
145
146
    /**
147
     * Display the page footer.
148
     */
149
    public static function display_reduced_footer()
150
    {
151
        $contents = ob_get_contents();
152
        if (ob_get_length()) {
153
            ob_end_clean();
154
        }
155
        $tpl = '@ChamiloCore/Layout/no_layout.html.twig';
156
        if (!empty(self::$legacyTemplate)) {
157
            $tpl = self::$legacyTemplate;
158
        }
159
        $response = new Response();
160
        $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...
161
        global $interbreadcrumb, $htmlHeadXtra;
162
        $params['legacy_javascript'] = $htmlHeadXtra;
163
        $params['legacy_breadcrumb'] = $interbreadcrumb;
164
165
        $content = Container::getTwig()->render($tpl, $params);
166
        $response->setContent($content);
167
        $response->send();
168
        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...
169
    }
170
171
    /**
172
     * Displays the tool introduction of a tool.
173
     *
174
     * @author Patrick Cool <[email protected]>, Ghent University
175
     *
176
     * @param string $tool          these are the constants that are used for indicating the tools
177
     * @param array  $editor_config Optional configuration settings for the online editor.
178
     *                              return: $tool return a string array list with the "define" in main_api.lib
179
     *
180
     * @return string html code for adding an introduction
181
     */
182
    public static function display_introduction_section(
183
        $tool,
184
        $editor_config = null
185
    ) {
186
        // @todo replace introduction section with a vue page.
187
        return;
188
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Unused Code introduced by
echo self::return_introd...($tool, $editor_config) 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...
189
    }
190
191
    /**
192
     * @param string $tool
193
     * @param array  $editor_config
194
     */
195
    public static function return_introduction_section(
196
        $tool,
197
        $editor_config = null
198
    ) {
199
        $moduleId = $tool;
200
        if ('true' === api_get_setting('enable_tool_introduction') || TOOL_COURSE_HOMEPAGE == $tool) {
201
            $introduction_section = null;
202
            require api_get_path(SYS_CODE_PATH).'inc/introductionSection.inc.php';
203
204
            return $introduction_section;
205
        }
206
    }
207
208
    /**
209
     * Displays a table.
210
     *
211
     * @param array  $header          Titles for the table header
212
     *                                each item in this array can contain 3 values
213
     *                                - 1st element: the column title
214
     *                                - 2nd element: true or false (column sortable?)
215
     *                                - 3th element: additional attributes for
216
     *                                th-tag (eg for column-width)
217
     *                                - 4the element: additional attributes for the td-tags
218
     * @param array  $content         2D-array with the tables content
219
     * @param array  $sorting_options Keys are:
220
     *                                'column' = The column to use as sort-key
221
     *                                'direction' = SORT_ASC or SORT_DESC
222
     * @param array  $paging_options  Keys are:
223
     *                                'per_page_default' = items per page when switching from
224
     *                                full-    list to per-page-view
225
     *                                'per_page' = number of items to show per page
226
     *                                'page_nr' = The page to display
227
     * @param array  $query_vars      Additional variables to add in the query-string
228
     * @param array  $form_actions
229
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
230
     * @param string $tableName
231
     * @param string $tableId
232
     *
233
     * @author [email protected]
234
     */
235
    public static function display_sortable_table(
236
        $header,
237
        $content,
238
        $sorting_options = [],
239
        $paging_options = [],
240
        $query_vars = null,
241
        $form_actions = [],
242
        $style = 'table',
243
        $tableName = 'tablename',
244
        $tableId = ''
245
    ) {
246
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
247
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
248
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
249
        if (is_array($query_vars)) {
250
            $table->set_additional_parameters($query_vars);
251
        }
252
        if ('table' == $style) {
253
            if (is_array($header) && count($header) > 0) {
254
                foreach ($header as $index => $header_item) {
255
                    $table->set_header(
256
                        $index,
257
                        isset($header_item[0]) ? $header_item[0] : null,
258
                        isset($header_item[1]) ? $header_item[1] : null,
259
                        isset($header_item[2]) ? $header_item[2] : null,
260
                        isset($header_item[3]) ? $header_item[3] : null
261
                    );
262
                }
263
            }
264
            $table->set_form_actions($form_actions);
265
            $table->display();
266
        } else {
267
            $table->display_grid();
268
        }
269
    }
270
271
    /**
272
     * Returns an HTML table with sortable column (through complete page refresh).
273
     *
274
     * @param array  $header
275
     * @param array  $content         Array of row arrays
276
     * @param array  $sorting_options
277
     * @param array  $paging_options
278
     * @param array  $query_vars
279
     * @param array  $form_actions
280
     * @param string $style
281
     *
282
     * @return string HTML string for array
283
     */
284
    public static function return_sortable_table(
285
        $header,
286
        $content,
287
        $sorting_options = [],
288
        $paging_options = [],
289
        $query_vars = null,
290
        $form_actions = [],
291
        $style = 'table'
292
    ) {
293
        ob_start();
294
        self::display_sortable_table(
295
            $header,
296
            $content,
297
            $sorting_options,
298
            $paging_options,
299
            $query_vars,
300
            $form_actions,
301
            $style
302
        );
303
        $content = ob_get_contents();
304
        ob_end_clean();
305
306
        return $content;
307
    }
308
309
    /**
310
     * Shows a nice grid.
311
     *
312
     * @param string grid name (important to create css)
313
     * @param array header content
314
     * @param array array with the information to show
315
     * @param array $paging_options Keys are:
316
     *                              'per_page_default' = items per page when switching from
317
     *                              full-    list to per-page-view
318
     *                              'per_page' = number of items to show per page
319
     *                              'page_nr' = The page to display
320
     *                              'hide_navigation' =  true to hide the navigation
321
     * @param array $query_vars     Additional variables to add in the query-string
322
     * @param mixed An array with bool values to know which columns show.
323
     * i.e: $visibility_options= array(true, false) we will only show the first column
324
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
325
     */
326
    public static function display_sortable_grid(
327
        $name,
328
        $header,
329
        $content,
330
        $paging_options = [],
331
        $query_vars = null,
332
        $form_actions = [],
333
        $visibility_options = true,
334
        $sort_data = true,
335
        $grid_class = []
336
    ) {
337
        echo self::return_sortable_grid(
338
            $name,
339
            $header,
340
            $content,
341
            $paging_options,
342
            $query_vars,
343
            $form_actions,
344
            $visibility_options,
345
            $sort_data,
346
            $grid_class
347
        );
348
    }
349
350
    /**
351
     * Gets a nice grid in html string.
352
     *
353
     * @param string grid name (important to create css)
354
     * @param array header content
355
     * @param array array with the information to show
356
     * @param array $paging_options Keys are:
357
     *                              'per_page_default' = items per page when switching from
358
     *                              full-    list to per-page-view
359
     *                              'per_page' = number of items to show per page
360
     *                              'page_nr' = The page to display
361
     *                              'hide_navigation' =  true to hide the navigation
362
     * @param array $query_vars     Additional variables to add in the query-string
363
     * @param mixed An array with bool values to know which columns show. i.e:
364
     *  $visibility_options= array(true, false) we will only show the first column
365
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
366
     * @param bool  true for sorting data or false otherwise
367
     * @param array grid classes
368
     *
369
     * @return string html grid
370
     */
371
    public static function return_sortable_grid(
372
        $name,
373
        $header,
374
        $content,
375
        $paging_options = [],
376
        $query_vars = null,
377
        $form_actions = [],
378
        $visibility_options = true,
379
        $sort_data = true,
380
        $grid_class = [],
381
        $elementCount = 0
382
    ) {
383
        $column = 0;
384
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
385
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
386
        $table->total_number_of_items = intval($elementCount);
387
        if (is_array($query_vars)) {
388
            $table->set_additional_parameters($query_vars);
389
        }
390
391
        return $table->display_simple_grid(
392
            $visibility_options,
393
            $paging_options['hide_navigation'],
394
            $default_items_per_page,
395
            $sort_data,
396
            $grid_class
397
        );
398
    }
399
400
    /**
401
     * Displays a table with a special configuration.
402
     *
403
     * @param array $header          Titles for the table header
404
     *                               each item in this array can contain 3 values
405
     *                               - 1st element: the column title
406
     *                               - 2nd element: true or false (column sortable?)
407
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
408
     *                               - 4the element: additional attributes for the td-tags
409
     * @param array $content         2D-array with the tables content
410
     * @param array $sorting_options Keys are:
411
     *                               'column' = The column to use as sort-key
412
     *                               'direction' = SORT_ASC or SORT_DESC
413
     * @param array $paging_options  Keys are:
414
     *                               'per_page_default' = items per page when switching from full list to per-page-view
415
     *                               'per_page' = number of items to show per page
416
     *                               'page_nr' = The page to display
417
     * @param array $query_vars      Additional variables to add in the query-string
418
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
419
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
420
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
421
     * @param array $form_actions    Set optional forms actions
422
     *
423
     * @author Julio Montoya
424
     */
425
    public static function display_sortable_config_table(
426
        $table_name,
427
        $header,
428
        $content,
429
        $sorting_options = [],
430
        $paging_options = [],
431
        $query_vars = null,
432
        $column_show = [],
433
        $column_order = [],
434
        $form_actions = []
435
    ) {
436
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
437
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
438
439
        $table = new SortableTableFromArrayConfig(
440
            $content,
441
            $column,
442
            $default_items_per_page,
443
            $table_name,
444
            $column_show,
445
            $column_order
446
        );
447
448
        if (is_array($query_vars)) {
449
            $table->set_additional_parameters($query_vars);
450
        }
451
        // Show or hide the columns header
452
        if (is_array($column_show)) {
453
            for ($i = 0; $i < count($column_show); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
454
                if (!empty($column_show[$i])) {
455
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
456
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
457
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
458
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
459
                    $table->set_header($i, $val0, $val1, $val2, $val3);
460
                }
461
            }
462
        }
463
        $table->set_form_actions($form_actions);
464
        $table->display();
465
    }
466
467
    /**
468
     * Returns a div html string with.
469
     *
470
     * @param string $message
471
     * @param string $type    Example: confirm, normal, warning, error
472
     * @param bool   $filter  Whether to XSS-filter or not
473
     *
474
     * @return string Message wrapped into an HTML div
475
     */
476
    public static function return_message($message, $type = 'normal', $filter = true)
477
    {
478
        if (empty($message)) {
479
            return '';
480
        }
481
482
        if ($filter) {
483
            $message = api_htmlentities(
484
                $message,
485
                ENT_QUOTES,
486
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
487
            );
488
        }
489
490
        $class = '';
491
        switch ($type) {
492
            case 'warning':
493
                $class .= 'alert alert-warning';
494
                break;
495
            case 'error':
496
                $class .= 'alert alert-danger';
497
                break;
498
            case 'confirmation':
499
            case 'confirm':
500
            case 'success':
501
                $class .= 'alert alert-success';
502
                break;
503
            case 'normal':
504
            case 'info':
505
            default:
506
                $class .= 'alert alert-info';
507
        }
508
509
        return self::div($message, ['class' => $class]);
510
    }
511
512
    /**
513
     * Returns an encrypted mailto hyperlink.
514
     *
515
     * @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...
516
     * @param string  clickable text
517
     * @param string  optional, class from stylesheet
518
     * @param bool $addExtraContent
519
     *
520
     * @return string encrypted mailto hyperlink
521
     */
522
    public static function encrypted_mailto_link(
523
        $email,
524
        $clickable_text = null,
525
        $style_class = '',
526
        $addExtraContent = false
527
    ) {
528
        if (is_null($clickable_text)) {
529
            $clickable_text = $email;
530
        }
531
532
        // "mailto:" already present?
533
        if ('mailto:' !== substr($email, 0, 7)) {
534
            $email = 'mailto:'.$email;
535
        }
536
537
        // Class (stylesheet) defined?
538
        if ('' !== $style_class) {
539
            $style_class = ' class="'.$style_class.'"';
540
        }
541
542
        // Encrypt email
543
        $hmail = '';
544
        for ($i = 0; $i < strlen($email); $i++) {
545
            $hmail .= '&#'.ord($email[$i]).';';
546
        }
547
548
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
549
550
        if ($value) {
551
            if ('false' === api_get_setting('allow_email_editor')) {
552
                $hmail .= '?';
553
            }
554
555
            if (!api_is_anonymous()) {
556
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
557
            }
558
            if ($addExtraContent) {
559
                $content = '';
560
                if (!api_is_anonymous()) {
561
                    $userInfo = api_get_user_info();
562
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
563
564
                    $courseInfo = api_get_course_info();
565
                    if (!empty($courseInfo)) {
566
                        $content .= get_lang('Course').': ';
567
                        $content .= $courseInfo['name'];
568
                        $sessionInfo = api_get_session_info(api_get_session_id());
569
                        if (!empty($sessionInfo)) {
570
                            $content .= ' '.$sessionInfo['name'].' <br />';
571
                        }
572
                    }
573
                }
574
                $hmail .= '&body='.rawurlencode($content);
575
            }
576
        }
577
578
        $hclickable_text = '';
579
        // Encrypt clickable text if @ is present
580
        if (strpos($clickable_text, '@')) {
581
            for ($i = 0; $i < strlen($clickable_text); $i++) {
582
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
583
            }
584
        } else {
585
            $hclickable_text = @htmlspecialchars(
586
                $clickable_text,
587
                ENT_QUOTES,
588
                api_get_system_encoding()
589
            );
590
        }
591
        // Return encrypted mailto hyperlink
592
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
593
    }
594
595
    /**
596
     * Returns an mailto icon hyperlink.
597
     *
598
     * @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...
599
     * @param string  icon source file from the icon lib
600
     * @param int  icon size from icon lib
601
     * @param string  optional, class from stylesheet
602
     *
603
     * @return string encrypted mailto hyperlink
604
     */
605
    public static function icon_mailto_link(
606
        $email,
607
        $icon_file = "mail.png",
608
        $icon_size = 22,
609
        $style_class = ''
610
    ) {
611
        // "mailto:" already present?
612
        if ('mailto:' != substr($email, 0, 7)) {
613
            $email = 'mailto:'.$email;
614
        }
615
        // Class (stylesheet) defined?
616
        if ('' != $style_class) {
617
            $style_class = ' class="'.$style_class.'"';
618
        }
619
        // Encrypt email
620
        $hmail = '';
621
        for ($i = 0; $i < strlen($email); $i++) {
622
            $hmail .= '&#'.ord($email[
623
            $i]).';';
624
        }
625
        // icon html code
626
        $icon_html_source = self::return_icon(
627
            $icon_file,
628
            $hmail,
629
            '',
630
            $icon_size
631
        );
632
        // Return encrypted mailto hyperlink
633
634
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
635
    }
636
637
    /**
638
     * Prints an <option>-list with all letters (A-Z).
639
     *
640
     * @todo This is English language specific implementation.
641
     * It should be adapted for the other languages.
642
     *
643
     * @return string
644
     */
645
    public static function get_alphabet_options($selectedLetter = '')
646
    {
647
        $result = '';
648
        for ($i = 65; $i <= 90; $i++) {
649
            $letter = chr($i);
650
            $result .= '<option value="'.$letter.'"';
651
            if ($selectedLetter == $letter) {
652
                $result .= ' selected="selected"';
653
            }
654
            $result .= '>'.$letter.'</option>';
655
        }
656
657
        return $result;
658
    }
659
660
    /**
661
     * Get the options withing a select box within the given values.
662
     *
663
     * @param int   Min value
664
     * @param int   Max value
665
     * @param int   Default value
666
     *
667
     * @return string HTML select options
668
     */
669
    public static function get_numeric_options($min, $max, $selected_num = 0)
670
    {
671
        $result = '';
672
        for ($i = $min; $i <= $max; $i++) {
673
            $result .= '<option value="'.$i.'"';
674
            if (is_int($selected_num)) {
675
                if ($selected_num == $i) {
676
                    $result .= ' selected="selected"';
677
                }
678
            }
679
            $result .= '>'.$i.'</option>';
680
        }
681
682
        return $result;
683
    }
684
685
    /**
686
     * This public function displays an icon.
687
     *
688
     * @param string   The filename of the file (in the main/img/ folder
689
     * @param string   The alt text (probably a language variable)
690
     * @param array    additional attributes (for instance height, width, onclick, ...)
691
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
692
     */
693
    public static function display_icon(
694
        $image,
695
        $alt_text = '',
696
        $additional_attributes = [],
697
        $size = null
698
    ) {
699
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
700
    }
701
702
    /**
703
     * Gets the path of an icon.
704
     *
705
     * @param string $icon
706
     * @param int    $size
707
     *
708
     * @return string
709
     */
710
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
711
    {
712
        return self::return_icon($icon, null, null, $size, null, true, false);
713
    }
714
715
    /**
716
     * This public function returns the htmlcode for an icon.
717
     *
718
     * @param string   The filename of the file (in the main/img/ folder
719
     * @param string   The alt text (probably a language variable)
720
     * @param array    Additional attributes (for instance height, width, onclick, ...)
721
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
722
     *
723
     * @return string An HTML string of the right <img> tag
724
     *
725
     * @author Patrick Cool <[email protected]>, Ghent University 2006
726
     * @author Julio Montoya 2010 Function improved, adding image constants
727
     * @author Yannick Warnier 2011 Added size handler
728
     *
729
     * @version Feb 2011
730
     */
731
    public static function return_icon(
732
        $image,
733
        $alt_text = '',
734
        $additional_attributes = [],
735
        $size = ICON_SIZE_SMALL,
736
        $show_text = true,
737
        $return_only_path = false,
738
        $loadThemeIcon = true
739
    ) {
740
        $code_path = api_get_path(SYS_PUBLIC_PATH);
741
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
742
        // The following path is checked to see if the file exist. It's
743
        // important to use the public path (i.e. web/css/) rather than the
744
        // internal path (/app/Resource/public/css/) because the path used
745
        // in the end must be the public path
746
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
747
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
748
749
        // Avoid issues with illegal string offset for legacy calls to this
750
        // method with an empty string rather than null or an empty array
751
        if (empty($additional_attributes)) {
752
            $additional_attributes = [];
753
        }
754
755
        $image = trim($image);
756
757
        if (isset($size)) {
758
            $size = (int) $size;
759
        } else {
760
            $size = ICON_SIZE_SMALL;
761
        }
762
763
        $size_extra = $size.'/';
764
        $icon = $w_code_path.'img/'.$image;
765
        $theme = 'themes/chamilo/icons/';
766
767
        if ($loadThemeIcon) {
768
            // @todo with chamilo 2 code
769
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
770
            if (is_file($alternateCssPath.$theme.$image)) {
771
                $icon = $alternateWebCssPath.$theme.$image;
772
            }
773
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
774
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
775
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
776
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
777
                //Checking the main/img/icons/XXX/ folder
778
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
779
            }
780
        } else {
781
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
782
                // Checking the main/img/icons/XXX/ folder
783
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
784
            }
785
        }
786
787
        // Special code to enable SVG - refs #7359 - Needs more work
788
        // The code below does something else to "test out" SVG: for each icon,
789
        // it checks if there is an SVG version. If so, it uses it.
790
        // When moving this to production, the return_icon() calls should
791
        // ask for the SVG version directly
792
        $svgIcons = api_get_setting('icons_mode_svg');
793
        if ('true' == $svgIcons && false == $return_only_path) {
794
            $svgImage = substr($image, 0, -3).'svg';
795
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
796
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
797
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
798
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
799
            }
800
801
            if (empty($additional_attributes['height'])) {
802
                $additional_attributes['height'] = $size;
803
            }
804
            if (empty($additional_attributes['width'])) {
805
                $additional_attributes['width'] = $size;
806
            }
807
        }
808
809
        if ($return_only_path) {
810
            return $icon;
811
        }
812
813
        $img = self::img($icon, $alt_text, $additional_attributes);
814
        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...
815
            if ($show_text) {
816
                $img = "$img $alt_text";
817
            }
818
        }
819
820
        return $img;
821
    }
822
823
    /**
824
     * Returns the htmlcode for an image.
825
     *
826
     * @param string $image_path            the filename of the file (in the main/img/ folder
827
     * @param string $alt_text              the alt text (probably a language variable)
828
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
829
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
830
     *
831
     * @return string
832
     *
833
     * @author Julio Montoya 2010
834
     */
835
    public static function img(
836
        $image_path,
837
        $alt_text = '',
838
        $additional_attributes = null,
839
        $filterPath = true
840
    ) {
841
        if (empty($image_path)) {
842
            return '';
843
        }
844
        // Sanitizing the parameter $image_path
845
        if ($filterPath) {
846
            $image_path = Security::filter_img_path($image_path);
847
        }
848
849
        // alt text = the image name if there is none provided (for XHTML compliance)
850
        if ('' == $alt_text) {
851
            $alt_text = basename($image_path);
852
        }
853
854
        if (empty($additional_attributes)) {
855
            $additional_attributes = [];
856
        }
857
858
        $additional_attributes['src'] = $image_path;
859
860
        if (empty($additional_attributes['alt'])) {
861
            $additional_attributes['alt'] = $alt_text;
862
        }
863
        if (empty($additional_attributes['title'])) {
864
            $additional_attributes['title'] = $alt_text;
865
        }
866
867
        return self::tag('img', '', $additional_attributes);
868
    }
869
870
    /**
871
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
872
     *
873
     * @param string $tag                   the tag name
874
     * @param string $content               the tag's content
875
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
876
     *
877
     * @return string
878
     *
879
     * @author Julio Montoya 2010
880
     */
881
    public static function tag($tag, $content, $additional_attributes = [])
882
    {
883
        $attribute_list = '';
884
        // Managing the additional attributes
885
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
886
            $attribute_list = '';
887
            foreach ($additional_attributes as $key => &$value) {
888
                $attribute_list .= $key.'="'.$value.'" ';
889
            }
890
        }
891
        //some tags don't have this </XXX>
892
        if (in_array($tag, ['img', 'input', 'br'])) {
893
            $return_value = '<'.$tag.' '.$attribute_list.' />';
894
        } else {
895
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
896
        }
897
898
        return $return_value;
899
    }
900
901
    /**
902
     * Creates a URL anchor.
903
     *
904
     * @param string $name
905
     * @param string $url
906
     * @param array  $attributes
907
     *
908
     * @return string
909
     */
910
    public static function url($name, $url, $attributes = [])
911
    {
912
        if (!empty($url)) {
913
            $url = preg_replace('#&amp;#', '&', $url);
914
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
915
            $attributes['href'] = $url;
916
        }
917
918
        return self::tag('a', $name, $attributes);
919
    }
920
921
    /**
922
     * Creates a div tag.
923
     *
924
     * @param string $content
925
     * @param array  $attributes
926
     *
927
     * @return string
928
     */
929
    public static function div($content, $attributes = [])
930
    {
931
        return self::tag('div', $content, $attributes);
932
    }
933
934
    /**
935
     * Creates a span tag.
936
     */
937
    public static function span($content, $attributes = [])
938
    {
939
        return self::tag('span', $content, $attributes);
940
    }
941
942
    /**
943
     * Displays an HTML input tag.
944
     */
945
    public static function input($type, $name, $value, $attributes = [])
946
    {
947
        if (isset($type)) {
948
            $attributes['type'] = $type;
949
        }
950
        if (isset($name)) {
951
            $attributes['name'] = $name;
952
        }
953
        if (isset($value)) {
954
            $attributes['value'] = $value;
955
        }
956
957
        return self::tag('input', '', $attributes);
958
    }
959
960
    /**
961
     * @param $name
962
     * @param $value
963
     * @param array $attributes
964
     *
965
     * @return string
966
     */
967
    public static function button($name, $value, $attributes = [])
968
    {
969
        if (!empty($name)) {
970
            $attributes['name'] = $name;
971
        }
972
973
        return self::tag('button', $value, $attributes);
974
    }
975
976
    /**
977
     * Displays an HTML select tag.
978
     *
979
     * @param string $name
980
     * @param array  $values
981
     * @param int    $default
982
     * @param array  $extra_attributes
983
     * @param bool   $show_blank_item
984
     * @param string $blank_item_text
985
     *
986
     * @return string
987
     */
988
    public static function select(
989
        $name,
990
        $values,
991
        $default = -1,
992
        $extra_attributes = [],
993
        $show_blank_item = true,
994
        $blank_item_text = ''
995
    ) {
996
        $html = '';
997
        $extra = '';
998
        $default_id = 'id="'.$name.'" ';
999
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1000
        foreach ($extra_attributes as $key => $parameter) {
1001
            if ('id' == $key) {
1002
                $default_id = '';
1003
            }
1004
            $extra .= $key.'="'.$parameter.'" ';
1005
        }
1006
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1007
1008
        if ($show_blank_item) {
1009
            if (empty($blank_item_text)) {
1010
                $blank_item_text = get_lang('Select');
1011
            } else {
1012
                $blank_item_text = Security::remove_XSS($blank_item_text);
1013
            }
1014
            $html .= self::tag(
1015
                'option',
1016
                '-- '.$blank_item_text.' --',
1017
                ['value' => '-1']
1018
            );
1019
        }
1020
        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...
1021
            foreach ($values as $key => $value) {
1022
                if (is_array($value) && isset($value['name'])) {
1023
                    $value = $value['name'];
1024
                }
1025
                $html .= '<option value="'.$key.'"';
1026
1027
                if (is_array($default)) {
1028
                    foreach ($default as $item) {
1029
                        if ($item == $key) {
1030
                            $html .= ' selected="selected"';
1031
                            break;
1032
                        }
1033
                    }
1034
                } else {
1035
                    if ($default == $key) {
1036
                        $html .= ' selected="selected"';
1037
                    }
1038
                }
1039
1040
                $html .= '>'.$value.'</option>';
1041
            }
1042
        }
1043
        $html .= '</select>';
1044
1045
        return $html;
1046
    }
1047
1048
    /**
1049
     * Creates a tab menu
1050
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1051
     * in the $htmlHeadXtra variable before the display_header
1052
     * Add this script.
1053
     *
1054
     * @param array  $headers       list of the tab titles
1055
     * @param array  $items
1056
     * @param string $id            id of the container of the tab in the example "tabs"
1057
     * @param array  $attributes    for the ul
1058
     * @param array  $ul_attributes
1059
     * @param string $selected
1060
     *
1061
     * @return string
1062
     */
1063
    public static function tabs(
1064
        $headers,
1065
        $items,
1066
        $id = 'tabs',
1067
        $attributes = [],
1068
        $ul_attributes = [],
1069
        $selected = ''
1070
    ) {
1071
        if (empty($headers) || 0 == count($headers)) {
1072
            return '';
1073
        }
1074
1075
        $lis = '';
1076
        $i = 1;
1077
        foreach ($headers as $item) {
1078
            $active = '';
1079
            if (1 == $i) {
1080
                $active = ' active';
1081
            }
1082
1083
            if (!empty($selected)) {
1084
                $active = '';
1085
                if ($selected == $i) {
1086
                    $active = ' active';
1087
                }
1088
            }
1089
1090
            $item = self::tag(
1091
                'a',
1092
                $item,
1093
                [
1094
                    'href' => '#'.$id.'-'.$i,
1095
                    'class' => 'nav-item nav-link '.$active,
1096
                    'id' => $id.$i.'-tab',
1097
                    'data-toggle' => 'tab',
1098
                    'role' => 'tab',
1099
                    'aria-controls' => $id.'-'.$i,
1100
                    'aria-selected' => $selected,
1101
                ]
1102
            );
1103
            $lis .= $item;
1104
            $i++;
1105
        }
1106
1107
        $ul = self::tag(
1108
            'nav',
1109
            $lis,
1110
            [
1111
                'id' => 'ul_'.$id,
1112
                'class' => 'nav nav-tabs',
1113
                'role' => 'tablist',
1114
            ]
1115
        );
1116
1117
        $i = 1;
1118
        $divs = '';
1119
        foreach ($items as $content) {
1120
            $active = '';
1121
            if (1 == $i) {
1122
                $active = ' show active';
1123
            }
1124
1125
            if (!empty($selected)) {
1126
                $active = '';
1127
                if ($selected == $i) {
1128
                    $active = ' show active';
1129
                }
1130
            }
1131
1132
            $divs .= self::tag(
1133
                'div',
1134
                $content,
1135
                [
1136
                    'id' => $id.'-'.$i,
1137
                    'class' => 'tab-pane fade '.$active,
1138
                    'role' => 'tabpanel',
1139
                    'aria-labelledby' => $id.$i.'-tab',
1140
                ]
1141
            );
1142
            $i++;
1143
        }
1144
1145
        $attributes['id'] = $id;
1146
        $attributes['class'] = 'tab_wrapper';
1147
1148
        return self::tag(
1149
            'div',
1150
            $ul.
1151
            self::tag('div', $divs, ['class' => 'tab-content']),
1152
            $attributes
1153
        );
1154
    }
1155
1156
    /**
1157
     * @param $headers
1158
     * @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...
1159
     *
1160
     * @return string
1161
     */
1162
    public static function tabsOnlyLink($headers, $selected = null)
1163
    {
1164
        $id = uniqid('tabs_');
1165
        $i = 1;
1166
        $list = '';
1167
        foreach ($headers as $item) {
1168
            $class = null;
1169
            if ($i == $selected) {
1170
                $class = 'active';
1171
            }
1172
            $item = self::tag(
1173
                'a',
1174
                $item['content'],
1175
                [
1176
                    'id' => $id.'-'.$i,
1177
                    'href' => $item['url'],
1178
                    'class' => 'nav-link '.$class,
1179
                ]
1180
            );
1181
            $list .= $item;
1182
            $i++;
1183
        }
1184
1185
        return self::toolbarAction($id, [$list]);
1186
    }
1187
1188
    /**
1189
     * In order to display a grid using jqgrid you have to:.
1190
     *
1191
     * @example
1192
     * After your Display::display_header function you have to add the nex javascript code:
1193
     * <script>
1194
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1195
     *   // for more information of this function check the grid_js() function
1196
     * </script>
1197
     * //Then you have to call the grid_html
1198
     * echo Display::grid_html('my_grid_name');
1199
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1200
     *
1201
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1202
     *
1203
     * @return string html
1204
     */
1205
    public static function grid_html($div_id)
1206
    {
1207
        $table = self::tag('table', '', ['id' => $div_id]);
1208
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1209
1210
        return $table;
1211
    }
1212
1213
    /**
1214
     * This is a wrapper to use the jqgrid in Chamilo.
1215
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1216
     * This function need to be in the ready jquery function
1217
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1218
     * In order to work this function needs the Display::grid_html function with the same div id.
1219
     *
1220
     * @param string $div_id       div id
1221
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1222
     * @param array  $column_names Visible columns (you should use get_lang).
1223
     *                             An array in which we place the names of the columns.
1224
     *                             This is the text that appears in the head of the grid (Header layer).
1225
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1226
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1227
     *                             This is the most important part of the grid.
1228
     *                             For a full description of all valid values see colModel API. See the url above.
1229
     * @param array  $extra_params extra parameters
1230
     * @param array  $data         data that will be loaded
1231
     * @param string $formatter    A string that will be appended to the JSON returned
1232
     * @param bool   $fixed_width  not implemented yet
1233
     *
1234
     * @return string the js code
1235
     */
1236
    public static function grid_js(
1237
        $div_id,
1238
        $url,
1239
        $column_names,
1240
        $column_model,
1241
        $extra_params,
1242
        $data = [],
1243
        $formatter = '',
1244
        $fixed_width = false
1245
    ) {
1246
        $obj = new stdClass();
1247
        $obj->first = 'first';
1248
1249
        if (!empty($url)) {
1250
            $obj->url = $url;
1251
        }
1252
1253
        // Needed it in order to render the links/html in the grid
1254
        foreach ($column_model as &$columnModel) {
1255
            if (!isset($columnModel['formatter'])) {
1256
                $columnModel['formatter'] = '';
1257
            }
1258
        }
1259
1260
        //This line should only be used/modified in case of having characters
1261
        // encoding problems - see #6159
1262
        //$column_names = array_map("utf8_encode", $column_names);
1263
        $obj->colNames = $column_names;
1264
        $obj->colModel = $column_model;
1265
        $obj->pager = '#'.$div_id.'_pager';
1266
        $obj->datatype = 'json';
1267
        $obj->viewrecords = 'true';
1268
        $obj->guiStyle = 'bootstrap4';
1269
        $obj->iconSet = 'fontAwesomeSolid';
1270
        $all_value = 10000000;
1271
1272
        // Sets how many records we want to view in the grid
1273
        $obj->rowNum = 20;
1274
1275
        // Default row quantity
1276
        if (!isset($extra_params['rowList'])) {
1277
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1278
            $rowList = api_get_configuration_value('table_row_list');
1279
            if (!empty($rowList) && isset($rowList['options'])) {
1280
                $rowList = $rowList['options'];
1281
                $rowList[] = $all_value;
1282
            }
1283
            $extra_params['rowList'] = $rowList;
1284
        }
1285
1286
        $defaultRow = api_get_configuration_value('table_default_row');
1287
        if (!empty($defaultRow)) {
1288
            $obj->rowNum = (int) $defaultRow;
1289
        }
1290
1291
        $json = '';
1292
        if (!empty($extra_params['datatype'])) {
1293
            $obj->datatype = $extra_params['datatype'];
1294
        }
1295
1296
        // Row even odd style.
1297
        $obj->altRows = true;
1298
        if (!empty($extra_params['altRows'])) {
1299
            $obj->altRows = $extra_params['altRows'];
1300
        }
1301
1302
        if (!empty($extra_params['sortname'])) {
1303
            $obj->sortname = $extra_params['sortname'];
1304
        }
1305
1306
        if (!empty($extra_params['sortorder'])) {
1307
            $obj->sortorder = $extra_params['sortorder'];
1308
        }
1309
1310
        if (!empty($extra_params['rowList'])) {
1311
            $obj->rowList = $extra_params['rowList'];
1312
        }
1313
1314
        if (!empty($extra_params['rowNum'])) {
1315
            $obj->rowNum = $extra_params['rowNum'];
1316
        } else {
1317
            // Try to load max rows from Session
1318
            $urlInfo = parse_url($url);
1319
            if (isset($urlInfo['query'])) {
1320
                parse_str($urlInfo['query'], $query);
1321
                if (isset($query['a'])) {
1322
                    $action = $query['a'];
1323
                    // This value is set in model.ajax.php
1324
                    $savedRows = Session::read('max_rows_'.$action);
1325
                    if (!empty($savedRows)) {
1326
                        $obj->rowNum = $savedRows;
1327
                    }
1328
                }
1329
            }
1330
        }
1331
1332
        if (!empty($extra_params['viewrecords'])) {
1333
            $obj->viewrecords = $extra_params['viewrecords'];
1334
        }
1335
1336
        $beforeSelectRow = null;
1337
        if (isset($extra_params['beforeSelectRow'])) {
1338
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1339
            unset($extra_params['beforeSelectRow']);
1340
        }
1341
1342
        $beforeProcessing = '';
1343
        if (isset($extra_params['beforeProcessing'])) {
1344
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1345
            unset($extra_params['beforeProcessing']);
1346
        }
1347
1348
        $beforeRequest = '';
1349
        if (isset($extra_params['beforeRequest'])) {
1350
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1351
            unset($extra_params['beforeRequest']);
1352
        }
1353
1354
        $gridComplete = '';
1355
        if (isset($extra_params['gridComplete'])) {
1356
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1357
            unset($extra_params['gridComplete']);
1358
        }
1359
1360
        // Adding extra params
1361
        if (!empty($extra_params)) {
1362
            foreach ($extra_params as $key => $element) {
1363
                // the groupHeaders key gets a special treatment
1364
                if ('groupHeaders' != $key) {
1365
                    $obj->$key = $element;
1366
                }
1367
            }
1368
        }
1369
1370
        // Adding static data.
1371
        if (!empty($data)) {
1372
            $data_var = $div_id.'_data';
1373
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1374
            $obj->data = $data_var;
1375
            $obj->datatype = 'local';
1376
            $json .= "\n";
1377
        }
1378
1379
        $obj->end = 'end';
1380
1381
        $json_encode = json_encode($obj);
1382
1383
        if (!empty($data)) {
1384
            //Converts the "data":"js_variable" to "data":js_variable,
1385
            // otherwise it will not work
1386
            $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...
1387
        }
1388
1389
        // Fixing true/false js values that doesn't need the ""
1390
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1391
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1392
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1393
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1394
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1395
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1396
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1397
1398
        if (api_get_configuration_value('allow_compilatio_tool') &&
1399
            (false !== strpos($_SERVER['REQUEST_URI'], 'work/work.php') ||
1400
             false != strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php')
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...
1401
            )
1402
        ) {
1403
            $json_encode = str_replace('"function () { compilatioInit() }"',
1404
                'function () { compilatioInit() }',
1405
                $json_encode
1406
            );
1407
        }
1408
        // Creating the jqgrid element.
1409
        $json .= '$("#'.$div_id.'").jqGrid({';
1410
        //$json .= $beforeSelectRow;
1411
        $json .= $gridComplete;
1412
        $json .= $beforeProcessing;
1413
        $json .= $beforeRequest;
1414
        $json .= $json_encode;
1415
        $json .= '});';
1416
1417
        // Grouping headers option
1418
        if (isset($extra_params['groupHeaders'])) {
1419
            $groups = '';
1420
            foreach ($extra_params['groupHeaders'] as $group) {
1421
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1422
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1423
            }
1424
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1425
                "useColSpanStyle" : false,
1426
                "groupHeaders"    : [
1427
                    '.$groups.'
1428
                ]
1429
            });';
1430
        }
1431
1432
        $all_text = addslashes(get_lang('All'));
1433
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1434
        $json .= "\n";
1435
        // Adding edit/delete icons.
1436
        $json .= $formatter;
1437
1438
        return $json;
1439
    }
1440
1441
    /**
1442
     * @param array $headers
1443
     * @param array $rows
1444
     * @param array $attributes
1445
     *
1446
     * @return string
1447
     */
1448
    public static function table($headers, $rows, $attributes = [])
1449
    {
1450
        if (empty($attributes)) {
1451
            $attributes['class'] = 'data_table';
1452
        }
1453
        $table = new HTML_Table($attributes);
1454
        $row = 0;
1455
        $column = 0;
1456
1457
        // Course headers
1458
        if (!empty($headers)) {
1459
            foreach ($headers as $item) {
1460
                $table->setHeaderContents($row, $column, $item);
1461
                $column++;
1462
            }
1463
            $row = 1;
1464
            $column = 0;
1465
        }
1466
1467
        if (!empty($rows)) {
1468
            foreach ($rows as $content) {
1469
                $table->setCellContents($row, $column, $content);
1470
                $row++;
1471
            }
1472
        }
1473
1474
        return $table->toHtml();
1475
    }
1476
1477
    /**
1478
     * Returns the "what's new" icon notifications.
1479
     *
1480
     * The general logic of this function is to track the last time the user
1481
     * entered the course and compare to what has changed inside this course
1482
     * since then, based on the item_property table inside this course. Note that,
1483
     * if the user never entered the course before, he will not see notification
1484
     * icons. This function takes session ID into account (if any) and only shows
1485
     * the corresponding notifications.
1486
     *
1487
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1488
     * @param bool  $loadAjax
1489
     *
1490
     * @return string The HTML link to be shown next to the course
1491
     */
1492
    public static function show_notification($courseInfo, $loadAjax = true)
1493
    {
1494
        // @todo
1495
        return '';
1496
    }
1497
1498
    /**
1499
     * Get the session box details as an array.
1500
     *
1501
     * @todo check session visibility.
1502
     *
1503
     * @param int $session_id
1504
     *
1505
     * @return array Empty array or session array
1506
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1507
     */
1508
    public static function getSessionTitleBox($session_id)
1509
    {
1510
        $session_info = api_get_session_info($session_id);
1511
        $coachInfo = [];
1512
        if (!empty($session_info['id_coach'])) {
1513
            $coachInfo = api_get_user_info($session_info['id_coach']);
1514
        }
1515
1516
        $session = [];
1517
        $session['category_id'] = $session_info['session_category_id'];
1518
        $session['title'] = $session_info['name'];
1519
        $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1520
        $session['dates'] = '';
1521
        $session['coach'] = '';
1522
        if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1523
            $session['coach'] = get_lang('General coach').': '.$coachInfo['complete_name'];
1524
        }
1525
        $active = false;
1526
        if (('0000-00-00 00:00:00' === $session_info['access_end_date'] &&
1527
            '0000-00-00 00:00:00' === $session_info['access_start_date']) ||
1528
            (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1529
        ) {
1530
            if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1531
                $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1532
                $session['duration'] = $daysLeft >= 0
1533
                    ? sprintf(get_lang('This session has a maximum duration. Only %s days to go.'), $daysLeft)
1534
                    : get_lang('You are already registered but your allowed access time has expired.');
1535
            }
1536
            $active = true;
1537
        } else {
1538
            $dates = SessionManager::parseSessionDates($session_info, true);
1539
            $session['dates'] = $dates['access'];
1540
            if ('true' === api_get_setting('show_session_coach') && isset($coachInfo['complete_name'])) {
1541
                $session['coach'] = $coachInfo['complete_name'];
1542
            }
1543
            //$active = $date_start <= $now && $date_end >= $now;
1544
        }
1545
        $session['active'] = $active;
1546
        $session['session_category_id'] = $session_info['session_category_id'];
1547
        $session['visibility'] = $session_info['visibility'];
1548
        $session['num_users'] = $session_info['nbr_users'];
1549
        $session['num_courses'] = $session_info['nbr_courses'];
1550
        $session['description'] = $session_info['description'];
1551
        $session['show_description'] = $session_info['show_description'];
1552
        //$session['image'] = SessionManager::getSessionImage($session_info['id']);
1553
        $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1554
1555
        $entityManager = Database::getManager();
1556
        $fieldValuesRepo = $entityManager->getRepository(ExtraFieldValues::class);
1557
        $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1558
            ExtraField::SESSION_FIELD_TYPE,
1559
            $session_id
1560
        );
1561
1562
        $session['extra_fields'] = [];
1563
        /** @var ExtraFieldValues $value */
1564
        foreach ($extraFieldValues as $value) {
1565
            if (empty($value)) {
1566
                continue;
1567
            }
1568
            $session['extra_fields'][] = [
1569
                'field' => [
1570
                    'variable' => $value->getField()->getVariable(),
1571
                    'display_text' => $value->getField()->getDisplayText(),
1572
                ],
1573
                'value' => $value->getValue(),
1574
            ];
1575
        }
1576
1577
        return $session;
1578
    }
1579
1580
    /**
1581
     * Return the five star HTML.
1582
     *
1583
     * @param string $id              of the rating ul element
1584
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1585
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1586
     * @param bool   $add_div_wrapper add a div wrapper
1587
     *
1588
     * @return string
1589
     */
1590
    public static function return_rating_system(
1591
        $id,
1592
        $url,
1593
        $point_info = [],
1594
        $add_div_wrapper = true
1595
    ) {
1596
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1597
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1598
1599
        if (!empty($percentage)) {
1600
            $percentage = $percentage * 125 / 100;
1601
        }
1602
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1603
        $star_label = sprintf(get_lang('%s stars out of 5'), $point_info['point_average_star']);
1604
1605
        $html = '<section class="rating-widget">';
1606
        $html .= '<div class="rating-stars"><ul id="stars">';
1607
        $html .= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1608
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1609
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1610
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1611
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1612
        ';
1613
        $html .= '</ul></div>';
1614
        $html .= '</section>';
1615
        $labels = [];
1616
1617
        $labels[] = 1 == $number_of_users_who_voted ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1618
        $labels[] = 1 == $accesses ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1619
        $labels[] = $point_info['user_vote'] ? get_lang('Your vote').' ['.$point_info['user_vote'].']' : get_lang('Your vote').' [?] ';
1620
1621
        if (!$add_div_wrapper && api_is_anonymous()) {
1622
            $labels[] = self::tag('span', get_lang('Login to vote'), ['class' => 'error']);
1623
        }
1624
1625
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1626
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1627
1628
        if ($add_div_wrapper) {
1629
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1630
        }
1631
1632
        return $html;
1633
    }
1634
1635
    /**
1636
     * @param string $title
1637
     * @param string $second_title
1638
     * @param string $size
1639
     * @param bool   $filter
1640
     *
1641
     * @return string
1642
     */
1643
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1644
    {
1645
        if ($filter) {
1646
            $title = Security::remove_XSS($title);
1647
        }
1648
1649
        if (!empty($second_title)) {
1650
            if ($filter) {
1651
                $second_title = Security::remove_XSS($second_title);
1652
            }
1653
            $title .= "<small> $second_title</small>";
1654
        }
1655
1656
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1657
    }
1658
1659
    public static function page_header_and_translate($title, $second_title = null)
1660
    {
1661
        $title = get_lang($title);
1662
1663
        return self::page_header($title, $second_title);
1664
    }
1665
1666
    public static function page_subheader_and_translate($title, $second_title = null)
1667
    {
1668
        $title = get_lang($title);
1669
1670
        return self::page_subheader($title, $second_title);
1671
    }
1672
1673
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1674
    {
1675
        if (!empty($second_title)) {
1676
            $second_title = Security::remove_XSS($second_title);
1677
            $title .= "<small> $second_title<small>";
1678
        }
1679
        $subTitle = self::tag($size, Security::remove_XSS($title), $attributes);
1680
1681
        return $subTitle;
1682
    }
1683
1684
    public static function page_subheader2($title, $second_title = null)
1685
    {
1686
        return self::page_header($title, $second_title, 'h4');
1687
    }
1688
1689
    public static function page_subheader3($title, $second_title = null)
1690
    {
1691
        return self::page_header($title, $second_title, 'h5');
1692
    }
1693
1694
    /**
1695
     * @param array $list
1696
     *
1697
     * @return string|null
1698
     */
1699
    public static function description($list)
1700
    {
1701
        $html = null;
1702
        if (!empty($list)) {
1703
            $html = '<dl class="dl-horizontal">';
1704
            foreach ($list as $item) {
1705
                $html .= '<dt>'.$item['title'].'</dt>';
1706
                $html .= '<dd>'.$item['content'].'</dd>';
1707
            }
1708
            $html .= '</dl>';
1709
        }
1710
1711
        return $html;
1712
    }
1713
1714
    /**
1715
     * @param int    $percentage      int value between 0 and 100
1716
     * @param bool   $show_percentage
1717
     * @param string $extra_info
1718
     * @param string $class           danger/success/infowarning
1719
     *
1720
     * @return string
1721
     */
1722
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1723
    {
1724
        $percentage = (int) $percentage;
1725
        $class = empty($class) ? '' : "progress-bar-$class";
1726
1727
        $div = '<div class="progress">
1728
                <div
1729
                    class="progress-bar progress-bar-striped '.$class.'"
1730
                    role="progressbar"
1731
                    aria-valuenow="'.$percentage.'"
1732
                    aria-valuemin="0"
1733
                    aria-valuemax="100"
1734
                    style="width: '.$percentage.'%;"
1735
                >';
1736
        if ($show_percentage) {
1737
            $div .= $percentage.'%';
1738
        } else {
1739
            if (!empty($extra_info)) {
1740
                $div .= $extra_info;
1741
            }
1742
        }
1743
        $div .= '</div></div>';
1744
1745
        return $div;
1746
    }
1747
1748
    /**
1749
     * @param string $count
1750
     * @param string $type
1751
     *
1752
     * @return string|null
1753
     */
1754
    public static function badge($count, $type = 'warning')
1755
    {
1756
        $class = '';
1757
1758
        switch ($type) {
1759
            case 'success':
1760
                $class = 'bg-success';
1761
                break;
1762
            case 'warning':
1763
                $class = 'bg-warning text-dark';
1764
                break;
1765
            case 'important':
1766
                $class = 'bg-important';
1767
                break;
1768
            case 'info':
1769
                $class = 'bg-info';
1770
                break;
1771
            case 'inverse':
1772
                $class = 'bg-inverse';
1773
                break;
1774
        }
1775
1776
        if (!empty($count)) {
1777
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1778
        }
1779
1780
        return null;
1781
    }
1782
1783
    /**
1784
     * @param array $badge_list
1785
     *
1786
     * @return string
1787
     */
1788
    public static function badge_group($badge_list)
1789
    {
1790
        $html = '<div class="badge-group">';
1791
        foreach ($badge_list as $badge) {
1792
            $html .= $badge;
1793
        }
1794
        $html .= '</div>';
1795
1796
        return $html;
1797
    }
1798
1799
    /**
1800
     * @param string $content
1801
     * @param string $type
1802
     *
1803
     * @return string
1804
     */
1805
    public static function label($content, $type = 'default')
1806
    {
1807
        switch ($type) {
1808
            case 'success':
1809
                $class = 'success';
1810
                break;
1811
            case 'warning':
1812
                $class = 'warning text-dark';
1813
                break;
1814
            case 'important':
1815
            case 'danger':
1816
                $class = 'danger';
1817
                break;
1818
            case 'info':
1819
                $class = 'info';
1820
                break;
1821
            case 'primary':
1822
                $class = 'primary';
1823
                break;
1824
            default:
1825
                $class = 'secondary';
1826
                break;
1827
        }
1828
1829
        $html = '';
1830
        if (!empty($content)) {
1831
            $html = '<span class="badge bg-'.$class.'">';
1832
            $html .= $content;
1833
            $html .= '</span>';
1834
        }
1835
1836
        return $html;
1837
    }
1838
1839
    /**
1840
     * @param array  $items
1841
     * @param string $class
1842
     */
1843
    public static function actions($items, $class = 'new_actions'): string
1844
    {
1845
        if (empty($items)) {
1846
            return '';
1847
        }
1848
        $links = '';
1849
        foreach ($items as $value) {
1850
            /*$class = '';
1851
            if (isset($value['active']) && $value['active']) {
1852
                $class = 'class ="active"';
1853
            }
1854
1855
            if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
1856
                $class = 'class ="active"';
1857
            }
1858
            $html .= "<li $class >";*/
1859
1860
            $attributes = $value['url_attributes'] ?? [];
1861
            $links .= self::url($value['content'], $value['url'], $attributes);
1862
        }
1863
1864
        return self::toolbarAction(uniqid('toolbar', false), [$links]);
1865
    }
1866
1867
    /**
1868
     * Prints a tooltip.
1869
     *
1870
     * @param string $text
1871
     * @param string $tip
1872
     *
1873
     * @return string
1874
     */
1875
    public static function tip($text, $tip)
1876
    {
1877
        if (empty($tip)) {
1878
            return $text;
1879
        }
1880
1881
        return self::span(
1882
            $text,
1883
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
1884
        );
1885
    }
1886
1887
    /**
1888
     * @param array  $items
1889
     * @param string $type
1890
     * @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...
1891
     *
1892
     * @return string|null
1893
     */
1894
    public static function generate_accordion($items, $type = 'jquery', $id = null)
1895
    {
1896
        $html = null;
1897
        if (!empty($items)) {
1898
            if (empty($id)) {
1899
                $id = api_get_unique_id();
1900
            }
1901
            if ('jquery' == $type) {
1902
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
1903
            } else {
1904
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
1905
            }
1906
1907
            $count = 1;
1908
            foreach ($items as $item) {
1909
                $html .= '<div class="accordion-my-group">';
1910
                $html .= '<div class="accordion-heading">
1911
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
1912
                            '.$item['title'].'
1913
                            </a>
1914
                          </div>';
1915
1916
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
1917
                $html .= '<div class="accordion-my-inner">
1918
                            '.$item['content'].'
1919
                            </div>
1920
                          </div>';
1921
            }
1922
            $html .= '</div>';
1923
        }
1924
1925
        return $html;
1926
    }
1927
1928
    /**
1929
     * @param array $buttons
1930
     *
1931
     * @return string
1932
     */
1933
    public static function groupButton($buttons)
1934
    {
1935
        $html = '<div class="btn-group" role="group">';
1936
        foreach ($buttons as $button) {
1937
            $html .= $button;
1938
        }
1939
        $html .= '</div>';
1940
1941
        return $html;
1942
    }
1943
1944
    /**
1945
     * @todo use twig
1946
     *
1947
     * @param string $title
1948
     * @param array  $elements
1949
     * @param bool   $alignToRight
1950
     *
1951
     * @return string
1952
     */
1953
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
1954
    {
1955
        $id = uniqid('dropdown', false);
1956
        $html = '
1957
        <div class="dropdown inline-block relative">
1958
            <button
1959
                id="'.$id.'"
1960
                type="button"
1961
                class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
1962
                aria-expanded="false"
1963
                aria-haspopup="true"
1964
            >
1965
              '.$title.'
1966
              <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
1967
                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
1968
              </svg>
1969
            </button>
1970
            <div
1971
                id="'.$id.'_menu"
1972
                class=" dropdown-menu hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
1973
                role="menu"
1974
                aria-orientation="vertical"
1975
                aria-labelledby="menu-button"
1976
                tabindex="-1"
1977
            >
1978
            <div class="py-1" role="none">';
1979
            foreach ($elements as $item) {
1980
                $html .= self::url(
1981
                    $item['title'],
1982
                    $item['href'],
1983
                    [
1984
                        'class' => 'text-gray-700 block px-4 py-2 text-sm',
1985
                        'role' => 'menuitem',
1986
                        'onclick' => $item['onclick'] ?? '',
1987
                        'data-action' => $item['data-action'] ?? '',
1988
                    ]
1989
                );
1990
            }
1991
        $html .= '
1992
            </div>
1993
            </div>
1994
            </div>
1995
            <script>
1996
             document.addEventListener("DOMContentLoaded", function() {
1997
                const button = document.querySelector("#'.$id.'");
1998
                    button.addEventListener("click", (e) => {
1999
                    let menu = document.querySelector("#'.$id.'_menu");
2000
                    if (menu.classList.contains("hidden")) {
2001
                        menu.classList.remove("hidden");
2002
                    } else {
2003
                        menu.classList.add("hidden");
2004
                    }
2005
                });
2006
            });
2007
            </script>';
2008
2009
        return $html;
2010
    }
2011
2012
    /**
2013
     * @param string $file
2014
     * @param array  $params
2015
     *
2016
     * @return string|null
2017
     */
2018
    public static function getMediaPlayer($file, $params = [])
2019
    {
2020
        $fileInfo = pathinfo($file);
2021
2022
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2023
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2024
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2025
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2026
2027
        switch ($fileInfo['extension']) {
2028
            case 'mp3':
2029
            case 'webm':
2030
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2031
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2032
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2033
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2034
                          </object>';
2035
                $html .= '</audio>';
2036
2037
                return $html;
2038
                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...
2039
            case 'wav':
2040
            case 'ogg':
2041
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >';
2042
2043
                return $html;
2044
                break;
2045
        }
2046
2047
        return null;
2048
    }
2049
2050
    /**
2051
     * @param int    $nextValue
2052
     * @param array  $list
2053
     * @param int    $current
2054
     * @param int    $fixedValue
2055
     * @param array  $conditions
2056
     * @param string $link
2057
     * @param bool   $isMedia
2058
     * @param bool   $addHeaders
2059
     * @param array  $linkAttributes
2060
     *
2061
     * @return string
2062
     */
2063
    public static function progressPaginationBar(
2064
        $nextValue,
2065
        $list,
2066
        $current,
2067
        $fixedValue = null,
2068
        $conditions = [],
2069
        $link = null,
2070
        $isMedia = false,
2071
        $addHeaders = true,
2072
        $linkAttributes = []
2073
    ) {
2074
        if ($addHeaders) {
2075
            $pagination_size = 'pagination-mini';
2076
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2077
        } else {
2078
            $html = null;
2079
        }
2080
        $affectAllItems = false;
2081
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2082
            $affectAllItems = true;
2083
        }
2084
        $localCounter = 0;
2085
        foreach ($list as $itemId) {
2086
            $isCurrent = false;
2087
            if ($affectAllItems) {
2088
                $isCurrent = true;
2089
            } else {
2090
                if (!$isMedia) {
2091
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2092
                }
2093
            }
2094
            $html .= self::parsePaginationItem(
2095
                $itemId,
2096
                $isCurrent,
2097
                $conditions,
2098
                $link,
2099
                $nextValue,
2100
                $isMedia,
2101
                $localCounter,
2102
                $fixedValue,
2103
                $linkAttributes
2104
            );
2105
            $localCounter++;
2106
        }
2107
        if ($addHeaders) {
2108
            $html .= '</ul></div>';
2109
        }
2110
2111
        return $html;
2112
    }
2113
2114
    /**
2115
     * @param int    $itemId
2116
     * @param bool   $isCurrent
2117
     * @param array  $conditions
2118
     * @param string $link
2119
     * @param int    $nextValue
2120
     * @param bool   $isMedia
2121
     * @param int    $localCounter
2122
     * @param int    $fixedValue
2123
     * @param array  $linkAttributes
2124
     *
2125
     * @return string
2126
     */
2127
    public static function parsePaginationItem(
2128
        $itemId,
2129
        $isCurrent,
2130
        $conditions,
2131
        $link,
2132
        $nextValue = 0,
2133
        $isMedia = false,
2134
        $localCounter = null,
2135
        $fixedValue = null,
2136
        $linkAttributes = []
2137
    ) {
2138
        $defaultClass = 'before';
2139
        $class = $defaultClass;
2140
        foreach ($conditions as $condition) {
2141
            $array = isset($condition['items']) ? $condition['items'] : [];
2142
            $class_to_applied = $condition['class'];
2143
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2144
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2145
            switch ($type) {
2146
                case 'positive':
2147
                    if (in_array($itemId, $array)) {
2148
                        if ('overwrite' == $mode) {
2149
                            $class = " $defaultClass $class_to_applied";
2150
                        } else {
2151
                            $class .= " $class_to_applied";
2152
                        }
2153
                    }
2154
                    break;
2155
                case 'negative':
2156
                    if (!in_array($itemId, $array)) {
2157
                        if ('overwrite' == $mode) {
2158
                            $class = " $defaultClass $class_to_applied";
2159
                        } else {
2160
                            $class .= " $class_to_applied";
2161
                        }
2162
                    }
2163
                    break;
2164
            }
2165
        }
2166
        if ($isCurrent) {
2167
            $class = 'before current';
2168
        }
2169
        if ($isMedia && $isCurrent) {
2170
            $class = 'before current';
2171
        }
2172
        if (empty($link)) {
2173
            $link_to_show = '#';
2174
        } else {
2175
            $link_to_show = $link.($nextValue + $localCounter);
2176
        }
2177
        $label = $nextValue + $localCounter + 1;
2178
        if ($isMedia) {
2179
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2180
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2181
        }
2182
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2183
2184
        return '<li class = "'.$class.'">'.$link.'</li>';
2185
    }
2186
2187
    /**
2188
     * @param int $current
2189
     * @param int $total
2190
     *
2191
     * @return string
2192
     */
2193
    public static function paginationIndicator($current, $total)
2194
    {
2195
        $html = null;
2196
        if (!empty($current) && !empty($total)) {
2197
            $label = sprintf(get_lang('%s of %s'), $current, $total);
2198
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2199
        }
2200
2201
        return $html;
2202
    }
2203
2204
    /**
2205
     * @param $url
2206
     * @param $currentPage
2207
     * @param $pagesCount
2208
     * @param $totalItems
2209
     *
2210
     * @return string
2211
     */
2212
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2213
    {
2214
        $pagination = '';
2215
        if ($totalItems > 1 && $pagesCount > 1) {
2216
            $pagination .= '<ul class="pagination">';
2217
            for ($i = 0; $i < $pagesCount; $i++) {
2218
                $newPage = $i + 1;
2219
                if ($currentPage == $newPage) {
2220
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2221
                } else {
2222
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2223
                }
2224
            }
2225
            $pagination .= '</ul>';
2226
        }
2227
2228
        return $pagination;
2229
    }
2230
2231
    /**
2232
     * Adds a legacy message in the queue.
2233
     *
2234
     * @param string $message
2235
     */
2236
    public static function addFlash($message)
2237
    {
2238
        // Detect type of message.
2239
        $parts = preg_match('/alert-([a-z]*)/', $message, $matches);
2240
        $type = 'primary';
2241
        if ($parts && isset($matches[1]) && $matches[1]) {
2242
            $type = $matches[1];
2243
        }
2244
        // Detect legacy content of message.
2245
        $result = preg_match('/<div(.*?)\>(.*?)\<\/div>/s', $message, $matches);
2246
        if ($result && isset($matches[2])) {
2247
            Container::getSession()->getFlashBag()->add($type, $matches[2]);
2248
        }
2249
    }
2250
2251
    /**
2252
     * Get the profile edition link for a user.
2253
     *
2254
     * @param int  $userId  The user id
2255
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2256
     *
2257
     * @return string The link
2258
     */
2259
    public static function getProfileEditionLink($userId, $asAdmin = false)
2260
    {
2261
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2262
        if ($asAdmin) {
2263
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2264
        }
2265
2266
        return $editProfileUrl;
2267
    }
2268
2269
    /**
2270
     * Get the vCard for a user.
2271
     *
2272
     * @param int $userId The user id
2273
     *
2274
     * @return string *.*vcf file
2275
     */
2276
    public static function getVCardUserLink($userId)
2277
    {
2278
        return api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2279
    }
2280
2281
    /**
2282
     * @param string $content
2283
     * @param string $title
2284
     * @param string $footer
2285
     * @param string $type        primary|success|info|warning|danger
2286
     * @param string $extra
2287
     * @param string $id
2288
     * @param string $customColor
2289
     * @param string $rightAction
2290
     *
2291
     * @return string
2292
     */
2293
    public static function panel(
2294
        $content,
2295
        $title = '',
2296
        $footer = '',
2297
        $type = 'default',
2298
        $extra = '',
2299
        $id = '',
2300
        $customColor = '',
2301
        $rightAction = ''
2302
    ) {
2303
        $headerStyle = '';
2304
        if (!empty($customColor)) {
2305
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2306
        }
2307
2308
        if (!empty($rightAction)) {
2309
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2310
        }
2311
2312
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2313
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2314
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2315
        $style = !in_array($type, $typeList) ? 'default' : $type;
2316
2317
        if (!empty($id)) {
2318
            $id = " id='$id'";
2319
        }
2320
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2321
2322
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2323
2324
        return '
2325
            <div '.$id.' class="card">
2326
                '.$panel.'
2327
            </div>'
2328
        ;
2329
    }
2330
2331
    /**
2332
     * @param string $content
2333
     */
2334
    public static function contentPanel($content): string
2335
    {
2336
        if (empty($content)) {
2337
            return '';
2338
        }
2339
2340
        return '<div class="card-text">'.$content.'</div>';
2341
    }
2342
2343
    /**
2344
     * Get the button HTML with an Awesome Font icon.
2345
     *
2346
     * @param string $text        The button content
2347
     * @param string $url         The url to button
2348
     * @param string $icon        The Awesome Font class for icon
2349
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2350
     * @param array  $attributes  The additional attributes
2351
     * @param bool   $includeText
2352
     *
2353
     * @return string The button HTML
2354
     */
2355
    public static function toolbarButton(
2356
        $text,
2357
        $url,
2358
        $icon = 'check',
2359
        $type = null,
2360
        array $attributes = [],
2361
        $includeText = true
2362
    ) {
2363
        $buttonClass = "btn btn-outline-secondary";
2364
        if (!empty($type)) {
2365
            $buttonClass = "btn btn-$type";
2366
        }
2367
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2368
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2369
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2370
2371
        if (!$includeText) {
2372
            $text = '<span class="sr-only">'.$text.'</span>';
2373
        }
2374
2375
        return self::url("$icon $text", $url, $attributes);
2376
    }
2377
2378
    public static function toolbarAction(string $id, array $contentList): string
2379
    {
2380
        $contentList = array_filter($contentList);
2381
2382
        if (empty($contentList)) {
2383
            return '';
2384
        }
2385
2386
        $col = count($contentList);
2387
        $html = ' <div id="'.$id.'" class="q-card p-2 mb-4">';
2388
        $html .= ' <div class="flex justify-between '.$col.'">';
2389
        foreach ($contentList as $item) {
2390
            $html .= '<div class="flex p-2 gap-2 ">'.$item.'</div>';
2391
        }
2392
        $html .= '</div>';
2393
        $html .= '</div>';
2394
2395
        return $html;
2396
    }
2397
2398
    /**
2399
     * Get a HTML code for a icon by Font Awesome.
2400
     *
2401
     * @param string     $name            The icon name. Example: "mail-reply"
2402
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2403
     * @param bool       $fixWidth        Optional. Whether add the fw class
2404
     * @param string     $additionalClass Optional. Additional class
2405
     *
2406
     * @return string
2407
     */
2408
    public static function returnFontAwesomeIcon(
2409
        $name,
2410
        $size = '',
2411
        $fixWidth = false,
2412
        $additionalClass = ''
2413
    ) {
2414
        $className = "fa fa-$name";
2415
2416
        if ($fixWidth) {
2417
            $className .= ' fa-fw';
2418
        }
2419
2420
        switch ($size) {
2421
            case 'xs':
2422
            case 'sm':
2423
            case 'lg':
2424
                $className .= " fa-{$size}";
2425
                break;
2426
            case 2:
2427
            case 3:
2428
            case 4:
2429
            case 5:
2430
                $className .= " fa-{$size}x";
2431
                break;
2432
        }
2433
2434
        if (!empty($additionalClass)) {
2435
            $className .= " $additionalClass";
2436
        }
2437
2438
        $icon = self::tag('em', null, ['class' => $className]);
2439
2440
        return "$icon ";
2441
    }
2442
2443
    /**
2444
     * @param string     $title
2445
     * @param string     $content
2446
     * @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...
2447
     * @param array      $params
2448
     * @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...
2449
     * @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...
2450
     * @param bool|true  $open
2451
     * @param bool|false $fullClickable
2452
     *
2453
     * @return string
2454
     *
2455
     * @todo rework function to easy use
2456
     */
2457
    public static function panelCollapse(
2458
        $title,
2459
        $content,
2460
        $id = null,
2461
        $params = [],
2462
        $idAccordion = null,
2463
        $idCollapse = null,
2464
        $open = true,
2465
        $fullClickable = false
2466
    ) {
2467
        if (!empty($idAccordion)) {
2468
            $headerClass = '';
2469
            $headerClass .= $fullClickable ? 'center-block ' : '';
2470
            $headerClass .= $open ? '' : 'collapsed';
2471
            $contentClass = 'panel-collapse collapse ';
2472
            $contentClass .= $open ? 'in' : '';
2473
            $ariaExpanded = $open ? 'true' : 'false';
2474
2475
            $html = <<<HTML
2476
                <div class="card" id="$id">
2477
                    <div class="card-header">
2478
                        $title
2479
                    </div>
2480
                    <div class="card-body">$content</div>
2481
                </div>
2482
HTML;
2483
        } else {
2484
            if (!empty($id)) {
2485
                $params['id'] = $id;
2486
            }
2487
            $params['class'] = 'card';
2488
            $html = '';
2489
            if (!empty($title)) {
2490
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2491
            }
2492
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2493
            $html = self::div($html, $params);
2494
        }
2495
2496
        return $html;
2497
    }
2498
2499
    /**
2500
     * Returns the string "1 day ago" with a link showing the exact date time.
2501
     *
2502
     * @param string $dateTime in UTC or a DateTime in UTC
2503
     *
2504
     * @return string
2505
     */
2506
    public static function dateToStringAgoAndLongDate($dateTime)
2507
    {
2508
        if (empty($dateTime) || '0000-00-00 00:00:00' === $dateTime) {
2509
            return '';
2510
        }
2511
2512
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2513
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2514
        }
2515
2516
        return self::tip(
2517
            date_to_str_ago($dateTime),
2518
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2519
            //api_get_local_time($dateTime)
2520
        );
2521
    }
2522
2523
    /**
2524
     * @param array  $userInfo
2525
     * @param string $status
2526
     * @param string $toolbar
2527
     *
2528
     * @return string
2529
     */
2530
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2531
    {
2532
        if (empty($userInfo)) {
2533
            return '';
2534
        }
2535
2536
        if (!empty($status)) {
2537
            $status = '<div class="items-user-status">'.$status.'</div>';
2538
        }
2539
2540
        if (!empty($toolbar)) {
2541
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2542
        }
2543
2544
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">
2545
                    <img src="'.$userInfo['avatar'].'" class="rounded" />
2546
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>
2547
                    <div class="card-body">
2548
                       <div class="card-title">
2549
                       '.$status.'
2550
                       '.$toolbar.'
2551
                       </div>
2552
                    </div>
2553
                    <hr />
2554
              </div>';
2555
    }
2556
2557
    /**
2558
     * @param string $fileName
2559
     * @param string $fileUrl
2560
     *
2561
     * @return string
2562
     */
2563
    public static function fileHtmlGuesser($fileName, $fileUrl)
2564
    {
2565
        $data = pathinfo($fileName);
2566
2567
        //$content = self::url($data['basename'], $fileUrl);
2568
        $content = '';
2569
        switch ($data['extension']) {
2570
            case 'webm':
2571
            case 'mp4':
2572
            case 'ogg':
2573
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2574
                // Allows video to play when loading during an ajax call
2575
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2576
                break;
2577
            case 'jpg':
2578
            case 'jpeg':
2579
            case 'gif':
2580
            case 'png':
2581
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2582
                break;
2583
            default:
2584
                //$html = self::url($data['basename'], $fileUrl);
2585
                break;
2586
        }
2587
        //$html = self::url($content, $fileUrl, ['ajax']);
2588
2589
        return $content;
2590
    }
2591
2592
    /**
2593
     * @param string $frameName
2594
     *
2595
     * @return string
2596
     */
2597
    public static function getFrameReadyBlock($frameName)
2598
    {
2599
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2600
        $videoFeatures = [
2601
            'playpause',
2602
            'current',
2603
            'progress',
2604
            'duration',
2605
            'tracks',
2606
            'volume',
2607
            'fullscreen',
2608
            'vrview',
2609
            'markersrolls',
2610
        ];
2611
        $features = api_get_configuration_value('video_features');
2612
        $videoPluginsJS = [];
2613
        $videoPluginCSS = [];
2614
        if (!empty($features) && isset($features['features'])) {
2615
            foreach ($features['features'] as $feature) {
2616
                if ('vrview' === $feature) {
2617
                    continue;
2618
                }
2619
                $defaultFeatures[] = $feature;
2620
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.js";
2621
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.css";
2622
            }
2623
        }
2624
2625
        $videoPluginFiles = '';
2626
        foreach ($videoPluginsJS as $file) {
2627
            $videoPluginFiles .= '{type: "script", src: "'.$webPublicPath.'assets/'.$file.'"},';
2628
        }
2629
2630
        $videoPluginCssFiles = '';
2631
        foreach ($videoPluginCSS as $file) {
2632
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webPublicPath.'assets/'.$file.'"},';
2633
        }
2634
2635
        $translateHtml = '';
2636
        $translate = api_get_configuration_value('translate_html');
2637
        if ($translate) {
2638
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2639
        }
2640
2641
        $lpJs = api_get_path(WEB_PUBLIC_PATH).'build/lp.js';
2642
        // {type:"script", src:"'.api_get_jquery_ui_js_web_path().'"},
2643
        // {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/markersrolls/markersrolls.js"},
2644
        // {type:"script", src:"'.$webPublicPath.'build/libs/mathjax/MathJax.js?config=AM_HTMLorMML"},
2645
        $videoFeatures = implode("','", $videoFeatures);
2646
        $frameReady = '
2647
        $.frameReady(function() {
2648
             $(function () {
2649
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2650
                    pluginPath: "'.$webPublicPath.'assets/mediaelement/plugins/",
2651
                    features: [\''.$videoFeatures.'\'],
2652
                    success: function(mediaElement, originalNode, instance) {
2653
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2654
                    },
2655
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2656
                });
2657
            });
2658
        },
2659
        "'.$frameName.'",
2660
        [
2661
            {type:"script", src:"'.$lpJs.'", deps: [
2662
2663
            {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2664
2665
            {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/mediaelement-and-player.min.js",
2666
                deps: [
2667
                {type:"script", src: "'.$webPublicPath.'build/libs/mediaelement/plugins/vrview/vrview.js"},
2668
                '.$videoPluginFiles.'
2669
            ]},
2670
            '.$translateHtml.'
2671
            ]},
2672
            '.$videoPluginCssFiles.'
2673
        ]);';
2674
2675
        return $frameReady;
2676
    }
2677
2678
    /**
2679
     * @param string $image
2680
     * @param int    $size
2681
     *
2682
     * @return string
2683
     */
2684
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2685
    {
2686
        return self::return_icon($image, '', [], $size, false, true);
2687
    }
2688
2689
    /**
2690
     * @param string $image
2691
     * @param int    $size
2692
     * @param string $name
2693
     *
2694
     * @return string
2695
     */
2696
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
2697
    {
2698
        return self::return_icon($image, $name, [], $size);
2699
    }
2700
2701
    /**
2702
     * @param $id
2703
     *
2704
     * @return array|mixed
2705
     */
2706
    public static function randomColor($id)
2707
    {
2708
        static $colors = [];
2709
2710
        if (!empty($colors[$id])) {
2711
            return $colors[$id];
2712
        } else {
2713
            $color = substr(md5(time() * $id), 0, 6);
2714
            $c1 = hexdec(substr($color, 0, 2));
2715
            $c2 = hexdec(substr($color, 2, 2));
2716
            $c3 = hexdec(substr($color, 4, 2));
2717
            $luminosity = $c1 + $c2 + $c3;
2718
2719
            $type = '#000000';
2720
            if ($luminosity < (255 + 255 + 255) / 2) {
2721
                $type = '#FFFFFF';
2722
            }
2723
2724
            $result = [
2725
                'color' => '#'.$color,
2726
                'luminosity' => $type,
2727
            ];
2728
            $colors[$id] = $result;
2729
2730
            return $result; // example: #fc443a
2731
        }
2732
    }
2733
2734
    public static function noDataView(string $title, string $icon, string $buttonTitle, string $url): string
2735
    {
2736
        $content = '<div id="no-data-view">';
2737
        $content .= '<h3>'.$title.'</h3>';
2738
        $content .= $icon;
2739
        $content .= '<div class="controls">';
2740
        $content .= self::url(
2741
            '<em class="fa fa-plus"></em> '.$buttonTitle,
2742
            $url,
2743
            ['class' => 'btn btn-primary']
2744
        );
2745
        $content .= '</div>';
2746
        $content .= '</div>';
2747
2748
        return $content;
2749
    }
2750
}
2751