Completed
Push — master ( 33dc2b...283fc9 )
by Julito
24:27 queued 11:46
created

Display::toolList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return false;
}

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

Loading history...
72
        $showHeader = true;
73
        if (isset($origin) && $origin == 'learnpath') {
74
            $showHeader = false;
75
        }
76
77
        self::$global_template = new Template($tool_name, $showHeader, $showHeader);
78
79
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
80
        if (empty($help)) {
81
            $currentURL = api_get_self();
82
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
83
            $toolList = self::toolList();
84
            if (!empty($matches)) {
85
                foreach ($matches as $match) {
86
                    if (in_array($match, $toolList)) {
87
                        $help = explode('_', $match);
88
                        $help = array_map('ucfirst', $help);
89
                        $help = implode('', $help);
90
                        break;
91
                    }
92
                }
93
            }
94
        }
95
96
        self::$global_template->setHelp($help);
97
98
        if (!empty(self::$preview_style)) {
99
            self::$global_template->preview_theme = self::$preview_style;
100
            self::$global_template->set_system_parameters();
101
            self::$global_template->setCssFiles();
102
            self::$global_template->set_js_files();
103
            self::$global_template->setCssCustomFiles();
104
        }
105
106
        if (!empty($page_header)) {
107
            self::$global_template->assign('header', $page_header);
108
        }
109
110
        echo self::$global_template->show_header_template();
111
    }
112
113
    /**
114
     * Displays the reduced page header (without banner).
115
     */
116
    public static function display_reduced_header()
117
    {
118
        global $show_learnpath, $tool_name;
119
        self::$global_template = new Template(
120
            $tool_name,
121
            false,
122
            false,
123
            $show_learnpath
124
        );
125
        echo self::$global_template->show_header_template();
126
    }
127
128
    /**
129
     * Display no header.
130
     */
131
    public static function display_no_header()
132
    {
133
        global $tool_name, $show_learnpath;
134
        $disable_js_and_css_files = true;
135
        self::$global_template = new Template(
136
            $tool_name,
137
            false,
138
            false,
139
            $show_learnpath
140
        );
141
    }
142
143
    /**
144
     * Displays the reduced page header (without banner).
145
     */
146
    private static function set_header()
147
    {
148
        global $show_learnpath, $tool_name;
149
        self::$global_template = new Template(
150
            $tool_name,
151
            false,
152
            false,
153
            $show_learnpath
154
        );
155
    }
156
157
    /**
158
     * Display the page footer.
159
     */
160
    public static function display_footer()
161
    {
162
        $contents = ob_get_contents();
163
        ob_end_clean();
164
        $tpl = '@ChamiloTheme/Layout/layout_one_col.html.twig';
165
        $response = new Response();
166
        $params['content'] = $contents;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
167
        global $interbreadcrumb;
168
        $params['legacy_breadcrumb'] = $interbreadcrumb;
169
        $content = Container::getTemplating()->render($tpl, $params);
170
        $response->setContent($content);
171
        $response->send();
172
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

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

381
        /** @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...
382
        $content,
383
        $paging_options = [],
384
        $query_vars = null,
385
        $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

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

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

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

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

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