Passed
Push — master ( b35e01...d5b91e )
by Julito
12:07 queued 03:32
created

Display::set_header()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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

62
        /** @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...
63
        $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

63
        /** @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...
64
        $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

64
        /** @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...
65
    ) {
66
        ob_start();
67
68
        return true;
69
70
        $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...
71
        $showHeader = true;
72
        if (isset($origin) && $origin == 'learnpath') {
73
            $showHeader = false;
74
        }
75
76
        self::$global_template = new Template($tool_name, $showHeader, $showHeader);
77
78
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
79
        if (empty($help)) {
80
            $currentURL = api_get_self();
81
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
82
            $toolList = self::toolList();
83
            if (!empty($matches)) {
84
                foreach ($matches as $match) {
85
                    if (in_array($match, $toolList)) {
86
                        $help = explode('_', $match);
87
                        $help = array_map('ucfirst', $help);
88
                        $help = implode('', $help);
89
                        break;
90
                    }
91
                }
92
            }
93
        }
94
95
        self::$global_template->setHelp($help);
96
97
        if (!empty(self::$preview_style)) {
98
            self::$global_template->preview_theme = self::$preview_style;
99
            self::$global_template->set_system_parameters();
100
            self::$global_template->setCssFiles();
101
            self::$global_template->set_js_files();
102
            self::$global_template->setCssCustomFiles();
103
        }
104
105
        if (!empty($page_header)) {
106
            self::$global_template->assign('header', $page_header);
107
        }
108
109
        echo self::$global_template->show_header_template();
110
    }
111
112
    /**
113
     * Displays the reduced page header (without banner).
114
     */
115
    public static function display_reduced_header()
