Completed
Push — master ( ae5621...ef667c )
by Julito
13:23
created

Display::page_header()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 6
nop 4
dl 0
loc 14
rs 9.2
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
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...
5
use ChamiloSession as Session;
6
7
/**
8
 * Class Display
9
 * Contains several public functions dealing with the display of
10
 * table data, messages, help topics, ...
11
 *
12
 * Include/require it in your code to use its public functionality.
13
 * There are also several display public functions in the main api library.
14
 *
15
 * All public functions static public functions inside a class called Display,
16
 * so you use them like this: e.g.
17
 * Display::return_message($message)
18
 *
19
 * @package chamilo.library
20
 */
21
class Display
22
{
23
    /** @var Template */
24
    public static $global_template;
25
    public static $preview_style = null;
26
27
    /**
28
     * Constructor.
29
     */
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
        $origin = api_get_origin();
65
        $showHeader = true;
66
        if (isset($origin) && $origin == 'learnpath') {
67
            $showHeader = false;
68
        }
69
70
        self::$global_template = new Template($tool_name, $showHeader, $showHeader);
71
72
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
73
        if (empty($help)) {
74
            $currentURL = api_get_self();
75
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
76
            $toolList = self::toolList();
77
            if (!empty($matches)) {
78
                foreach ($matches as $match) {
79
                    if (in_array($match, $toolList)) {
80
                        $help = explode('_', $match);
81
                        $help = array_map('ucfirst', $help);
82
                        $help = implode('', $help);
83
                        break;
84
                    }
85
                }
86
            }
87
        }
88
89
        self::$global_template->setHelp($help);
90
91
        if (!empty(self::$preview_style)) {
92
            self::$global_template->preview_theme = self::$preview_style;
93
            self::$global_template->set_system_parameters();
94
            self::$global_template->setCssFiles();
95
            self::$global_template->set_js_files();
96
            self::$global_template->setCssCustomFiles();
97
        }
98
99
        if (!empty($page_header)) {
100
            self::$global_template->assign('header', $page_header);
101
        }
102
103
        echo self::$global_template->show_header_template();
104
    }
105
106
    /**
107
     * Displays the reduced page header (without banner).
108
     */
109
    public static function display_reduced_header()
110
    {
111
        global $show_learnpath, $tool_name;
112
        self::$global_template = new Template(
113
            $tool_name,
114
            false,
115
            false,
116
            $show_learnpath
117
        );
118
        echo self::$global_template->show_header_template();
119
    }
120
121
    /**
122
     * Display no header.
123
     */
124
    public static function display_no_header()
125
    {
126
        global $tool_name, $show_learnpath;
127
        $disable_js_and_css_files = true;
128
        self::$global_template = new Template(
129
            $tool_name,
130
            false,
131
            false,
132
            $show_learnpath
133
        );
134
    }
135
136
    /**
137
     * Displays the reduced page header (without banner).
138
     */
139
    public static function set_header()
140
    {
141
        global $show_learnpath, $tool_name;
142
        self::$global_template = new Template(
143
            $tool_name,
144
            false,
145
            false,
146
            $show_learnpath
147
        );
148
    }
149
150
    /**
151
     * Display the page footer.
152
     */
153
    public static function display_footer()
154
    {
155
        echo self::$global_template->show_footer_template();
156
    }
157
158
    /**
159
     * Display the page footer.
160
     */
161
    public static function display_reduced_footer()
162
    {
163
        echo self::$global_template->show_footer_js_template();
164
        echo '</body></html>';
165
    }
166
167
    /**
168
     * Displays the tool introduction of a tool.
169
     *
170
     * @author Patrick Cool <[email protected]>, Ghent University
171
     *
172
     * @param string $tool          these are the constants that are used for indicating the tools
173
     * @param array  $editor_config Optional configuration settings for the online editor.
174
     *                              return: $tool return a string array list with the "define" in main_api.lib
175
     *
176
     * @return string html code for adding an introduction
177
     */
178
    public static function display_introduction_section(
179
        $tool,
180
        $editor_config = null
181
    ) {
182
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::return_introductio...($tool, $editor_config) targeting Display::return_introduction_section() seems to always return null.

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

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

}

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

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

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

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

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

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

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

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

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

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

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

Loading history...
369
        $visibility_options = true,
370
        $sort_data = true,
371
        $grid_class = [],
372
        $elementCount = 0
373
    ) {
374
        $column = 0;
375
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
376
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
377
        $table->total_number_of_items = intval($elementCount);
378
        if (is_array($query_vars)) {
379
            $table->set_additional_parameters($query_vars);
380
        }
381
382
        return $table->display_simple_grid(
383
            $visibility_options,
384
            $paging_options['hide_navigation'],
385
            $default_items_per_page,
386
            $sort_data,
387
            $grid_class
388
        );
389
    }
390
391
    /**
392
     * Displays a table with a special configuration.
393
     *
394
     * @param array $header          Titles for the table header
395
     *                               each item in this array can contain 3 values
396
     *                               - 1st element: the column title
397
     *                               - 2nd element: true or false (column sortable?)
398
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
399
     *                               - 4the element: additional attributes for the td-tags
400
     * @param array $content         2D-array with the tables content
401
     * @param array $sorting_options Keys are:
402
     *                               'column' = The column to use as sort-key
403
     *                               'direction' = SORT_ASC or SORT_DESC
404
     * @param array $paging_options  Keys are:
405
     *                               'per_page_default' = items per page when switching from full list to per-page-view
406
     *                               'per_page' = number of items to show per page
407
     *                               'page_nr' = The page to display
408
     * @param array $query_vars      Additional variables to add in the query-string
409
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
410
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
411
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
412
     * @param array $form_actions    Set optional forms actions
413
     *
414
     * @author Julio Montoya
415
     */
416
    public static function display_sortable_config_table(
417
        $table_name,
418
        $header,
419
        $content,
420
        $sorting_options = [],
421
        $paging_options = [],
422
        $query_vars = null,
423
        $column_show = [],
424
        $column_order = [],
425
        $form_actions = []
426
    ) {
427
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
428
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
429
430
        $table = new SortableTableFromArrayConfig(
431
            $content,
432
            $column,
433
            $default_items_per_page,
434
            $table_name,
435
            $column_show,
436
            $column_order
437
        );
438
439
        if (is_array($query_vars)) {
440
            $table->set_additional_parameters($query_vars);
441
        }
442
        // Show or hide the columns header
443
        if (is_array($column_show)) {
444
            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...
445
                if (!empty($column_show[$i])) {
446
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
447
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
448
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
449
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
450
                    $table->set_header($i, $val0, $val1, $val2, $val3);
451
                }
452
            }
453
        }
454
        $table->set_form_actions($form_actions);
455
        $table->display();
456
    }
457
458
    /**
459
     * Displays a normal message. It is recommended to use this public function
460
     * to display any normal information messages.
461
     *
462
     * @param string $message
463
     * @param bool   $filter      (true) or not (false)
464
     * @param bool   $returnValue
465
     *
466
     * @deprecated Use <code>Display::addFlash(Display::return_message($message, 'normal'));</code>
467
     *  Or <code>echo Display::return_message($message, 'normal')</code>
468
     */
469
    public static function display_normal_message(
470
        $message,
471
        $filter = true,
472
        $returnValue = false
473
    ) {
474
        $message = self::return_message($message, 'normal', $filter);
475
        if ($returnValue) {
476
            return $message;
477
        } else {
478
            echo $message;
479
        }
480
    }
481
482
    /**
483
     * Displays an warning message. Use this if you want to draw attention to something
484
     * This can also be used for instance with the hint in the exercises.
485
     *
486
     * @deprecated use Display::addFlash(Display::return_message($message, 'warning'));
487
     */
488
    public static function display_warning_message(
489
        $message,
490
        $filter = true,
491
        $returnValue = false
492
    ) {
493
        $message = self::return_message($message, 'warning', $filter);
494
        if ($returnValue) {
495
            return $message;
496
        } else {
497
            echo $message;
498
        }
499
    }
500
501
    /**
502
     * Displays an confirmation message. Use this if something has been done successfully.
503
     *
504
     * @param bool    Filter (true) or not (false)
505
     *
506
     * @deprecated use Display::addFlash(Display::return_message($message, 'confirm'));
507
     */
508
    public static function display_confirmation_message(
509
        $message,
510
        $filter = true,
511
        $returnValue = false
512
    ) {
513
        $message = self::return_message($message, 'confirm', $filter);
514
        if ($returnValue) {
515
            return $message;
516
        } else {
517
            echo $message;
518
        }
519
    }
520
521
    /**
522
     * Displays an error message. It is recommended to use this public function if an error occurs.
523
     *
524
     * @param string $message - include any additional html
525
     *                        tags if you need them
526
     * @param bool    Filter (true) or not (false)
527
     *
528
     * @deprecated use Display::addFlash(Display::return_message($message, 'error'));
529
     */
530
    public static function display_error_message(
531
        $message,
532
        $filter = true,
533
        $returnValue = false
534
    ) {
535
        $message = self::return_message($message, 'error', $filter);
536
        if ($returnValue) {
537
            return $message;
538
        } else {
539
            echo $message;
540
        }
541
    }
542
543
    /**
544
     * @param string $message
545
     * @param string $type
546
     * @param bool   $filter
547
     */
