Passed
Push — master ( f23aa1...456a08 )
by Julito
11:24 queued 01:42
created

Display::display_introduction_section()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 7
rs 10
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
            if (!empty($interbreadcrumb)) {
131
                array_unshift(
132
                    $interbreadcrumb,
133
                    ['name' => $courseInfo['title'], 'url' => $url]
134
                );
135
            }
136
        }
137
138
        $params['legacy_javascript'] = $htmlHeadXtra;
139
        $params['legacy_breadcrumb'] = $interbreadcrumb;
140
141
        Template::setVueParams($params);
142
        $content = Container::getTwig()->render($tpl, $params);
143
        $response->setContent($content);
144
        $response->send();
145
        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...
146
    }
147
148
    /**
149
     * Display the page footer.
150
     */
151
    public static function display_reduced_footer()
152
    {
153
        $contents = ob_get_contents();
154
        if (ob_get_length()) {
155
            ob_end_clean();
156
        }
157
        $tpl = '@ChamiloCore/Layout/no_layout.html.twig';
158
        if (!empty(self::$legacyTemplate)) {
159
            $tpl = self::$legacyTemplate;
160
        }
161
        $response = new Response();
162
        $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...
163
        global $interbreadcrumb, $htmlHeadXtra;
164
        $params['legacy_javascript'] = $htmlHeadXtra;
165
        $params['legacy_breadcrumb'] = $interbreadcrumb;
166
167
        $content = Container::getTwig()->render($tpl, $params);
168
        $response->setContent($content);
169
        $response->send();
170
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

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