116
    {
117
        global $show_learnpath, $tool_name;
118
        self::$global_template = new Template(
119
            $tool_name,
120
            false,
121
            false,
122
            $show_learnpath
123
        );
124
        echo self::$global_template->show_header_template();
0 ignored issues
show
Bug introduced by
The method show_header_template() does not exist on Template. ( Ignorable by Annotation )

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

124
        echo self::$global_template->/** @scrutinizer ignore-call */ show_header_template();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

374
        /** @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...
375
        $content,
376
        $paging_options = [],
377
        $query_vars = null,
378
        $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

378
        /** @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...
379
        $visibility_options = true,
380
        $sort_data = true,
381
        $grid_class = [],
382
        $elementCount = 0
383
    ) {
384
        $column = 0;
385
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
386
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
387
        $table->total_number_of_items = intval($elementCount);
388
        if (is_array($query_vars)) {
389
            $table->set_additional_parameters($query_vars);
390
        }
391
392
        return $table->display_simple_grid(
393
            $visibility_options,
394
            $paging_options['hide_navigation'],
395
            $default_items_per_page,
396
            $sort_data,
397
            $grid_class
398
        );
399
    }
400
401
    /**
402
     * Displays a table with a special configuration.
403
     *
404
     * @param array $header          Titles for the table header
405
     *                               each item in this array can contain 3 values
406
     *                               - 1st element: the column title
407
     *                               - 2nd element: true or false (column sortable?)
408
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
409
     *                               - 4the element: additional attributes for the td-tags
410
     * @param array $content         2D-array with the tables content
411
     * @param array $sorting_options Keys are:
412
     *                               'column' = The column to use as sort-key
413
     *                               'direction' = SORT_ASC or SORT_DESC
414
     * @param array $paging_options  Keys are:
415
     *                               'per_page_default' = items per page when switching from full list to per-page-view
416
     *                               'per_page' = number of items to show per page
417
     *                               'page_nr' = The page to display
418
     * @param array $query_vars      Additional variables to add in the query-string
419
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
420
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
421
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the
422
     *                               4th column
423
     * @param array $form_actions    Set optional forms actions
424
     *
425
     * @author Julio Montoya
426
     */
427
    public static function display_sortable_config_table(
428
        $table_name,
429
        $header,
430
        $content,
431
        $sorting_options = [],
432
        $paging_options = [],
433
        $query_vars = null,
434
        $column_show = [],
435
        $column_order = [],
436
        $form_actions = []
437
    ) {
438
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
439
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
440
441
        $table = new SortableTableFromArrayConfig(
442
            $content,
443
            $column,
444
            $default_items_per_page,
445
            $table_name,
446
            $column_show,
447
            $column_order
448
        );
449
450
        if (is_array($query_vars)) {
451
            $table->set_additional_parameters($query_vars);
452
        }
453
        // Show or hide the columns header
454
        if (is_array($column_show)) {
455
            for ($i = 0; $i < count($column_show); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

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

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

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
456
                if (!empty($column_show[$i])) {
457
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
458
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
459
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
460
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
461
                    $table->set_header($i, $val0, $val1, $val2, $val3);
462
                }
463
            }
464
        }
465
        $table->set_form_actions($form_actions);
466
        $table->display();
467
    }
468
469
    /**
470
     * Displays a normal message. It is recommended to use this public function
471
     * to display any normal information messages.
472
     *
473
     * @param string $message
474
     * @param bool   $filter      (true) or not (false)
475
     * @param bool   $returnValue
476
     *
477
     * @deprecated Use <code>Display::addFlash(Display::return_message($message, 'normal'));</code>
478
     *  Or <code>echo Display::return_message($message, 'normal')</code>
479
     */
480
    public static function display_normal_message(
481
        $message,
482
        $filter = true,
483
        $returnValue = false
484
    ) {
485
        $message = self::return_message($message, 'normal', $filter);
486
        if ($returnValue) {
487
            return $message;
488
        } else {
489
            echo $message;
490
        }
491
    }
492
493
    /**
494
     * Displays an warning message. Use this if you want to draw attention to something
495
     * This can also be used for instance with the hint in the exercises.
496
     *
497
     * @deprecated use Display::addFlash(Display::return_message($message, 'warning'));
498
     */
499
    public static function display_warning_message(
500
        $message,
501
        $filter = true,
502
        $returnValue = false
503
    ) {
504
        $message = self::return_message($message, 'warning', $filter);
505
        if ($returnValue) {
506
            return $message;
507
        } else {
508
            echo $message;
509
        }
510
    }
511
512
    /**
513
     * Displays an confirmation message. Use this if something has been done successfully.
514
     *
515
     * @param bool    Filter (true) or not (false)
516
     *
517
     * @deprecated use Display::addFlash(Display::return_message($message, 'confirm'));
518
     */
519
    public static function display_confirmation_message(
520
        $message,
521
        $filter = true,
522
        $returnValue = false
523
    ) {
524
        $message = self::return_message($message, 'confirm', $filter);
525
        if ($returnValue) {
526
            return $message;
527
        } else {
528
            echo $message;
529
        }
530
    }
531
532
    /**
533
     * Displays an error message. It is recommended to use this public function if an error occurs.
534
     *
535
     * @param string $message - include any additional html
536
     *                        tags if you need them
537
     * @param bool    Filter (true) or not (false)
538
     *
539
     * @deprecated use Display::addFlash(Display::return_message($message, 'error'));
540
     */
541
    public static function display_error_message(
542
        $message,
543
        $filter = true,
544
        $returnValue = false
545
    ) {
546
        $message = self::return_message($message, 'error', $filter);
547
        if ($returnValue) {
548
            return $message;
549
        } else {
550
            echo $message;
551
        }
552
    }
553
554
    /**
555
     * @param string $message
556
     * @param string $type
557
     * @param bool   $filter
558
     */
559
    public static function return_message_and_translate(
560
        $message,
561
        $type = 'normal',
562
        $filter = true
563
    ) {
564
        $message = get_lang($message);
565
        echo self::return_message($message, $type, $filter);
566
    }
567
568
    /**
569
     * Returns a div html string with.
570
     *
571
     * @param string $message
572
     * @param string $type    Example: confirm, normal, warning, error
573
     * @param bool   $filter  Whether to XSS-filter or not
574
     *
575
     * @return string Message wrapped into an HTML div
576
     */
577
    public static function return_message(
578
        $message,
579
        $type = 'normal',
580
        $filter = true
581
    ) {
582
        if (empty($message)) {
583
            return '';
584
        }
585
586
        if ($filter) {
587
            $message = api_htmlentities(
588
                $message,
589
                ENT_QUOTES,
590
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
591
            );
592
        }
593
594
        $class = '';
595
        switch ($type) {
596
            case 'warning':
597
                $class .= 'alert alert-warning';
598
                break;
599
            case 'error':
600
                $class .= 'alert alert-danger';
601
                break;
602
            case 'confirmation':
603
            case 'confirm':
604
            case 'success':
605
                $class .= 'alert alert-success';
606
                break;
607
            case 'normal':
608
            default:
609
                $class .= 'alert alert-info';
610
        }
611
612
        return self::div($message, ['class' => $class]);
613
    }
614
615
    /**
616
     * Returns an encrypted mailto hyperlink.
617
     *
618
     * @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...
619
     * @param string  clickable text
620
     * @param string  optional, class from stylesheet
621
     *
622
     * @return string encrypted mailto hyperlink
623
     */
624
    public static function encrypted_mailto_link(
625
        $email,
626
        $clickable_text = null,
627
        $style_class = '',
628
        $cut = false
629
    ) {
630
        if (is_null($clickable_text)) {
631
            $clickable_text = $email;
632
        }
633
        // "mailto:" already present?
634
        if (substr($email, 0, 7) != 'mailto:') {
635
            $email = 'mailto:'.$email;
636
        }
637
        // Class (stylesheet) defined?
638
        if ($style_class != '') {
639
            $style_class = ' class="'.$style_class.'"';
640
        }
641
        // Encrypt email
642
        $hmail = '';
643
        for ($i = 0; $i < strlen($email); $i++) {
644
            $hmail .= '&#'.ord($email[
645
            $i]).';';
646
        }
647
        $hclickable_text = null;
648
        // Encrypt clickable text if @ is present
649
        if (strpos($clickable_text, '@')) {
650
            for ($i = 0; $i < strlen($clickable_text); $i++) {
651
                $hclickable_text .= '&#'.ord($clickable_text[
652
                $i]).';';
653
            }
654
        } else {
655
            $hclickable_text = @htmlspecialchars(
656
                $clickable_text,
657
                ENT_QUOTES,
658
                api_get_system_encoding()
659
            );
660
        }
661
        // Return encrypted mailto hyperlink
662
        $classCut = '';
663
        if ($cut) {
664
            $classCut = 'cut-email';
665
        }
666
667
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link '.$classCut.'">'.$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
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1085
        foreach ($extra_attributes as $key => $parameter) {
1086
            if ($key == 'id') {
1087
                $default_id = '';
1088
            }
1089
            $extra .= $key.'="'.$parameter.'" ';
1090
        }
1091
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1092
1093
        if ($show_blank_item) {
1094
            if (empty($blank_item_text)) {
1095
                $blank_item_text = get_lang('Select');
1096
            } else {
1097
                $blank_item_text = Security::remove_XSS($blank_item_text);
1098
            }
1099
            $html .= self::tag(
1100
                'option',
1101
                '-- '.$blank_item_text.' --',
1102
                ['value' => '-1']
1103
            );
1104
        }
1105
        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...
1106
            foreach ($values as $key => $value) {
1107
                if (is_array($value) && isset($value['name'])) {
1108
                    $value = $value['name'];
1109
                }
1110
                $html .= '<option value="'.$key.'"';
1111
1112
                if (is_array($default)) {
1113
                    foreach ($default as $item) {
1114
                        if ($item == $key) {
1115
                            $html .= ' selected="selected"';
1116
                            break;
1117
                        }
1118
                    }
1119
                } else {
1120
                    if ($default == $key) {
1121
                        $html .= ' selected="selected"';
1122
                    }
1123
                }
1124
1125
                $html .= '>'.$value.'</option>';
1126
            }
1127
        }
1128
        $html .= '</select>';
1129
1130
        return $html;
1131
    }