548
    public static function return_message_and_translate(
549
        $message,
550
        $type = 'normal',
551
        $filter = true
552
    ) {
553
        $message = get_lang($message);
554
        echo self::return_message($message, $type, $filter);
555
    }
556
557
    /**
558
     * Returns a div html string with.
559
     *
560
     * @param string $message
561
     * @param string $type    Example: confirm, normal, warning, error
562
     * @param bool   $filter  Whether to XSS-filter or not
563
     *
564
     * @return string Message wrapped into an HTML div
565
     */
566
    public static function return_message(
567
        $message,
568
        $type = 'normal',
569
        $filter = true
570
    ) {
571
        if (empty($message)) {
572
            return '';
573
        }
574
575
        if ($filter) {
576
            $message = api_htmlentities(
577
                $message,
578
                ENT_QUOTES,
579
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
580
            );
581
        }
582
583
        $class = '';
584
        switch ($type) {
585
            case 'warning':
586
                $class .= 'alert alert-warning';
587
                break;
588
            case 'error':
589
                $class .= 'alert alert-danger';
590
                break;
591
            case 'confirmation':
592
            case 'confirm':
593
            case 'success':
594
                $class .= 'alert alert-success';
595
                break;
596
            case 'normal':
597
            default:
598
                $class .= 'alert alert-info';
599
        }
600
601
        return self::div($message, ['class' => $class]);
602
    }
603
604
    /**
605
     * Returns an encrypted mailto hyperlink.
606
     *
607
     * @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...
608
     * @param string  clickable text
609
     * @param string  optional, class from stylesheet
610
     *
611
     * @return string encrypted mailto hyperlink
612
     */
613
    public static function encrypted_mailto_link(
614
        $email,
615
        $clickable_text = null,
616
        $style_class = ''
617
    ) {
618
        if (is_null($clickable_text)) {
619
            $clickable_text = $email;
620
        }
621
        // "mailto:" already present?
622
        if (substr($email, 0, 7) != 'mailto:') {
623
            $email = 'mailto:'.$email;
624
        }
625
        // Class (stylesheet) defined?
626
        if ($style_class != '') {
627
            $style_class = ' class="'.$style_class.'"';
628
        }
629
        // Encrypt email
630
        $hmail = '';
631
        for ($i = 0; $i < strlen($email); $i++) {
632
            $hmail .= '&#'.ord($email[
633
            $i]).';';
634
        }
635
        $hclickable_text = null;
636
        // Encrypt clickable text if @ is present
637
        if (strpos($clickable_text, '@')) {
638
            for ($i = 0; $i < strlen($clickable_text); $i++) {
639
                $hclickable_text .= '&#'.ord($clickable_text[
640
                $i]).';';
641
            }
642
        } else {
643
            $hclickable_text = @htmlspecialchars(
644
                $clickable_text,
645
                ENT_QUOTES,
646
                api_get_system_encoding()
647
            );
648
        }
649
        // Return encrypted mailto hyperlink
650
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
651
    }
652
653
    /**
654
     * Returns an mailto icon hyperlink.
655
     *
656
     * @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...
657
     * @param string  icon source file from the icon lib
658
     * @param int  icon size from icon lib
659
     * @param string  optional, class from stylesheet
660
     *
661
     * @return string encrypted mailto hyperlink
662
     */
663
    public static function icon_mailto_link(
664
        $email,
665
        $icon_file = "mail.png",
666
        $icon_size = 22,
667
        $style_class = ''
668
    ) {
669
        // "mailto:" already present?
670
        if (substr($email, 0, 7) != 'mailto:') {
671
            $email = 'mailto:'.$email;
672
        }
673
        // Class (stylesheet) defined?
674
        if ($style_class != '') {
675
            $style_class = ' class="'.$style_class.'"';
676
        }
677
        // Encrypt email
678
        $hmail = '';
679
        for ($i = 0; $i < strlen($email); $i++) {
680
            $hmail .= '&#'.ord($email[
681
            $i]).';';
682
        }
683
        // icon html code
684
        $icon_html_source = self::return_icon(
685
            $icon_file,
686
            $hmail,
687
            '',
688
            $icon_size
689
        );
690
        // Return encrypted mailto hyperlink
691
692
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
693
    }
694
695
    /**
696
     * Prints an <option>-list with all letters (A-Z).
697
     *
698
     * @param string $selected_letter The letter that should be selected
699
     *
700
     * @todo This is English language specific implementation.
701
     * It should be adapted for the other languages.
702
     *
703
     * @return string
704
     */
705
    public static function get_alphabet_options($selectedLetter = '')
706
    {
707
        $result = '';
708
        for ($i = 65; $i <= 90; $i++) {
709
            $letter = chr($i);
710
            $result .= '<option value="'.$letter.'"';
711
            if ($selectedLetter == $letter) {
712
                $result .= ' selected="selected"';
713
            }
714
            $result .= '>'.$letter.'</option>';
715
        }
716
717
        return $result;
718
    }
719
720
    /**
721
     * Get the options withing a select box within the given values.
722
     *
723
     * @param int   Min value
724
     * @param int   Max value
725
     * @param int   Default value
726
     *
727
     * @return string HTML select options
728
     */
729
    public static function get_numeric_options($min, $max, $selected_num = 0)
730
    {
731
        $result = '';
732
        for ($i = $min; $i <= $max; $i++) {
733
            $result .= '<option value="'.$i.'"';
734
            if (is_int($selected_num)) {
735
                if ($selected_num == $i) {
736
                    $result .= ' selected="selected"';
737
                }
738
            }
739
            $result .= '>'.$i.'</option>';
740
        }
741
742
        return $result;
743
    }
744
745
    /**
746
     * This public function displays an icon.
747
     *
748
     * @param string   The filename of the file (in the main/img/ folder
749
     * @param string   The alt text (probably a language variable)
750
     * @param array    additional attributes (for instance height, width, onclick, ...)
751
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
752
     */
753
    public static function display_icon(
754
        $image,
755
        $alt_text = '',
756
        $additional_attributes = [],
757
        $size = null
758
    ) {
759
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
760
    }
761
762
    /**
763
     * Gets the path of an icon.
764
     *
765
     * @param string $icon
766
     * @param int    $size
767
     *
768
     * @return string
769
     */
770
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
771
    {
772
        return self::return_icon($icon, null, null, $size, null, true, false);
773
    }
774
775
    /**
776
     * This public function returns the htmlcode for an icon.
777
     *
778
     * @param string   The filename of the file (in the main/img/ folder
779
     * @param string   The alt text (probably a language variable)
780
     * @param array    Additional attributes (for instance height, width, onclick, ...)
781
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
782
     *
783
     * @return string An HTML string of the right <img> tag
784
     *
785
     * @author Patrick Cool <[email protected]>, Ghent University 2006
786
     * @author Julio Montoya 2010 Function improved, adding image constants
787
     * @author Yannick Warnier 2011 Added size handler
788
     *
789
     * @version Feb 2011
790
     */
791
    public static function return_icon(
792
        $image,
793
        $alt_text = '',
794
        $additional_attributes = [],
795
        $size = ICON_SIZE_SMALL,
796
        $show_text = true,
797
        $return_only_path = false,
798
        $loadThemeIcon = true
799
    ) {
800
        $code_path = api_get_path(SYS_PUBLIC_PATH);
801
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
802
        // The following path is checked to see if the file exist. It's
803
        // important to use the public path (i.e. web/css/) rather than the
804
        // internal path (/app/Resource/public/css/) because the path used
805
        // in the end must be the public path
806
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
807
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
808
809
        // Avoid issues with illegal string offset for legacy calls to this
810
        // method with an empty string rather than null or an empty array
811
        if (empty($additional_attributes)) {
812
            $additional_attributes = [];
813
        }
814
815
        $image = trim($image);
816
817
        if (isset($size)) {
818
            $size = intval($size);
819
        } else {
820
            $size = ICON_SIZE_SMALL;
821
        }
822
823
        $size_extra = $size.'/';
824
        $icon = $w_code_path.'img/'.$image;
825
        $theme = 'themes/chamilo/icons/';
826
827
        if ($loadThemeIcon) {
828
            // @todo with chamilo 2 code
829
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
830
            if (is_file($alternateCssPath.$theme.$image)) {
831
                $icon = $alternateWebCssPath.$theme.$image;
832
            }
833
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
834
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
835
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
836
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
837
                //Checking the main/img/icons/XXX/ folder
838
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
839
            }
840
        } else {
841
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
842
                // Checking the main/img/icons/XXX/ folder
843
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
844
            }
845
        }
846
847
        // Special code to enable SVG - refs #7359 - Needs more work
848
        // The code below does something else to "test out" SVG: for each icon,
849
        // it checks if there is an SVG version. If so, it uses it.
850
        // When moving this to production, the return_icon() calls should
851
        // ask for the SVG version directly
852
        $svgIcons = api_get_setting('icons_mode_svg');
853
        if ($svgIcons == 'true' && $return_only_path == false) {
854
            $svgImage = substr($image, 0, -3).'svg';
855
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
856
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
857
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
858
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
859
            }
860
861
            if (empty($additional_attributes['height'])) {
862
                $additional_attributes['height'] = $size;
863
            }
864
            if (empty($additional_attributes['width'])) {
865
                $additional_attributes['width'] = $size;
866
            }
867
        }
868
869
        $icon = api_get_cdn_path($icon);
870
871
        if ($return_only_path) {
872
            return $icon;
873
        }
874
875
        $img = self::img($icon, $alt_text, $additional_attributes);
876
        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...
877
            if ($show_text) {
878
                $img = "$img $alt_text";
879
            }
880
        }
881
882
        return $img;
883
    }
884
885
    /**
886
     * Returns the htmlcode for an image.
887
     *
888
     * @param string $image_path            the filename of the file (in the main/img/ folder
889
     * @param string $alt_text              the alt text (probably a language variable)
890
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
891
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
892
     *
893
     * @return string
894
     *
895
     * @author Julio Montoya 2010
896
     */
897
    public static function img(
898
        $image_path,
899
        $alt_text = '',
900
        $additional_attributes = null,
901
        $filterPath = true
902
    ) {
903
        if (empty($image_path)) {
904
            // For some reason, the call to img() happened without a proper
905
            // image. Log the error and return an empty string to avoid
906
            // breaking the HTML
907
            $trace = debug_backtrace();
908
            $caller = $trace[1];
909
            //error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
910
            return '';
911
        }
912
        // Sanitizing the parameter $image_path
913
        if ($filterPath) {
914
            $image_path = Security::filter_img_path($image_path);
915
        }
916
917
        // alt text = the image name if there is none provided (for XHTML compliance)
918
        if ($alt_text == '') {
919
            $alt_text = basename($image_path);
920
        }
921
922
        if (empty($additional_attributes)) {
923
            $additional_attributes = [];
924
        }
925
926
        $additional_attributes['src'] = $image_path;
927
928
        if (empty($additional_attributes['alt'])) {
929
            $additional_attributes['alt'] = $alt_text;
930
        }
931
        if (empty($additional_attributes['title'])) {
932
            $additional_attributes['title'] = $alt_text;
933
        }
934
935
        return self::tag('img', '', $additional_attributes);
936
    }
937
938
    /**
939
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
940
     *
941
     * @param string $tag                   the tag name
942
     * @param string $content               the tag's content
943
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
944
     *
945
     * @return string
946
     *
947
     * @author Julio Montoya 2010
948
     */
949
    public static function tag($tag, $content, $additional_attributes = [])
950
    {
951
        $attribute_list = '';
952
        // Managing the additional attributes
953
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
954
            $attribute_list = '';
955
            foreach ($additional_attributes as $key => &$value) {
956
                $attribute_list .= $key.'="'.$value.'" ';
957
            }
958
        }
959
        //some tags don't have this </XXX>
960
        if (in_array($tag, ['img', 'input', 'br'])) {
961
            $return_value = '<'.$tag.' '.$attribute_list.' />';
962
        } else {
963
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
964
        }
965
966
        return $return_value;
967
    }
968
969
    /**
970
     * Creates a URL anchor.
971
     *
972
     * @param string $name
973
     * @param string $url
974
     * @param array  $attributes
975
     *
976
     * @return string
977
     */
978
    public static function url($name, $url, $attributes = [])
979
    {
980
        if (!empty($url)) {
981
            $url = preg_replace('#&amp;#', '&', $url);
982
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
983
            $attributes['href'] = $url;
984
        }
985
986
        return self::tag('a', $name, $attributes);
987
    }
988
989
    /**
990
     * Creates a div tag.
991
     *
992
     * @param string $content
993
     * @param array  $attributes
994
     *
995
     * @return string
996
     */
997
    public static function div($content, $attributes = [])
998
    {
999
        return self::tag('div', $content, $attributes);
1000
    }
1001
1002
    /**
1003
     * Creates a span tag.
1004
     */
1005
    public static function span($content, $attributes = [])
1006
    {
1007
        return self::tag('span', $content, $attributes);
1008
    }
1009
1010
    /**
1011
     * Displays an HTML input tag.
1012
     */
1013
    public static function input($type, $name, $value, $attributes = [])
1014
    {
1015
        if (isset($type)) {
1016
            $attributes['type'] = $type;
1017
        }
1018
        if (isset($name)) {
1019
            $attributes['name'] = $name;
1020
        }
1021
        if (isset($value)) {
1022
            $attributes['value'] = $value;
1023
        }
1024
1025
        return self::tag('input', '', $attributes);
1026
    }
1027
1028
    /**
1029
     * @param $name
1030
     * @param $value
1031
     * @param array $attributes
1032
     *
1033
     * @return string
1034
     */
1035
    public static function button($name, $value, $attributes = [])
1036
    {
1037
        if (!empty($name)) {
1038
            $attributes['name'] = $name;
1039
        }
1040
1041
        return self::tag('button', $value, $attributes);
1042
    }
1043
1044
    /**
1045
     * Displays an HTML select tag.
1046
     *
1047
     * @param string $name
1048
     * @param array  $values
1049
     * @param int    $default
1050
     * @param array  $extra_attributes
1051
     * @param bool   $show_blank_item
1052
     * @param null   $blank_item_text
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $blank_item_text is correct as it would always require null to be passed?
Loading history...
1053
     *
1054
     * @return string
1055
     */
1056
    public static function select(
1057
        $name,
1058
        $values,
1059
        $default = -1,
1060
        $extra_attributes = [],
1061
        $show_blank_item = true,
1062
        $blank_item_text = ''
1063
    ) {
1064
        $html = '';
1065
        $extra = '';
1066
        $default_id = 'id="'.$name.'" ';
1067
        foreach ($extra_attributes as $key => $parameter) {
1068
            if ($key == 'id') {
1069
                $default_id = '';
1070
            }
1071
            $extra .= $key.'="'.$parameter.'" ';
1072
        }
1073
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1074
1075
        if ($show_blank_item) {
1076
            if (empty($blank_item_text)) {
1077
                $blank_item_text = get_lang('Select');
1078
            } else {
1079
                $blank_item_text = Security::remove_XSS($blank_item_text);
1080
            }
1081
            $html .= self::tag(
1082
                'option',
1083
                '-- '.$blank_item_text.' --',
1084
                ['value' => '-1']
1085
            );
1086
        }
1087
        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...
1088
            foreach ($values as $key => $value) {
1089
                if (is_array($value) && isset($value['name'])) {
1090
                    $value = $value['name'];
1091
                }
1092
                $html .= '<option value="'.$key.'"';
1093
1094
                if (is_array($default)) {
1095
                    foreach ($default as $item) {
1096
                        if ($item == $key) {
1097
                            $html .= ' selected="selected"';
1098
                            break;
1099
                        }
1100
                    }
1101
                } else {
1102
                    if ($default == $key) {
1103
                        $html .= ' selected="selected"';
1104
                    }
1105
                }
1106
1107
                $html .= '>'.$value.'</option>';
1108
            }
1109
        }
1110
        $html .= '</select>';
1111
1112
        return $html;
1113
    }
1114
1115
    /**
1116
     * Creates a tab menu
1117
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1118
     * in the $htmlHeadXtra variable before the display_header
1119
     * Add this script.
1120
     *
1121
     * @example
1122
     * <script>
1123
                </script>
1124
     * @param array  $headers       list of the tab titles
1125
     * @param array  $items
1126
     * @param string $id            id of the container of the tab in the example "tabs"
1127
     * @param array  $attributes    for the ul
1128
     * @param array  $ul_attributes
1129
     *
1130
     * @return string
1131
     */
1132
    public static function tabs(
1133
        $headers,
1134
        $items,
1135
        $id = 'tabs',
1136
        $attributes = [],
1137
        $ul_attributes = []
1138
    ) {
1139
        if (empty($headers) || count($headers) == 0) {
1140
            return '';
1141
        }
1142
1143
        $lis = '';
1144
        $i = 1;
1145
        foreach ($headers as $item) {
1146
            $active = '';
1147
            if ($i == 1) {
1148
                $active = ' active';
1149
            }
1150
            $item = self::tag(
1151
                'a',
1152
                $item,
1153
                [
1154
                    'href' => '#'.$id.'-'.$i,
1155
                    'role' => 'tab',
1156
                    'data-toggle' => 'tab',
1157
                    'id' => $id.$i,
1158
                ]
1159
            );
1160
            $ul_attributes['role'] = 'presentation';
1161
            $ul_attributes['class'] = $active;
1162
            $lis .= self::tag('li', $item, $ul_attributes);
1163
            $i++;
1164
        }
1165
        $ul = self::tag(
1166
            'ul',
1167
            $lis,
1168
            [
1169
                'class' => 'nav nav-tabs tabs-margin',
1170
                'role' => 'tablist',
1171
                'id' => 'ul_'.$id,
1172
            ]
1173
        );
1174
1175
        $i = 1;
1176
        $divs = '';
1177
        foreach ($items as $content) {
1178
            $active = '';
1179
            if ($i == 1) {
1180
                $active = ' active';
1181
            }
1182
            $divs .= self::tag(
1183
                'div',
1184
                $content,
1185
                ['id' => $id.'-'.$i, 'class' => 'tab-pane '.$active, 'role' => 'tabpanel']
1186
            );
1187
            $i++;
1188
        }
1189
1190
        $attributes['id'] = $id;
1191
        $attributes['role'] = 'tabpanel';
1192
        $attributes['class'] = 'tab-wrapper';
1193
1194
        $main_div = self::tag(
1195
            'div',
1196
            $ul.self::tag('div', $divs, ['class' => 'tab-content']),
1197
            $attributes
1198
        );
1199
1200
        return $main_div;
1201
    }