1132
1133
    /**
1134
     * Creates a tab menu
1135
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1136
     * in the $htmlHeadXtra variable before the display_header
1137
     * Add this script.
1138
     *
1139
     * @example
1140
     * <script>
1141
                </script>
1142
     * @param array  $headers       list of the tab titles
1143
     * @param array  $items
1144
     * @param string $id            id of the container of the tab in the example "tabs"
1145
     * @param array  $attributes    for the ul
1146
     * @param array  $ul_attributes
1147
     *
1148
     * @return string
1149
     */
1150
    public static function tabs(
1151
        $headers,
1152
        $items,
1153
        $id = 'tabs',
1154
        $attributes = [],
1155
        $ul_attributes = []
0 ignored issues
show
Unused Code introduced by
The parameter $ul_attributes is not used and could be removed. ( Ignorable by Annotation )

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

1155
        /** @scrutinizer ignore-unused */ $ul_attributes = []

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

Loading history...
1156
    ) {
1157
        if (empty($headers) || count($headers) == 0) {
1158
            return '';
1159
        }
1160
1161
        $lis = '';
1162
        $i = 1;
1163
        foreach ($headers as $item) {
1164
            $active = '';
1165
            $selected = 'false';
1166
            if ($i == 1) {
1167
                $active = ' active';
1168
                $selected = 'true';
1169
            }
1170
1171
            $item = self::tag(
1172
                'a',
1173
                $item,
1174
                [
1175
                    'href' => '#'.$id.'-'.$i,
1176
                    'class' => 'nav-item nav-link '.$active,
1177
                    'id' => $id.$i.'-tab',
1178
                    'data-toggle' => 'tab',
1179
                    'role' => 'tab',
1180
                    'aria-controls' => $id.'-'.$i,
1181
                    'aria-selected' => $selected,
1182
                ]
1183
            );
1184
            $lis .= $item;
1185
            $i++;
1186
        }
1187
1188
        $ul = self::tag(
1189
            'nav',
1190
            $lis,
1191
            [
1192
                'id' => 'ul_'.$id,
1193
                'class' => 'nav nav-tabs',
1194
                'role' => 'tablist',
1195
            ]
1196
        );
1197
1198
        $i = 1;
1199
        $divs = '';
1200
        foreach ($items as $content) {
1201
            $active = '';
1202
            if ($i == 1) {
1203
                $active = ' show active';
1204
            }
1205
            $divs .= self::tag(
1206
                'div',
1207
                $content,
1208
                [
1209
                    'id' => $id.'-'.$i,
1210
                    'class' => 'tab-pane fade '.$active,
1211
                    'role' => 'tabpanel',
1212
                    'aria-labelledby' => $id.$i.'-tab',
1213
                ]
1214
            );
1215
            $i++;
1216
        }
1217
1218
        $attributes['id'] = $id;
1219
        $attributes['class'] = 'tab_wrapper';
1220
1221
        $html = self::tag(
1222
            'div',
1223
            $ul.
1224
            self::tag('div', $divs, ['class' => 'tab-content']),
1225
            $attributes
1226
        );
1227
1228
        return $html;
1229
    }