1202
1203
    /**
1204
     * @param $headers
1205
     * @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...
1206
     *
1207
     * @return string
1208
     */
1209
    public static function tabsOnlyLink($headers, $selected = null)
1210
    {
1211
        $id = uniqid();
1212
        $i = 1;
1213
        $lis = null;
1214
        foreach ($headers as $item) {
1215
            $class = null;
1216
            if ($i == $selected) {
1217
                $class = 'active';
1218
            }
1219
            $item = self::tag(
1220
                'a',
1221
                $item['content'],
1222
                ['id' => $id.'-'.$i, 'href' => $item['url']]
1223
            );
1224
            $lis .= self::tag('li', $item, ['class' => $class]);
1225
            $i++;
1226
        }
1227
1228
        return self::tag(
1229
            'ul',
1230
            $lis,
1231
            ['class' => 'nav nav-tabs tabs-margin']
1232
        );
1233
    }
1234
1235
    /**
1236
     * In order to display a grid using jqgrid you have to:.
1237
     *
1238
     * @example
1239
     * After your Display::display_header function you have to add the nex javascript code:
1240
     * <script>
1241
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1242
     *   // for more information of this function check the grid_js() function
1243
     * </script>
1244
     * //Then you have to call the grid_html
1245
     * echo Display::grid_html('my_grid_name');
1246
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1247
     *
1248
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1249
     *
1250
     * @return string html
1251
     */
1252
    public static function grid_html($div_id)
1253
    {
1254
        $table = self::tag('table', '', ['id' => $div_id]);
1255
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1256
1257
        return $table;
1258
    }
1259
1260
    /**
1261
     * @param string $label
1262
     * @param string $form_item
1263
     *
1264
     * @return string
1265
     */
1266
    public static function form_row($label, $form_item)
1267
    {
1268
        $label = self::span($label, ['class' => 'control-label']);
1269
        $form_item = self::div($form_item, ['class' => 'controls']);
1270
1271
        return self::div($label.$form_item, ['class' => 'control-group']);
1272
    }
1273
1274
    /**
1275
     * This is a wrapper to use the jqgrid in Chamilo.
1276
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1277
     * This function need to be in the ready jquery function
1278
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1279
     * In order to work this function needs the Display::grid_html function with the same div id.
1280
     *
1281
     * @param string $div_id       div id
1282
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1283
     * @param array  $column_names Visible columns (you should use get_lang).
1284
     *                             An array in which we place the names of the columns.
1285
     *                             This is the text that appears in the head of the grid (Header layer).
1286
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1287
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1288
     *                             This is the most important part of the grid.
1289
     *                             For a full description of all valid values see colModel API. See the url above.
1290
     * @param array  $extra_params extra parameters
1291
     * @param array  $data         data that will be loaded
1292
     * @param string $formatter    A string that will be appended to the JSON returned
1293
     * @param bool   $fixed_width  not implemented yet
1294
     *
1295
     * @return string the js code
1296
     */
1297
    public static function grid_js(
1298
        $div_id,
1299
        $url,
1300
        $column_names,
1301
        $column_model,
1302
        $extra_params,
1303
        $data = [],
1304
        $formatter = '',
1305
        $fixed_width = false
0 ignored issues
show
Unused Code introduced by
The parameter $fixed_width is not used and could be removed. ( Ignorable by Annotation )

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

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

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

Loading history...
1306
    ) {
1307
        $obj = new stdClass();
1308
        $obj->first = 'first';
1309
1310
        if (!empty($url)) {
1311
            $obj->url = $url;
1312
        }
1313
1314
        //This line should only be used/modified in case of having characters
1315
        // encoding problems - see #6159
1316
        //$column_names = array_map("utf8_encode", $column_names);
1317
        $obj->colNames = $column_names;
1318
        $obj->colModel = $column_model;
1319
        $obj->pager = '#'.$div_id.'_pager';
1320
        $obj->datatype = 'json';
1321
        $obj->viewrecords = 'true';
1322
        $all_value = 10000000;
1323
1324
        // Default row quantity
1325
        if (!isset($extra_params['rowList'])) {
1326
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1327
        }
1328
1329
        $json = '';
1330
        if (!empty($extra_params['datatype'])) {
1331
            $obj->datatype = $extra_params['datatype'];
1332
        }
1333
1334
        // Row even odd style.
1335
        $obj->altRows = true;
1336
        if (!empty($extra_params['altRows'])) {
1337
            $obj->altRows = $extra_params['altRows'];
1338
        }
1339
1340
        if (!empty($extra_params['sortname'])) {
1341
            $obj->sortname = $extra_params['sortname'];
1342
        }
1343
1344
        if (!empty($extra_params['sortorder'])) {
1345
            $obj->sortorder = $extra_params['sortorder'];
1346
        }
1347
1348
        if (!empty($extra_params['rowList'])) {
1349
            $obj->rowList = $extra_params['rowList'];
1350
        }
1351
1352
        // Sets how many records we want to view in the grid
1353
        $obj->rowNum = 20;
1354
        if (!empty($extra_params['rowNum'])) {
1355
            $obj->rowNum = $extra_params['rowNum'];
1356
        } else {
1357
            // Try to load max rows from Session
1358
            $urlInfo = parse_url($url);
1359
            if (isset($urlInfo['query'])) {
1360
                parse_str($urlInfo['query'], $query);
1361
                if (isset($query['a'])) {
1362
                    $action = $query['a'];
1363
                    // This value is set in model.ajax.php
1364
                    $savedRows = Session::read('max_rows_'.$action);
1365
                    if (!empty($savedRows)) {
1366
                        $obj->rowNum = $savedRows;
1367
                    }
1368
                }
1369
            }
1370
        }
1371
1372
        if (!empty($extra_params['viewrecords'])) {
1373
            $obj->viewrecords = $extra_params['viewrecords'];
1374
        }
1375
1376
        $beforeSelectRow = null;
1377
        if (isset($extra_params['beforeSelectRow'])) {
1378
            $beforeSelectRow = "beforeSelectRow: ".$extra_params['beforeSelectRow'].", ";
1379
            unset($extra_params['beforeSelectRow']);
1380
        }
1381
1382
        // Adding extra params
1383
        if (!empty($extra_params)) {
1384
            foreach ($extra_params as $key => $element) {
1385
                // the groupHeaders key gets a special treatment
1386
                if ($key != 'groupHeaders') {
1387
                    $obj->$key = $element;
1388
                }
1389
            }
1390
        }
1391
1392
        // Adding static data.
1393
        if (!empty($data)) {
1394
            $data_var = $div_id.'_data';
1395
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1396
            $obj->data = $data_var;
1397
            $obj->datatype = 'local';
1398
            $json .= "\n";
1399
        }
1400
1401
        $obj->end = 'end';
1402
1403
        $json_encode = json_encode($obj);
1404
1405
        if (!empty($data)) {
1406
            //Converts the "data":"js_variable" to "data":js_variable,
1407
            // otherwise it will not work
1408
            $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...
1409
        }
1410
1411
        // Fixing true/false js values that doesn't need the ""
1412
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1413
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1414
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1415
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1416
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1417
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1418
1419
        // Creating the jqgrid element.
1420
        $json .= '$("#'.$div_id.'").jqGrid({';
1421
        //$json .= $beforeSelectRow;
1422
        $json .= $json_encode;
1423
        $json .= '});';
1424
1425
        // Grouping headers option
1426
        if (isset($extra_params['groupHeaders'])) {
1427
            $groups = '';
1428
            foreach ($extra_params['groupHeaders'] as $group) {
1429
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1430
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1431
            }
1432
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1433
                "useColSpanStyle" : false,
1434
                "groupHeaders"    : [
1435
                    '.$groups.'
1436
                ]
1437
            });';
1438
        }
1439
1440
        $all_text = addslashes(get_lang('All'));
1441
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1442
        $json .= "\n";
1443
        // Adding edit/delete icons.
1444
        $json .= $formatter;
1445
1446
        return $json;
1447
    }
1448
1449
    /**
1450
     * @param array $headers
1451
     * @param array $rows
1452
     * @param array $attributes
1453
     *
1454
     * @return string
1455
     */
1456
    public static function table($headers, $rows, $attributes = [])
1457
    {
1458
        if (empty($attributes)) {
1459
            $attributes['class'] = 'data_table';
1460
        }
1461
        $table = new HTML_Table($attributes);
1462
        $row = 0;
1463
        $column = 0;
1464
1465
        // Course headers
1466
        if (!empty($headers)) {
1467
            foreach ($headers as $item) {
1468
                $table->setHeaderContents($row, $column, $item);
1469
                $column++;
1470
            }
1471
            $row = 1;
1472
            $column = 0;
1473
        }
1474
1475
        if (!empty($rows)) {
1476
            foreach ($rows as $content) {
1477
                $table->setCellContents($row, $column, $content);
1478
                $row++;
1479
            }
1480
        }
1481
1482
        return $table->toHtml();
1483
    }