1230
1231
    /**
1232
     * @param $headers
1233
     * @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...
1234
     *
1235
     * @return string
1236
     */
1237
    public static function tabsOnlyLink($headers, $selected = null)
1238
    {
1239
        $id = uniqid();
1240
        $i = 1;
1241
        $lis = null;
1242
        foreach ($headers as $item) {
1243
            $class = null;
1244
            if ($i == $selected) {
1245
                $class = 'active';
1246
            }
1247
            $item = self::tag(
1248
                'a',
1249
                $item['content'],
1250
                [
1251
                    'id' => $id.'-'.$i,
1252
                    'href' => $item['url'],
1253
                    'class' => 'nav-link '.$class,
1254
                ]
1255
            );
1256
            $lis .= self::tag('li', $item, ['class' => 'nav-item']);
1257
            $i++;
1258
        }
1259
1260
        return self::tag(
1261
            'ul',
1262
            $lis,
1263
            ['class' => 'nav nav-tabs tabs-margin']
1264
        );
1265
    }
1266
1267
    /**
1268
     * In order to display a grid using jqgrid you have to:.
1269
     *
1270
     * @example
1271
     * After your Display::display_header function you have to add the nex javascript code:
1272
     * <script>
1273
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1274
     *   // for more information of this function check the grid_js() function
1275
     * </script>
1276
     * //Then you have to call the grid_html
1277
     * echo Display::grid_html('my_grid_name');
1278
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1279
     *
1280
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1281
     *
1282
     * @return string html
1283
     */