1484
1485
    /**
1486
     * Returns the "what's new" icon notifications.
1487
     *
1488
     * The general logic of this function is to track the last time the user
1489
     * entered the course and compare to what has changed inside this course
1490
     * since then, based on the item_property table inside this course. Note that,
1491
     * if the user never entered the course before, he will not see notification
1492
     * icons. This function takes session ID into account (if any) and only shows
1493
     * the corresponding notifications.
1494
     *
1495
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1496
     * @param bool  $loadAjax
1497
     *
1498
     * @return string The HTML link to be shown next to the course
1499
     */
1500
    public static function show_notification($courseInfo, $loadAjax = true)
1501
    {
1502
        if (empty($courseInfo)) {
1503
            return '';
1504
        }
1505
1506
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1507
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1508
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1509
        $course_code = Database::escape_string($courseInfo['code']);
1510
1511
        $user_id = api_get_user_id();
1512
        $course_id = (int) $courseInfo['real_id'];
1513
        $sessionId = (int) $courseInfo['id_session'];
1514
        $status = (int) $courseInfo['status'];
1515
1516
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1517
1518
        if ($loadNotificationsByAjax) {
1519
            if ($loadAjax) {
1520
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1521
                Session::write($id, true);
1522
1523
                return '<span id ="'.$id.'" class="course_notification"></span>';
1524
            }
1525
        }
1526
1527
        // Get the user's last access dates to all tools of this course
1528
        $sql = "SELECT *
1529
                FROM $t_track_e_access
1530
                WHERE
1531
                    c_id = $course_id AND
1532
                    access_user_id = '$user_id' AND
1533
                    access_session_id ='".$sessionId."'
1534
                ORDER BY access_date DESC 
1535
                LIMIT 1
1536
                ";
1537
        $result = Database::query($sql);
1538
1539
        // latest date by default is the creation date
1540
        $latestDate = $courseInfo['creation_date'];
1541
        if (Database::num_rows($result)) {
1542
            $row = Database::fetch_array($result, 'ASSOC');
1543
            $latestDate = $row['access_date'];
1544
        }
1545
1546
        $sessionCondition = api_get_session_condition(
1547
            $sessionId,
1548
            true,
1549
            false,
1550
            'session_id'
1551
        );
1552
1553
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1554
        // Get current tools in course
1555
        $sql = "SELECT name, link, image 
1556
                FROM $course_tool_table 
1557
                WHERE 
1558
                    c_id = $course_id AND 
1559
                    visibility = '1' AND
1560
                    name NOT IN ('".implode("','", $hideTools)."')
1561
                ";
1562
        $result = Database::query($sql);
1563
        $tools = Database::store_result($result);
1564
1565
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1566
        $group_ids[] = 0; //add group 'everyone'
1567
        $notifications = [];
1568
        if ($tools) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tools of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1569
            foreach ($tools as $tool) {
1570
                $toolName = $tool['name'];
1571
                $toolName = Database::escape_string($toolName);
1572
                // Fix to get student publications
1573
                $toolCondition = " tool = '$toolName' AND ";
1574
                if ($toolName == 'student_publication' || $toolName == 'work') {
1575
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1576
                }
1577
1578
                $toolName = addslashes($toolName);
1579
1580
                $sql = "SELECT * FROM $tool_edit_table 
1581
                        WHERE
1582
                            c_id = $course_id AND
1583
                            $toolCondition
1584
                            lastedit_type NOT LIKE '%Deleted%' AND
1585
                            lastedit_type NOT LIKE '%deleted%' AND
1586
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1587
                            lastedit_date > '$latestDate' AND
1588
                            lastedit_user_id != $user_id $sessionCondition AND
1589
                            visibility != 2 AND
1590
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1591
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1592
                        ORDER BY lastedit_date DESC
1593
                        LIMIT 1";
1594
                $result = Database::query($sql);
1595
1596
                $latestChange = Database::fetch_array($result, 'ASSOC');
1597
1598
                if ($latestChange) {
1599
                    $latestChange['link'] = $tool['link'];
1600
                    $latestChange['image'] = $tool['image'];
1601
                    $latestChange['tool'] = $tool['name'];
1602
                    $notifications[$toolName] = $latestChange;
1603
                }
1604
            }
1605
        }
1606
1607
        // Show all tool icons where there is something new.
1608
        $return = '';
1609
        foreach ($notifications as $notification) {
1610
            $toolName = $notification['tool'];
1611
            if (!(
1612
                    $notification['visibility'] == '1' ||
1613
                    ($status == '1' && $notification['visibility'] == '0') ||
1614
                    !isset($notification['visibility'])
1615
                )
1616
            ) {
1617
                continue;
1618
            }
1619
1620
            if ($toolName == TOOL_SURVEY) {
1621
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1622
                if (!empty($survey_info)) {
1623
                    $invited_users = SurveyUtil::get_invited_users(
1624
                        $survey_info['code'],
1625
                        $course_code
1626
                    );
1627
                    if (!in_array($user_id, $invited_users['course_users'])) {
1628
                        continue;
1629
                    }
1630
                }
1631
            }
1632
1633
            if ($notification['tool'] == TOOL_LEARNPATH) {
1634
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $course_code)) {
1635
                    continue;
1636
                }
1637
            }
1638
1639
            if ($notification['tool'] == TOOL_DROPBOX) {
1640
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1641
            }
1642
1643
            if ($notification['tool'] == 'work' &&
1644
                $notification['lastedit_type'] == 'DirectoryCreated'
1645
            ) {
1646
                $notification['lastedit_type'] = 'WorkAdded';
1647
            }
1648
1649
            $lastDate = api_get_local_time($notification['lastedit_date']);
1650
            $type = $notification['lastedit_type'];
1651
            if ($type == 'CalendareventVisible') {
1652
                $type = 'Visible';
1653
            }
1654
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1655
1656
            if (strpos($notification['link'], '?') === false) {
1657
                $notification['link'] = $notification['link'].'?notification=1';
1658
            } else {
1659
                $notification['link'] = $notification['link'].'&notification=1';
1660
            }
1661
1662
            $image = substr($notification['image'], 0, -4).'.png';
1663
1664
            $return .= self::url(
1665
                self::return_icon($image, $label),
1666
                api_get_path(WEB_CODE_PATH).
1667
                $notification['link'].'&cidReq='.$course_code.
1668
                '&ref='.$notification['ref'].
1669
                '&gidReq='.$notification['to_group_id'].
1670
                '&id_session='.$sessionId
1671
            ).PHP_EOL;
1672
        }
1673
1674
        return $return;
1675
    }
1676
1677
    /**
1678
     * Get the session box details as an array.
1679
     *
1680
     * @param int       Session ID
1681
     *
1682
     * @return array Empty array or session array
1683
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1684
     */
1685
    public static function getSessionTitleBox($session_id)
1686
    {
1687
        global $nosession;
1688
1689
        if (!$nosession) {
1690
            global $now, $date_start, $date_end;
1691
        }
1692
        $output = [];
1693
        if (!$nosession) {
1694
            $main_user_table = Database::get_main_table(TABLE_MAIN_USER);
1695
            $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
1696
            // Request for the name of the general coach
1697
            $sql = 'SELECT tu.lastname, tu.firstname, ts.*
1698
                    FROM '.$tbl_session.' ts
1699
                    LEFT JOIN '.$main_user_table.' tu
1700
                    ON ts.id_coach = tu.user_id
1701
                    WHERE ts.id = '.intval($session_id);
1702
            $rs = Database::query($sql);
1703
            $session_info = Database::store_result($rs, 'ASSOC');
1704
            $session_info = $session_info[0];
1705
1706
            $session = [];
1707
            $session['category_id'] = $session_info['session_category_id'];
1708
            $session['title'] = $session_info['name'];
1709
            $session['id_coach'] = $session_info['id_coach'];
1710
            $session['coach'] = '';
1711
            $session['dates'] = '';
1712
1713
            if (api_get_setting('show_session_coach') === 'true') {
1714
                $session['coach'] = get_lang('GeneralCoach').': '.api_get_person_name($session_info['firstname'], $session_info['lastname']);
1715
            }
1716
1717
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1718
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1719
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1720
            ) {
1721
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1722
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1723
                    $session['duration'] = $daysLeft >= 0
1724
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1725
                        : get_lang('YourSessionTimeHasExpired');
1726
                }
1727
                $active = true;
1728
            } else {
1729
                $dates = SessionManager::parseSessionDates($session_info, true);
1730
                $session['dates'] = $dates['access'];
1731
                if (api_get_setting('show_session_coach') === 'true') {
1732
                    $session['coach'] = api_get_person_name(
1733
                        $session_info['firstname'],
1734
                        $session_info['lastname']
1735
                    );
1736
                }
1737
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $date_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_end does not seem to be defined for all execution paths leading up to this point.
Loading history...
1738
            }
1739
            $session['active'] = $active;
1740
            $session['session_category_id'] = $session_info['session_category_id'];
1741
            $session['visibility'] = $session_info['visibility'];
1742
            $session['num_users'] = $session_info['nbr_users'];
1743
            $session['num_courses'] = $session_info['nbr_courses'];
1744
            $session['description'] = $session_info['description'];
1745
            $session['show_description'] = $session_info['show_description'];
1746
1747
            $entityManager = Database::getManager();
1748
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1749
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1750
                ExtraField::SESSION_FIELD_TYPE,
1751
                $session_id
1752
            );
1753
1754
            $session['extra_fields'] = [];
1755
            foreach ($extraFieldValues as $value) {
1756
                $session['extra_fields'][] = [
1757
                    'field' => [
1758
                        'variable' => $value->getField()->getVariable(),
1759
                        'display_text' => $value->getField()->getDisplayText(),
1760
                    ],
1761
                    'value' => $value->getValue(),
1762
                ];
1763
            }
1764
1765
            $output = $session;
1766
        }
1767
1768
        return $output;
1769
    }
1770
1771
    /**
1772
     * Return the five star HTML.
1773
     *
1774
     * @param string $id              of the rating ul element
1775
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1776
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1777
     * @param bool   $add_div_wrapper add a div wrapper
1778
     *
1779
     * @return string
1780
     */
1781
    public static function return_rating_system(
1782
        $id,
1783
        $url,
1784
        $point_info = [],
1785
        $add_div_wrapper = true
1786
    ) {
1787
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1788
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1789
1790
        if (!empty($percentage)) {
1791
            $percentage = $percentage * 125 / 100;
1792
        }
1793
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1794
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1795
1796
        $html = '<ul id="'.$id.'" class="star-rating">
1797
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1798
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1799
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1800
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1801
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1802
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1803
                </ul>';
1804
1805
        $labels = [];
1806
1807
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1808
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1809
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1810
1811
        if (!$add_div_wrapper && api_is_anonymous()) {
1812
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1813
        }
1814
1815
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1816
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1817
1818
        if ($add_div_wrapper) {
1819
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1820
        }
1821
1822
        return $html;
1823
    }
1824
1825
    /**
1826
     * @param string $title
1827
     * @param string $second_title
1828
     * @param string $size
1829
     * @param bool   $filter
1830
     *
1831
     * @return string
1832
     */
1833
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1834
    {
1835
        if ($filter) {
1836
            $title = Security::remove_XSS($title);
1837
        }
1838
1839
        if (!empty($second_title)) {
1840
            if ($filter) {
1841
                $second_title = Security::remove_XSS($second_title);
1842
            }
1843
            $title .= "<small> $second_title</small>";
1844
        }
1845
1846
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1847
    }
1848
1849
    public static function page_header_and_translate($title, $second_title = null)
1850
    {
1851
        $title = get_lang($title);
1852
1853
        return self::page_header($title, $second_title);
1854
    }
1855
1856
    public static function page_subheader_and_translate($title, $second_title = null)
1857
    {
1858
        $title = get_lang($title);
1859
1860
        return self::page_subheader($title, $second_title);
1861
    }
1862
1863
    public static function page_subheader($title, $second_title = null, $size = 'h3')
1864
    {
1865
        if (!empty($second_title)) {
1866
            $second_title = Security::remove_XSS($second_title);
1867
            $title .= "<small> $second_title<small>";
1868
        }
1869
1870
        return '<'.$size.'>'.Security::remove_XSS($title).'</'.$size.'>';
1871
    }
1872
1873
    public static function page_subheader2($title, $second_title = null)
1874
    {
1875
        return self::page_header($title, $second_title, 'h4');
1876
    }
1877
1878
    public static function page_subheader3($title, $second_title = null)
1879
    {
1880
        return self::page_header($title, $second_title, 'h5');
1881
    }
1882
1883
    /**
1884
     * @param array $list
1885
     *
1886
     * @return null|string
1887
     */
1888
    public static function description($list)
1889
    {
1890
        $html = null;
1891
        if (!empty($list)) {
1892
            $html = '<dl class="dl-horizontal">';
1893
            foreach ($list as $item) {
1894
                $html .= '<dt>'.$item['title'].'</dt>';
1895
                $html .= '<dd>'.$item['content'].'</dd>';
1896
            }
1897
            $html .= '</dl>';
1898
        }
1899
1900
        return $html;
1901
    }
1902
1903
    /**
1904
     * @param $percentage
1905
     * @param bool $show_percentage
1906
     * @param null $extra_info
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $extra_info is correct as it would always require null to be passed?
Loading history...
1907
     *
1908
     * @return string
1909
     */
1910
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = null)
1911
    {
1912
        $percentage = intval($percentage);
1913
        $div = '<div class="progress">
1914
                <div
1915
                    class="progress-bar progress-bar-striped"
1916
                    role="progressbar"
1917
                    aria-valuenow="'.$percentage.'"
1918
                    aria-valuemin="0"
1919
                    aria-valuemax="100"
1920
                    style="width: '.$percentage.'%;"
1921
                >';
1922
        if ($show_percentage) {
1923
            $div .= $percentage.'%';
1924
        } else {
1925
            if (!empty($extra_info)) {
1926
                $div .= $extra_info;
1927
            }
1928
        }
1929
        $div .= '</div>';
1930
1931
        return $div;
1932
    }
1933
1934
    /**
1935
     * @param string $count
1936
     * @param string $type
1937
     *
1938
     * @return null|string
1939
     */
1940
    public static function badge($count, $type = "warning")
1941
    {
1942
        $class = '';
1943
1944
        switch ($type) {
1945
            case 'success':
1946
                $class = 'badge-success';
1947
                break;
1948
            case 'warning':
1949
                $class = 'badge-warning';
1950
                break;
1951
            case 'important':
1952
                $class = 'badge-important';
1953
                break;
1954
            case 'info':
1955
                $class = 'badge-info';
1956
                break;
1957
            case 'inverse':
1958
                $class = 'badge-inverse';
1959
                break;
1960
        }
1961
1962
        if (!empty($count)) {
1963
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1964
        }
1965
1966
        return null;
1967
    }
1968
1969
    /**
1970
     * @param array $badge_list
1971
     *
1972
     * @return string
1973
     */
1974
    public static function badge_group($badge_list)
1975
    {
1976
        $html = '<div class="badge-group">';
1977
        foreach ($badge_list as $badge) {
1978
            $html .= $badge;
1979
        }
1980
        $html .= '</div>';
1981
1982
        return $html;
1983
    }
1984
1985
    /**
1986
     * @param string $content
1987
     * @param string $type
1988
     *
1989
     * @return string
1990
     */
1991
    public static function label($content, $type = 'default')
1992
    {
1993
        switch ($type) {
1994
            case 'success':
1995
                $class = 'label-success';
1996
                break;
1997
            case 'warning':
1998
                $class = 'label-warning';
1999
                break;
2000
            case 'important':
2001
            case 'danger':
2002
                $class = 'label-danger';
2003
                break;
2004
            case 'info':
2005
                $class = 'label-info';
2006
                break;
2007
            case 'primary':
2008
                $class = 'label-primary';
2009
                break;
2010
            default:
2011
                $class = 'label-default';
2012
                break;
2013
        }
2014
2015
        $html = '';
2016
        if (!empty($content)) {
2017
            $html = '<span class="label '.$class.'">';
2018
            $html .= $content;
2019
            $html .= '</span>';
2020
        }
2021
2022
        return $html;
2023
    }
2024
2025
    /**
2026
     * @param array  $items
2027
     * @param string $class
2028
     *
2029
     * @return null|string
2030
     */
2031
    public static function actions($items, $class = 'new_actions')
2032
    {
2033
        $html = null;
2034
        if (!empty($items)) {
2035
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2036
            foreach ($items as $value) {
2037
                $class = null;
2038
                if (isset($value['active']) && $value['active']) {
2039
                    $class = 'class ="active"';
2040
                }
2041
2042
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2043
                    $class = 'class ="active"';
2044
                }
2045
                $html .= "<li $class >";
2046
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2047
                $html .= self::url($value['content'], $value['url'], $attributes);
2048
                $html .= '</li>';
2049
            }
2050
            $html .= '</ul></div>';
2051
            $html .= '<br />';
2052
        }
2053
2054
        return $html;
2055
    }
2056
2057
    /**
2058
     * Prints a tooltip.
2059
     *
2060
     * @param string $text
2061
     * @param string $tip
2062
     *
2063
     * @return string
2064
     */
2065
    public static function tip($text, $tip)
2066
    {
2067
        if (empty($tip)) {
2068
            return $text;
2069
        }
2070
2071
        return self::span(
2072
            $text,
2073
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2074
        );
2075
    }
2076
2077
    /**
2078
     * @param array  $items
2079
     * @param string $type
2080
     * @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...
2081
     *
2082
     * @return null|string
2083
     */
2084
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2085
    {
2086
        $html = null;
2087
        if (!empty($items)) {
2088
            if (empty($id)) {
2089
                $id = api_get_unique_id();
2090
            }
2091
            if ($type == 'jquery') {
2092
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2093
            } else {
2094
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2095
            }
2096
2097
            $count = 1;
2098
            foreach ($items as $item) {
2099
                $html .= '<div class="accordion-my-group">';
2100
                $html .= '<div class="accordion-heading">
2101
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2102
                            '.$item['title'].'
2103
                            </a>
2104
                          </div>';
2105
2106
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2107
                $html .= '<div class="accordion-my-inner">
2108
                            '.$item['content'].'
2109
                            </div>
2110
                          </div>';
2111
            }
2112
            $html .= '</div>';
2113
        }
2114
2115
        return $html;
2116
    }