1284
    public static function grid_html($div_id)
1285
    {
1286
        $table = self::tag('table', '', ['id' => $div_id]);
1287
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1288
1289
        return $table;
1290
    }
1291
1292
    /**
1293
     * @param string $label
1294
     * @param string $form_item
1295
     *
1296
     * @return string
1297
     */
1298
    public static function form_row($label, $form_item)
1299
    {
1300
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1301
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1302
1303
        return self::div($label.$form_item, ['class' => 'form-group']);
1304
    }
1305
1306
    /**
1307
     * This is a wrapper to use the jqgrid in Chamilo.
1308
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1309
     * This function need to be in the ready jquery function
1310
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1311
     * In order to work this function needs the Display::grid_html function with the same div id.
1312
     *
1313
     * @param string $div_id       div id
1314
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1315
     * @param array  $column_names visible columns (you should use get_lang).
1316
     *                             An array in which we place the names of the columns.
1317
     *                             This is the text that appears in the head of the grid (Header layer).
1318
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1319
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1320
     *                             This is the most important part of the grid.
1321
     *                             For a full description of all valid values see colModel API. See the url above.
1322
     * @param array  $extra_params extra parameters
1323
     * @param array  $data         data that will be loaded
1324
     * @param string $formatter    A string that will be appended to the JSON returned
1325
     * @param bool   $fixed_width  not implemented yet
1326
     *
1327
     * @return string the js code
1328
     */
1329
    public static function grid_js(
1330
        $div_id,
1331
        $url,
1332
        $column_names,
1333
        $column_model,
1334
        $extra_params,
1335
        $data = [],
1336
        $formatter = '',
1337
        $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

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

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

2626
        /** @scrutinizer ignore-unused */ $idCollapse = null,

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

Loading history...
2627
        $open = true,
2628
        $fullClickable = false
2629
    ) {
2630
        if (!empty($idAccordion)) {
2631
            $headerClass = '';
2632
            $headerClass .= $fullClickable ? 'center-block ' : '';
2633
            $headerClass .= $open ? '' : 'collapsed';
2634
            $contentClass = 'panel-collapse collapse ';
2635
            $contentClass .= $open ? 'in' : '';
2636
            $ariaExpanded = $open ? 'true' : 'false';
2637
            $html = <<<HTML
2638
            
2639
                <div class="card" id="$id">
2640
                    <div class="card-header">                        
2641
                        $title                        
2642
                    </div>                    
2643
                    <div class="card-body">$content</div>                    
2644
                </div>
2645
            
2646
HTML;
2647
        } else {
2648
            if (!empty($id)) {
2649
                $params['id'] = $id;
2650
            }
2651
            $params['class'] = 'card';
2652
            $html = null;
2653
            if (!empty($title)) {
2654
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2655
            }
2656
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2657
            $html = self::div($html, $params);
2658
        }
2659
2660
        return $html;
2661
    }
2662
2663
    /**
2664
     * Returns the string "1 day ago" with a link showing the exact date time.
2665
     *
2666
     * @param string $dateTime in UTC or a DateTime in UTC
2667
     *
2668
     * @return string
2669
     */
2670
    public static function dateToStringAgoAndLongDate($dateTime)
2671
    {
2672
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2673
            return '';
2674
        }
2675
2676
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2677
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2678
        }
2679
2680
        return self::tip(
2681
            date_to_str_ago($dateTime),
2682
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2683
            //api_get_local_time($dateTime)
2684
        );
2685
    }
2686
2687
    /**
2688
     * @param array  $userInfo
2689
     * @param string $status
2690
     * @param string $toolbar
2691
     *
2692
     * @return string
2693
     */