2117
2118
    /**
2119
     * @param array $buttons
2120
     *
2121
     * @return string
2122
     */
2123
    public static function groupButton($buttons)
2124
    {
2125
        $html = '<div class="btn-group" role="group">';
2126
        foreach ($buttons as $button) {
2127
            $html .= $button;
2128
        }
2129
        $html .= '</div>';
2130
2131
        return $html;
2132
    }
2133
2134
    /**
2135
     * @todo use twig
2136
     *
2137
     * @param string $title
2138
     * @param array  $elements
2139
     * @param bool   $alignToRight
2140
     *
2141
     * @return string
2142
     */
2143
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2144
    {
2145
        $html = '<div class="btn-group">
2146
                <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
2147
                '.$title.'
2148
                <span class="caret"></span></button>
2149
                <ul class="dropdown-menu '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2150
        foreach ($elements as $item) {
2151
            $html .= self::tag('li', self::url($item['title'], $item['href']));
2152
        }
2153
        $html .= '</ul>
2154
            </div>';
2155
2156
        return $html;
2157
    }
2158
2159
    /**
2160
     * @param string $file
2161
     * @param array  $params
2162
     *
2163
     * @return null|string
2164
     */
2165
    public static function getMediaPlayer($file, $params = [])
2166
    {
2167
        $fileInfo = pathinfo($file);
2168
2169
        switch ($fileInfo['extension']) {
2170
            case 'mp3':
2171
            case 'webm':
2172
                $autoplay = null;
2173
                if (isset($params['autoplay']) && $params['autoplay'] == 'true') {
2174
                    $autoplay = 'autoplay';
2175
                }
2176
                $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2177
                $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2178
                $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2179
2180
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2181
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2182
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2183
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2184
                          </object>';
2185
                $html .= '</audio>';
2186
2187
                return $html;
2188
                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...
2189
            case 'wav':
2190
            case 'ogg':
2191
                $html = '<audio width="300px" controls src="'.$params['url'].'" >';
2192
2193
                return $html;
2194
                break;
2195
        }
2196
2197
        return null;
2198
    }
2199
2200
    /**
2201
     * @param int    $nextValue
2202
     * @param array  $list
2203
     * @param int    $current
2204
     * @param int    $fixedValue
2205
     * @param array  $conditions
2206
     * @param string $link
2207
     * @param bool   $isMedia
2208
     * @param bool   $addHeaders
2209
     * @param array  $linkAttributes
2210
     *
2211
     * @return string
2212
     */
2213
    public static function progressPaginationBar(
2214
        $nextValue,
2215
        $list,
2216
        $current,
2217
        $fixedValue = null,
2218
        $conditions = [],
2219
        $link = null,
2220
        $isMedia = false,
2221
        $addHeaders = true,
2222
        $linkAttributes = []
2223
    ) {
2224
        if ($addHeaders) {
2225
            $pagination_size = 'pagination-mini';
2226
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2227
        } else {
2228
            $html = null;
2229
        }
2230
        $affectAllItems = false;
2231
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2232
            $affectAllItems = true;
2233
        }
2234
        $localCounter = 0;
2235
        foreach ($list as $itemId) {
2236
            $isCurrent = false;
2237
            if ($affectAllItems) {
2238
                $isCurrent = true;
2239
            } else {
2240
                if (!$isMedia) {
2241
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2242
                }
2243
            }
2244
            $html .= self::parsePaginationItem(
2245
                $itemId,
2246
                $isCurrent,
2247
                $conditions,
2248
                $link,
2249
                $nextValue,
2250
                $isMedia,
2251
                $localCounter,
2252
                $fixedValue,
2253
                $linkAttributes
2254
            );
2255
            $localCounter++;
2256
        }
2257
        if ($addHeaders) {
2258
            $html .= '</ul></div>';
2259
        }
2260
2261
        return $html;
2262
    }
2263
2264
    /**
2265
     * @param int    $itemId
2266
     * @param bool   $isCurrent
2267
     * @param array  $conditions
2268
     * @param string $link
2269
     * @param int    $nextValue
2270
     * @param bool   $isMedia
2271
     * @param int    $localCounter
2272
     * @param int    $fixedValue
2273
     * @param array  $linkAttributes
2274
     *
2275
     * @return string
2276
     */
2277
    public static function parsePaginationItem(
2278
        $itemId,
2279
        $isCurrent,
2280
        $conditions,
2281
        $link,
2282
        $nextValue = 0,
2283
        $isMedia = false,
2284
        $localCounter = null,
2285
        $fixedValue = null,
2286
        $linkAttributes = []
2287
    ) {
2288
        $defaultClass = 'before';
2289
        $class = $defaultClass;
2290
        foreach ($conditions as $condition) {
2291
            $array = isset($condition['items']) ? $condition['items'] : [];
2292
            $class_to_applied = $condition['class'];
2293
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2294
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2295
            switch ($type) {
2296
                case 'positive':
2297
                    if (in_array($itemId, $array)) {
2298
                        if ($mode == 'overwrite') {
2299
                            $class = " $defaultClass $class_to_applied";
2300
                        } else {
2301
                            $class .= " $class_to_applied";
2302
                        }
2303
                    }
2304
                    break;
2305
                case 'negative':
2306
                    if (!in_array($itemId, $array)) {
2307
                        if ($mode == 'overwrite') {
2308
                            $class = " $defaultClass $class_to_applied";
2309
                        } else {
2310
                            $class .= " $class_to_applied";
2311
                        }
2312
                    }
2313
                    break;
2314
            }
2315
        }
2316
        if ($isCurrent) {
2317
            $class = 'before current';
2318
        }
2319
        if ($isMedia && $isCurrent) {
2320
            $class = 'before current';
2321
        }
2322
        if (empty($link)) {
2323
            $link_to_show = '#';
2324
        } else {
2325
            $link_to_show = $link.($nextValue + $localCounter);
2326
        }
2327
        $label = $nextValue + $localCounter + 1;
2328
        if ($isMedia) {
2329
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2330
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2331
        }
2332
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2333
2334
        return  '<li class = "'.$class.'">'.$link.'</li>';
2335
    }
2336
2337
    /**
2338
     * @param int $current
2339
     * @param int $total
2340
     *
2341
     * @return string
2342
     */
2343
    public static function paginationIndicator($current, $total)
2344
    {
2345
        $html = null;
2346
        if (!empty($current) && !empty($total)) {
2347
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2348
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2349
        }
2350
2351
        return $html;
2352
    }
2353
2354
    /**
2355
     * Adds a message in the queue.
2356
     *
2357
     * @param string $message
2358
     */
2359
    public static function addFlash($message)
2360
    {
2361
        $messages = Session::read('flash_messages');
2362
        if (empty($messages)) {
2363
            $messages[] = $message;
2364
        } else {
2365
            array_push($messages, $message);
2366
        }
2367
        Session::write('flash_messages', $messages);
2368
    }
2369
2370
    /**
2371
     * @return string
2372
     */
2373
    public static function getFlashToString()
2374
    {
2375
        $messages = Session::read('flash_messages');
2376
        $messageToString = '';
2377
        if (!empty($messages)) {
2378
            foreach ($messages as $message) {
2379
                $messageToString .= $message;
2380
            }
2381
        }
2382
2383
        return $messageToString;
2384
    }
2385
2386
    /**
2387
     * Shows the message from the session.
2388
     */
2389
    public static function showFlash()
2390
    {
2391
        echo self::getFlashToString();
2392
    }
2393
2394
    /**
2395
     * Destroys the message session.
2396
     */
2397
    public static function cleanFlashMessages()
2398
    {
2399
        Session::erase('flash_messages');
2400
    }
2401
2402
    /**
2403
     * Get the profile edition link for a user.
2404
     *
2405
     * @param int  $userId  The user id
2406
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2407
     *
2408
     * @return string The link
2409
     */
2410
    public static function getProfileEditionLink($userId, $asAdmin = false)
2411
    {
2412
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2413
        if ($asAdmin) {
2414
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2415
        }
2416
2417
        if (api_get_setting('sso_authentication') === 'true') {
2418
            $subSSOClass = api_get_setting('sso_authentication_subclass');
2419
            $objSSO = null;
2420
2421
            if (!empty($subSSOClass)) {
2422
                $file = api_get_path(SYS_CODE_PATH)."auth/sso/sso.$subSSOClass.class.php";
2423
                if (file_exists($file)) {
2424
                    require_once $file;
2425
                    $subSSOClass = 'sso'.$subSSOClass;
2426
                    $objSSO = new $subSSOClass();
2427
                } else {
2428
                    throw new Exception("$subSSOClass file not set");
2429
                }
2430
            } else {
2431
                $objSSO = new sso();
2432
            }
2433
2434
            $editProfileUrl = $objSSO->generateProfileEditingURL(
2435
                $userId,
2436
                $asAdmin
2437
            );
2438
        }
2439
2440
        return $editProfileUrl;
2441
    }
2442
2443
    /**
2444
     * Get the vCard for a user.
2445
     *
2446
     * @param int $userId The user id
2447
     *
2448
     * @return string *.*vcf file
2449
     */
2450
    public static function getVCardUserLink($userId)
2451
    {
2452
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2453
2454
        return $vCardUrl;
2455
    }