2694
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2695
    {
2696
        if (empty($userInfo)) {
2697
            return '';
2698
        }
2699
2700
        if (!empty($status)) {
2701
            $status = '<div class="items-user-status">'.$status.'</div>';
2702
        }
2703
2704
        if (!empty($toolbar)) {
2705
            $toolbar = '<div class="btn-group float-right">'.$toolbar.'</div>';
2706
        }
2707
2708
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">                    
2709
                    <img src="'.$userInfo['avatar'].'" class="rounded">
2710
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>                    
2711
                    <div class="card-body">                       
2712
                       <div class="card-title">
2713
                       '.$status.'
2714
                       '.$toolbar.'
2715
                       </div> 
2716
                    </div>
2717
                    <hr />
2718
              </div>';
2719
    }
2720
2721
    /**
2722
     * @param string $frameName
2723
     *
2724
     * @return string
2725
     */
2726
    public static function getFrameReadyBlock($frameName)
2727
    {
2728
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
2729
        $features = api_get_configuration_value('video_features');
2730
        if (!empty($features) && isset($features['features'])) {
2731
            foreach ($features['features'] as $feature) {
2732
                if ($feature === 'vrview') {
2733
                    continue;
2734
                }
2735
                $defaultFeatures[] = $feature;
2736
            }
2737
        }
2738
2739
        $defaultFeatures = implode("','", $defaultFeatures);
2740
        $frameReady = '
2741
          $.frameReady(function() {
2742
            $(document).ready(function () {
2743
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2744
                    pluginPath: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/",            
2745
                    features: ["'.$defaultFeatures.'"],
2746
                    success: function(mediaElement, originalNode, instance) {
2747
                    },
2748
                    vrPath: "'.api_get_path(WEB_PUBLIC_PATH).'assets/vrview/build/vrview.js"
2749
                });
2750
            });
2751
          }, "'.$frameName.'",
2752
          {
2753
            load: [
2754
                { type:"script", id:"_fr1", src:"'.api_get_jquery_web_path().'"},
2755
                { type:"script", id:"_fr7", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
2756
                { type:"script", id:"_fr4", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js"},
2757
                { type:"stylesheet", id:"_fr5", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
2758
                { type:"stylesheet", id:"_fr6", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/theme.css"},
2759
                { type:"script", id:"_fr2", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2760
                { type:"script", id:"_fr3", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2761
                {type: "script", id: "_media1", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/mediaelement-and-player.min.js"},
2762
                {type: "stylesheet", id: "_media2", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/mediaelementplayer.min.css"},                
2763
                {type: "stylesheet", id: "_media4", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/plugins/vrview/vrview.css"},
2764
                {type: "script", id: "_media4", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/plugins/vrview/vrview.js"},
2765
            ]
2766
          });';
2767
2768
        return $frameReady;
2769
    }
2770
2771
    public static function dropdownMenu($items = [], array $attr = [])
2772
    {
2773
        $links = null;
2774
        $url = null;
2775
        foreach ($items as $row) {
2776
            $url = self::url($row['icon'].$row['item'], $row['url'], ['class' => 'dropdown-item']);
2777
            $links .= self::tag('li', $url);
2778
        }
2779
        $html = self::tag('ul', $links, $attr);
2780
2781
        return  $html;
2782
    }
2783
2784
    /**
2785
     * @param $id
2786
     *
2787
     * @return array|mixed
2788
     */
2789
    public static function randomColor($id)
2790
    {
2791
        static $colors = [];
2792
2793
        if (!empty($colors[$id])) {
2794
            return $colors[$id];
2795
        } else {
2796
            $color = substr(md5(time() * $id), 0, 6);
2797
            $c1 = hexdec(substr($color, 0, 2));
2798
            $c2 = hexdec(substr($color, 2, 2));
2799
            $c3 = hexdec(substr($color, 4, 2));
2800
            $luminosity = $c1 + $c2 + $c3;
2801
2802
            $type = '#000000';
2803
            if ($luminosity < (255 + 255 + 255) / 2) {
2804
                $type = '#FFFFFF';
2805
            }
2806
2807
            $result = [
2808
                'color' => '#'.$color,
2809
                'luminosity' => $type,
2810
            ];
2811
            $colors[$id] = $result;
2812
2813
            return $result; // example: #fc443a
2814
        }
2815
    }
2816
}
2817