2456
2457
    /**
2458
     * @param string $content
2459
     * @param string $title
2460
     * @param string $footer
2461
     * @param string $type        primary|success|info|warning|danger
2462
     * @param string $extra
2463
     * @param string $id
2464
     * @param string $customColor
2465
     *
2466
     * @return string
2467
     */
2468
    public static function panel(
2469
        $content,
2470
        $title = '',
2471
        $footer = '',
2472
        $type = 'default',
2473
        $extra = '',
2474
        $id = '',
2475
        $customColor = ''
2476
    ) {
2477
        $headerStyle = '';
2478
        if (!empty($customColor)) {
2479
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2480
        }
2481
2482
        $title = !empty($title) ? '<div class="panel-heading" '.$headerStyle.' ><h3 class="panel-title">'.$title.'</h3>'.$extra.'</div>' : '';
2483
        $footer = !empty($footer) ? '<div class="panel-footer">'.$footer.'</div>' : '';
2484
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2485
        $style = !in_array($type, $typeList) ? 'default' : $type;
2486
2487
        if (!empty($id)) {
2488
            $id = " id='$id'";
2489
        }
2490
2491
        return '
2492
            <div '.$id.' class="panel panel-'.$style.'">
2493
                '.$title.'
2494
                '.self::contentPanel($content).'
2495
                '.$footer.'
2496
            </div>'
2497
        ;
2498
    }
2499
2500
    /**
2501
     * @param string $content
2502
     *
2503
     * @return string
2504
     */
2505
    public static function contentPanel($content)
2506
    {
2507
        if (empty($content)) {
2508
            return '';
2509
        }
2510
2511
        return '<div class="panel-body">'.$content.'</div>';
2512
    }
2513
2514
    /**
2515
     * Get the button HTML with an Awesome Font icon.
2516
     *
2517
     * @param string $text        The button content
2518
     * @param string $url         The url to button
2519
     * @param string $icon        The Awesome Font class for icon
2520
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2521
     * @param array  $attributes  The additional attributes
2522
     * @param bool   $includeText
2523
     *
2524
     * @return string The button HTML
2525
     */
2526
    public static function toolbarButton(
2527
        $text,
2528
        $url,
2529
        $icon = 'check',
2530
        $type = 'default',
2531
        array $attributes = [],
2532
        $includeText = true
2533
    ) {
2534
        $buttonClass = "btn btn-$type";
2535
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2536
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2537
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2538
2539
        if (!$includeText) {
2540
            $text = '<span class="sr-only">'.$text.'</span>';
2541
        }
2542
2543
        return self::url("$icon $text", $url, $attributes);
2544
    }
2545
2546
    /**
2547
     * @param string $id
2548
     * @param array  $content
2549
     * @param array  $colsWidth Optional. Columns width
2550
     *
2551
     * @return string
2552
     */
2553
    public static function toolbarAction($id, $content, $colsWidth = [])
2554
    {
2555
        $col = count($content);
2556
2557
        if (!$colsWidth) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $colsWidth of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2558
            $width = 12 / $col;
2559
            array_walk($content, function () use ($width, &$colsWidth) {
2560
                $colsWidth[] = $width;
2561
            });
2562
        }
2563
2564
        $html = '<div id="'.$id.'" class="actions">';
2565
        $html .= '<div class="row">';
2566
2567
        for ($i = 0; $i < $col; $i++) {
2568
            $class = 'col-sm-'.$colsWidth[$i];
2569
2570
            if ($col > 1) {
2571
                if ($i > 0 && $i < count($content) - 1) {
2572
                    $class .= ' text-center';
2573
                } elseif ($i === count($content) - 1) {
2574
                    $class .= ' text-right';
2575
                }
2576
            }
2577
2578
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2579
        }
2580
2581
        $html .= '</div>';
2582
        $html .= '</div>';
2583
2584
        return $html;
2585
    }
2586
2587
    /**
2588
     * Get a HTML code for a icon by Font Awesome.
2589
     *
2590
     * @param string     $name            The icon name
2591
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2592
     * @param bool       $fixWidth        Optional. Whether add the fw class
2593
     * @param string     $additionalClass Optional. Additional class
2594
     *
2595
     * @return string
2596
     */
2597
    public static function returnFontAwesomeIcon(
2598
        $name,
2599
        $size = '',
2600
        $fixWidth = false,
2601
        $additionalClass = ''
2602
    ) {
2603
        $className = "fa fa-$name";
2604
2605
        if ($fixWidth) {
2606
            $className .= ' fa-fw';
2607
        }
2608
2609
        switch ($size) {
2610
            case 'lg':
2611
                $className .= ' fa-lg';
2612
                break;
2613
            case 2:
2614
            case 3:
2615
            case 4:
2616
            case 5:
2617
                $className .= " fa-{$size}x";
2618
                break;
2619
        }
2620
2621
        if (!empty($additionalClass)) {
2622
            $className .= " $additionalClass";
2623
        }
2624
2625
        $icon = self::tag('em', null, ['class' => $className]);
2626
2627
        return "$icon ";
2628
    }
2629
2630
    /**
2631
     * @param string     $title
2632
     * @param string     $content
2633
     * @param null       $id
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...
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...
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...
2634
     * @param array      $params
2635
     * @param null       $idAccordion
2636
     * @param null       $idCollapse
2637
     * @param bool|true  $open
2638
     * @param bool|false $fullClickable
2639
     *
2640
     * @return null|string
2641
     *
2642
     * @todo rework function to easy use
2643
     */
2644
    public static function panelCollapse(
2645
        $title,
2646
        $content,
2647
        $id = null,
2648
        $params = [],
2649
        $idAccordion = null,
2650
        $idCollapse = null,
2651
        $open = true,
2652
        $fullClickable = false
2653
    ) {
2654
        if (!empty($idAccordion)) {
2655
            $headerClass = '';
2656
            $headerClass .= $fullClickable ? 'center-block ' : '';
2657
            $headerClass .= $open ? '' : 'collapsed';
2658
            $contentClass = 'panel-collapse collapse ';
2659
            $contentClass .= $open ? 'in' : '';
2660
            $ariaExpanded = $open ? 'true' : 'false';
2661
2662
            $html = <<<HTML
2663
                <div class="panel-group" id="$idAccordion" role="tablist" aria-multiselectable="true">
2664
                    <div class="panel panel-default" id="$id">
2665
                        <div class="panel-heading" role="tab">
2666
                            <h4 class="panel-title">
2667
                                <a class="$headerClass" role="button" data-toggle="collapse" data-parent="#$idAccordion" href="#$idCollapse" aria-expanded="$ariaExpanded" aria-controls="$idCollapse">$title</a>
2668
                            </h4>
2669
                        </div>
2670
                        <div id="$idCollapse" class="$contentClass" role="tabpanel">
2671
                            <div class="panel-body">$content</div>
2672
                        </div>
2673
                    </div>
2674
                </div>
2675
HTML;
2676
        } else {
2677
            if (!empty($id)) {
2678
                $params['id'] = $id;
2679
            }
2680
            $params['class'] = 'panel panel-default';
2681
            $html = null;
2682
            if (!empty($title)) {
2683
                $html .= '<div class="panel-heading">'.$title.'</div>'.PHP_EOL;
2684
            }
2685
            $html .= '<div class="panel-body">'.$content.'</div>'.PHP_EOL;
2686
            $html = self::div($html, $params);
2687
        }
2688
2689
        return $html;
2690
    }
2691
2692
    /**
2693
     * Returns the string "1 day ago" with a link showing the exact date time.
2694
     *
2695
     * @param string $dateTime in UTC or a DateTime in UTC
2696
     *
2697
     * @return string
2698
     */
2699
    public static function dateToStringAgoAndLongDate($dateTime)
2700
    {
2701
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2702
            return '';
2703
        }
2704
2705
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2706
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2707
        }
2708
2709
        return self::tip(
2710
            date_to_str_ago($dateTime),
2711
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2712
            //api_get_local_time($dateTime)
2713
        );
2714
    }
2715
2716
    /**
2717
     * @param array  $userInfo
2718
     * @param string $status
2719
     * @param string $toolbar
2720
     *
2721
     * @return string
2722
     */
2723
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2724
    {
2725
        if (empty($userInfo)) {
2726
            return '';
2727
        }
2728
2729
        if (!empty($status)) {
2730
            $status = '<div class="items-user-status">'.$status.'</div>';
2731
        }
2732
2733
        if (!empty($toolbar)) {
2734
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2735
        }
2736
2737
        return '<div id="user_card_'.$userInfo['id'].'" class="col-md-12">                    
2738
                    <div class="row">
2739
                        <div class="col-md-2">                            
2740
                            <img src="'.$userInfo['avatar'].'" class="img-responsive img-circle">
2741
                        </div>
2742
                        <div class="col-md-10">
2743
                           <p>'.$userInfo['complete_name'].'</p>
2744
                           <div class="row">
2745
                           <div class="col-md-2">
2746
                           '.$status.'
2747
                           </div>
2748
                           <div class="col-md-10">                           
2749
                           '.$toolbar.'
2750
                           </div>
2751
                           </div>
2752
                        </div>
2753
                    </div>
2754
                    <hr />
2755
              </div>';
2756
    }
2757
}
2758