Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

Display::tag()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 3
dl 0
loc 18
rs 9.6111
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
            $session_info = api_get_session_info($session_id);
1728
            $coachInfo = [];
1729
            if (!empty($session['id_coach'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $session does not exist. Did you maybe mean $session_info?
Loading history...
1730
                $coachInfo = api_get_user_info($session['id_coach']);
1731
            }
1732
1733
            $session = [];
1734
            $session['category'] = SessionManager::get_session_category($session_info['session_category_id']);
1735
            $session['title'] = $session_info['name'];
1736
            $session['coach_id'] = $session_info['id_coach'];
1737
1738
            if (api_get_setting('show_session_coach') === 'true') {
1739
                $session['coach_name'] = api_get_person_name($session_info['firstname'], $session_info['lastname']);
1740
            }
1741
1742
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1743
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1744
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1745
            ) {
1746
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1747
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1748
                    $session['duration'] = $daysLeft >= 0
1749
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1750
                        : get_lang('YourSessionTimeHasExpired');
1751
                }
1752
                $active = true;
1753
            } else {
1754
                $dates = SessionManager::parseSessionDates($session_info, true);
1755
                $session['dates'] = $dates['access'];
1756
                $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...
1757
            }
1758
            $session['active'] = $active;
1759
            $session['visibility'] = $session_info['visibility'];
1760
            $session['num_users'] = $session_info['nbr_users'];
1761
            $session['num_courses'] = $session_info['nbr_courses'];
1762
            $session['description'] = $session_info['description'];
1763
            $session['show_description'] = $session_info['show_description'];
1764
            $session['image'] = SessionManager::getSessionImage($session_info['id']);
1765
            $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id'];
1766
1767
            $entityManager = Database::getManager();
1768
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1769
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(ExtraField::SESSION_FIELD_TYPE, $session_id);
1770
1771
            $session['extra_fields'] = [];
1772
            /** @var \Chamilo\CoreBundle\Entity\ExtraFieldValues $value */
1773
            foreach ($extraFieldValues as $value) {
1774
                if (empty($value)) {
1775
                    continue;
1776
                }
1777
                $session['extra_fields'][] = [
1778
                    'field' => [
1779
                        'variable' => $value->getField()->getVariable(),
1780
                        'display_text' => $value->getField()->getDisplayText(),
1781
                    ],
1782
                    'value' => $value->getValue(),
1783
                ];
1784
            }
1785
1786
            $output = $session;
1787
        }
1788
1789
        return $output;
1790
    }
1791
1792
    /**
1793
     * Return the five star HTML.
1794
     *
1795
     * @param string $id              of the rating ul element
1796
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1797
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1798
     * @param bool   $add_div_wrapper add a div wrapper
1799
     *
1800
     * @return string
1801
     */
1802
    public static function return_rating_system(
1803
        $id,
1804
        $url,
1805
        $point_info = [],
1806
        $add_div_wrapper = true
1807
    ) {
1808
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1809
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1810
1811
        if (!empty($percentage)) {
1812
            $percentage = $percentage * 125 / 100;
1813
        }
1814
1815
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1816
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1817
1818
        $html= '<section class="rating-widget">';
1819
        $html.= '<div class="rating-stars"><ul id="stars">';
1820
        $html.= '<li class="star" data-link="'.$url.'&amp;star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li>
1821
                 <li class="star" data-link="'.$url.'&amp;star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li>
1822
                 <li class="star" data-link="'.$url.'&amp;star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li>
1823
                 <li class="star" data-link="'.$url.'&amp;star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li>
1824
                 <li class="star" data-link="'.$url.'&amp;star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li>
1825
        ';
1826
        $html.= '</ul></div>';
1827
        $html.= '</section>';
1828
        /*$html.= '<ul id="'.$id.'" class="star-rating">
1829
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1830
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1831
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1832
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1833
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1834
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1835
                </ul>';*/
1836
1837
        $labels = [];
1838
1839
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1840
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1841
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1842
1843
        if (!$add_div_wrapper && api_is_anonymous()) {
1844
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1845
        }
1846
1847
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1848
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1849
1850
        if ($add_div_wrapper) {
1851
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1852
        }
1853
1854
        return $html;
1855
    }
1856
1857
    /**
1858
     * @param string $title
1859
     * @param string $second_title
1860
     * @param string $size
1861
     * @param bool   $filter
1862
     *
1863
     * @return string
1864
     */
1865
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1866
    {
1867
        if ($filter) {
1868
            $title = Security::remove_XSS($title);
1869
        }
1870
1871
        if (!empty($second_title)) {
1872
            if ($filter) {
1873
                $second_title = Security::remove_XSS($second_title);
1874
            }
1875
            $title .= "<small> $second_title</small>";
1876
        }
1877
1878
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1879
    }
1880
1881
    public static function page_header_and_translate($title, $second_title = null)
1882
    {
1883
        $title = get_lang($title);
1884
1885
        return self::page_header($title, $second_title);
1886
    }
1887
1888
    public static function page_subheader_and_translate($title, $second_title = null)
1889
    {
1890
        $title = get_lang($title);
1891
1892
        return self::page_subheader($title, $second_title);
1893
    }
1894
1895
    public static function page_subheader($title, $second_title = null, $size = 'h3')
1896
    {
1897
        if (!empty($second_title)) {
1898
            $second_title = Security::remove_XSS($second_title);
1899
            $title .= "<small> $second_title<small>";
1900
        }
1901
1902
        return '<'.$size.'>'.Security::remove_XSS($title).'</'.$size.'>';
1903
    }
1904
1905
    public static function page_subheader2($title, $second_title = null)
1906
    {
1907
        return self::page_header($title, $second_title, 'h4');
1908
    }
1909
1910
    public static function page_subheader3($title, $second_title = null)
1911
    {
1912
        return self::page_header($title, $second_title, 'h5');
1913
    }
1914
1915
    /**
1916
     * @param array $list
1917
     *
1918
     * @return string|null
1919
     */
1920
    public static function description($list)
1921
    {
1922
        $html = null;
1923
        if (!empty($list)) {
1924
            $html = '<dl class="dl-horizontal">';
1925
            foreach ($list as $item) {
1926
                $html .= '<dt>'.$item['title'].'</dt>';
1927
                $html .= '<dd>'.$item['content'].'</dd>';
1928
            }
1929
            $html .= '</dl>';
1930
        }
1931
1932
        return $html;
1933
    }
1934
1935
    /**
1936
     * @param $percentage
1937
     * @param bool $show_percentage
1938
     * @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...
1939
     *
1940
     * @return string
1941
     */
1942
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = null)
1943
    {
1944
        $percentage = intval($percentage);
1945
        $div = '<div class="progress">
1946
                <div
1947
                    class="progress-bar progress-bar-striped"
1948
                    role="progressbar"
1949
                    aria-valuenow="'.$percentage.'"
1950
                    aria-valuemin="0"
1951
                    aria-valuemax="100"
1952
                    style="width: '.$percentage.'%;"
1953
                >';
1954
        if ($show_percentage) {
1955
            $div .= $percentage.'%';
1956
        } else {
1957
            if (!empty($extra_info)) {
1958
                $div .= $extra_info;
1959
            }
1960
        }
1961
        $div .= '</div>';
1962
1963
        return $div;
1964
    }
1965
1966
    /**
1967
     * @param string $count
1968
     * @param string $type
1969
     *
1970
     * @return string|null
1971
     */
1972
    public static function badge($count, $type = "warning")
1973
    {
1974
        $class = '';
1975
1976
        switch ($type) {
1977
            case 'success':
1978
                $class = 'badge-success';
1979
                break;
1980
            case 'warning':
1981
                $class = 'badge-warning';
1982
                break;
1983
            case 'important':
1984
                $class = 'badge-important';
1985
                break;
1986
            case 'info':
1987
                $class = 'badge-info';
1988
                break;
1989
            case 'inverse':
1990
                $class = 'badge-inverse';
1991
                break;
1992
        }
1993
1994
        if (!empty($count)) {
1995
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1996
        }
1997
1998
        return null;
1999
    }
2000
2001
    /**
2002
     * @param array $badge_list
2003
     *
2004
     * @return string
2005
     */
2006
    public static function badge_group($badge_list)
2007
    {
2008
        $html = '<div class="badge-group">';
2009
        foreach ($badge_list as $badge) {
2010
            $html .= $badge;
2011
        }
2012
        $html .= '</div>';
2013
2014
        return $html;
2015
    }
2016
2017
    /**
2018
     * @param string $content
2019
     * @param string $type
2020
     *
2021
     * @return string
2022
     */
2023
    public static function label($content, $type = 'default')
2024
    {
2025
        switch ($type) {
2026
            case 'success':
2027
                $class = 'success';
2028
                break;
2029
            case 'warning':
2030
                $class = 'warning';
2031
                break;
2032
            case 'important':
2033
            case 'danger':
2034
                $class = 'danger';
2035
                break;
2036
            case 'info':
2037
                $class = 'info';
2038
                break;
2039
            case 'primary':
2040
                $class = 'primary';
2041
                break;
2042
            default:
2043
                $class = 'secondary';
2044
                break;
2045
        }
2046
2047
        $html = '';
2048
        if (!empty($content)) {
2049
            $html = '<span class="badge badge-'.$class.'">';
2050
            $html .= $content;
2051
            $html .= '</span>';
2052
        }
2053
2054
        return $html;
2055
    }
2056
2057
    /**
2058
     * @param array  $items
2059
     * @param string $class
2060
     *
2061
     * @return string|null
2062
     */
2063
    public static function actions($items, $class = 'new_actions')
2064
    {
2065
        $html = null;
2066
        if (!empty($items)) {
2067
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2068
            foreach ($items as $value) {
2069
                $class = null;
2070
                if (isset($value['active']) && $value['active']) {
2071
                    $class = 'class ="active"';
2072
                }
2073
2074
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2075
                    $class = 'class ="active"';
2076
                }
2077
                $html .= "<li $class >";
2078
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2079
                $html .= self::url($value['content'], $value['url'], $attributes);
2080
                $html .= '</li>';
2081
            }
2082
            $html .= '</ul></div>';
2083
            $html .= '<br />';
2084
        }
2085
2086
        return $html;
2087
    }
2088
2089
    /**
2090
     * Prints a tooltip.
2091
     *
2092
     * @param string $text
2093
     * @param string $tip
2094
     *
2095
     * @return string
2096
     */
2097
    public static function tip($text, $tip)
2098
    {
2099
        if (empty($tip)) {
2100
            return $text;
2101
        }
2102
2103
        return self::span(
2104
            $text,
2105
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2106
        );
2107
    }
2108
2109
    /**
2110
     * @param array  $items
2111
     * @param string $type
2112
     * @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...
2113
     *
2114
     * @return string|null
2115
     */
2116
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2117
    {
2118
        $html = null;
2119
        if (!empty($items)) {
2120
            if (empty($id)) {
2121
                $id = api_get_unique_id();
2122
            }
2123
            if ($type == 'jquery') {
2124
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2125
            } else {
2126
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2127
            }
2128
2129
            $count = 1;
2130
            foreach ($items as $item) {
2131
                $html .= '<div class="accordion-my-group">';
2132
                $html .= '<div class="accordion-heading">
2133
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2134
                            '.$item['title'].'
2135
                            </a>
2136
                          </div>';
2137
2138
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2139
                $html .= '<div class="accordion-my-inner">
2140
                            '.$item['content'].'
2141
                            </div>
2142
                          </div>';
2143
            }
2144
            $html .= '</div>';
2145
        }
2146
2147
        return $html;
2148
    }
2149
2150
    /**
2151
     * @param array $buttons
2152
     *
2153
     * @return string
2154
     */
2155
    public static function groupButton($buttons)
2156
    {
2157
        $html = '<div class="btn-group" role="group">';
2158
        foreach ($buttons as $button) {
2159
            $html .= $button;
2160
        }
2161
        $html .= '</div>';
2162
2163
        return $html;
2164
    }
2165
2166
    /**
2167
     * @todo use twig
2168
     *
2169
     * @param string $title
2170
     * @param array  $elements
2171
     * @param bool   $alignToRight
2172
     *
2173
     * @return string
2174
     */
2175
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2176
    {
2177
        $id = uniqid('dropdown', true);
2178
        $html = '<div class="btn-group" role="group">
2179
                <button id = "'.$id.'" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
2180
                '.$title.'
2181
                </button>
2182
                <div class="dropdown-menu aria-labelledby="'.$id.'" '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2183
        foreach ($elements as $item) {
2184
            $html .= self::tag('li', self::url($item['title'], $item['href'], ['class' => 'dropdown-item']));
2185
        }
2186
        $html .= '</div>
2187
            </div>';
2188
2189
        return $html;
2190
    }
2191
2192
    /**
2193
     * @param string $file
2194
     * @param array  $params
2195
     *
2196
     * @return string|null
2197
     */
2198
    public static function getMediaPlayer($file, $params = [])
2199
    {
2200
        $fileInfo = pathinfo($file);
2201
2202
        switch ($fileInfo['extension']) {
2203
            case 'mp3':
2204
            case 'webm':
2205
                $autoplay = null;
2206
                if (isset($params['autoplay']) && $params['autoplay'] == 'true') {
2207
                    $autoplay = 'autoplay';
2208
                }
2209
                $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2210
                $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2211
                $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2212
2213
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2214
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2215
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2216
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2217
                          </object>';
2218
                $html .= '</audio>';
2219
2220
                return $html;
2221
                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...
2222
            case 'wav':
2223
            case 'ogg':
2224
                $html = '<audio width="300px" controls src="'.$params['url'].'" >';
2225
2226
                return $html;
2227
                break;
2228
        }
2229
2230
        return null;
2231
    }
2232
2233
    /**
2234
     * @param int    $nextValue
2235
     * @param array  $list
2236
     * @param int    $current
2237
     * @param int    $fixedValue
2238
     * @param array  $conditions
2239
     * @param string $link
2240
     * @param bool   $isMedia
2241
     * @param bool   $addHeaders
2242
     * @param array  $linkAttributes
2243
     *
2244
     * @return string
2245
     */
2246
    public static function progressPaginationBar(
2247
        $nextValue,
2248
        $list,
2249
        $current,
2250
        $fixedValue = null,
2251
        $conditions = [],
2252
        $link = null,
2253
        $isMedia = false,
2254
        $addHeaders = true,
2255
        $linkAttributes = []
2256
    ) {
2257
        if ($addHeaders) {
2258
            $pagination_size = 'pagination-mini';
2259
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2260
        } else {
2261
            $html = null;
2262
        }
2263
        $affectAllItems = false;
2264
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2265
            $affectAllItems = true;
2266
        }
2267
        $localCounter = 0;
2268
        foreach ($list as $itemId) {
2269
            $isCurrent = false;
2270
            if ($affectAllItems) {
2271
                $isCurrent = true;
2272
            } else {
2273
                if (!$isMedia) {
2274
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2275
                }
2276
            }
2277
            $html .= self::parsePaginationItem(
2278
                $itemId,
2279
                $isCurrent,
2280
                $conditions,
2281
                $link,
2282
                $nextValue,
2283
                $isMedia,
2284
                $localCounter,
2285
                $fixedValue,
2286
                $linkAttributes
2287
            );
2288
            $localCounter++;
2289
        }
2290
        if ($addHeaders) {
2291
            $html .= '</ul></div>';
2292
        }
2293
2294
        return $html;
2295
    }
2296
2297
    /**
2298
     * @param int    $itemId
2299
     * @param bool   $isCurrent
2300
     * @param array  $conditions
2301
     * @param string $link
2302
     * @param int    $nextValue
2303
     * @param bool   $isMedia
2304
     * @param int    $localCounter
2305
     * @param int    $fixedValue
2306
     * @param array  $linkAttributes
2307
     *
2308
     * @return string
2309
     */
2310
    public static function parsePaginationItem(
2311
        $itemId,
2312
        $isCurrent,
2313
        $conditions,
2314
        $link,
2315
        $nextValue = 0,
2316
        $isMedia = false,
2317
        $localCounter = null,
2318
        $fixedValue = null,
2319
        $linkAttributes = []
2320
    ) {
2321
        $defaultClass = 'before';
2322
        $class = $defaultClass;
2323
        foreach ($conditions as $condition) {
2324
            $array = isset($condition['items']) ? $condition['items'] : [];
2325
            $class_to_applied = $condition['class'];
2326
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2327
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2328
            switch ($type) {
2329
                case 'positive':
2330
                    if (in_array($itemId, $array)) {
2331
                        if ($mode == 'overwrite') {
2332
                            $class = " $defaultClass $class_to_applied";
2333
                        } else {
2334
                            $class .= " $class_to_applied";
2335
                        }
2336
                    }
2337
                    break;
2338
                case 'negative':
2339
                    if (!in_array($itemId, $array)) {
2340
                        if ($mode == 'overwrite') {
2341
                            $class = " $defaultClass $class_to_applied";
2342
                        } else {
2343
                            $class .= " $class_to_applied";
2344
                        }
2345
                    }
2346
                    break;
2347
            }
2348
        }
2349
        if ($isCurrent) {
2350
            $class = 'before current';
2351
        }
2352
        if ($isMedia && $isCurrent) {
2353
            $class = 'before current';
2354
        }
2355
        if (empty($link)) {
2356
            $link_to_show = '#';
2357
        } else {
2358
            $link_to_show = $link.($nextValue + $localCounter);
2359
        }
2360
        $label = $nextValue + $localCounter + 1;
2361
        if ($isMedia) {
2362
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2363
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2364
        }
2365
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2366
2367
        return  '<li class = "'.$class.'">'.$link.'</li>';
2368
    }
2369
2370
    /**
2371
     * @param int $current
2372
     * @param int $total
2373
     *
2374
     * @return string
2375
     */
2376
    public static function paginationIndicator($current, $total)
2377
    {
2378
        $html = null;
2379
        if (!empty($current) && !empty($total)) {
2380
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2381
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2382
        }
2383
2384
        return $html;
2385
    }
2386
2387
    /**
2388
     * Adds a message in the queue.
2389
     *
2390
     * @param string $message
2391
     */
2392
    public static function addFlash($message)
2393
    {
2394
        $messages = Session::read('flash_messages');
2395
        if (empty($messages)) {
2396
            $messages[] = $message;
2397
        } else {
2398
            array_push($messages, $message);
2399
        }
2400
        Session::write('flash_messages', $messages);
2401
    }
2402
2403
    /**
2404
     * @return string
2405
     */
2406
    public static function getFlashToString()
2407
    {
2408
        $messages = Session::read('flash_messages');
2409
        $messageToString = '';
2410
        if (!empty($messages)) {
2411
            foreach ($messages as $message) {
2412
                $messageToString .= $message;
2413
            }
2414
        }
2415
2416
        return $messageToString;
2417
    }
2418
2419
    /**
2420
     * Shows the message from the session.
2421
     */
2422
    public static function showFlash()
2423
    {
2424
        echo self::getFlashToString();
2425
    }
2426
2427
    /**
2428
     * Destroys the message session.
2429
     */
2430
    public static function cleanFlashMessages()
2431
    {
2432
        Session::erase('flash_messages');
2433
    }
2434
2435
    /**
2436
     * Get the profile edition link for a user.
2437
     *
2438
     * @param int  $userId  The user id
2439
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2440
     *
2441
     * @return string The link
2442
     */
2443
    public static function getProfileEditionLink($userId, $asAdmin = false)
2444
    {
2445
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2446
        if ($asAdmin) {
2447
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2448
        }
2449
2450
        return $editProfileUrl;
2451
    }
2452
2453
    /**
2454
     * Get the vCard for a user.
2455
     *
2456
     * @param int $userId The user id
2457
     *
2458
     * @return string *.*vcf file
2459
     */
2460
    public static function getVCardUserLink($userId)
2461
    {
2462
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2463
2464
        return $vCardUrl;
2465
    }
2466
2467
    /**
2468
     * @param string $content
2469
     * @param string $title
2470
     * @param string $footer
2471
     * @param string $type        primary|success|info|warning|danger
2472
     * @param string $extra
2473
     * @param string $id
2474
     * @param string $customColor
2475
     * @param string $rightAction
2476
     *
2477
     * @return string
2478
     */
2479
    public static function panel(
2480
        $content,
2481
        $title = '',
2482
        $footer = '',
2483
        $type = 'default',
2484
        $extra = '',
2485
        $id = '',
2486
        $customColor = '',
2487
        $rightAction = ''
2488
    ) {
2489
        $headerStyle = '';
2490
        if (!empty($customColor)) {
2491
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2492
        }
2493
2494
        if (!empty($rightAction)) {
2495
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2496
        }
2497
2498
        $title = !empty($title) ? '<h5 class="card-title">'.$title.' '.$rightAction.'</h5>'.$extra : '';
2499
        $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : '';
2500
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2501
        $style = !in_array($type, $typeList) ? 'default' : $type;
2502
2503
        if (!empty($id)) {
2504
            $id = " id='$id'";
2505
        }
2506
        $cardBody = $title.' '.self::contentPanel($content).' '.$footer;
2507
2508
        $panel = Display::tag('div', $cardBody, ['id' => 'card-'.$id, 'class' => 'card-body']);
2509
2510
        return '
2511
            <div '.$id.' class="card">
2512
                '.$panel.'
2513
            </div>'
2514
        ;
2515
    }
2516
2517
    /**
2518
     * @param string $content
2519
     *
2520
     * @return string
2521
     */
2522
    public static function contentPanel($content): string
2523
    {
2524
        if (empty($content)) {
2525
            return '';
2526
        }
2527
2528
        return '<div class="card-text">'.$content.'</div>';
2529
    }
2530
2531
    /**
2532
     * Get the button HTML with an Awesome Font icon.
2533
     *
2534
     * @param string $text        The button content
2535
     * @param string $url         The url to button
2536
     * @param string $icon        The Awesome Font class for icon
2537
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2538
     * @param array  $attributes  The additional attributes
2539
     * @param bool   $includeText
2540
     *
2541
     * @return string The button HTML
2542
     */
2543
    public static function toolbarButton(
2544
        $text,
2545
        $url,
2546
        $icon = 'check',
2547
        $type = null,
2548
        array $attributes = [],
2549
        $includeText = true
2550
    ) {
2551
        $buttonClass = "btn btn-outline-secondary";
2552
        if (!empty($type)) {
2553
            $buttonClass = "btn btn-$type";
2554
        }
2555
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2556
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2557
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2558
2559
        if (!$includeText) {
2560
            $text = '<span class="sr-only">'.$text.'</span>';
2561
        }
2562
2563
        return self::url("$icon $text", $url, $attributes);
2564
    }
2565
2566
    /**
2567
     * @param string $id
2568
     * @param array  $content
2569
     * @param array  $colsWidth Optional. Columns width
2570
     *
2571
     * @return string
2572
     */
2573
    public static function toolbarAction($id, $content, $colsWidth = [])
2574
    {
2575
        $col = count($content);
2576
2577
        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...
2578
            $width = 12 / $col;
2579
            array_walk($content, function () use ($width, &$colsWidth) {
2580
                $colsWidth[] = $width;
2581
            });
2582
        }
2583
2584
        $html = '<div id="'.$id.'" class="actions" >';
2585
        $html .= '<div class="row">';
2586
2587
        for ($i = 0; $i < $col; $i++) {
2588
            $class = 'col-sm-'.$colsWidth[$i];
2589
2590
            if ($col > 1) {
2591
                if ($i > 0 && $i < count($content) - 1) {
2592
                    $class .= ' text-center';
2593
                } elseif ($i === count($content) - 1) {
2594
                    $class .= ' text-right';
2595
                }
2596
            }
2597
2598
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2599
        }
2600
2601
        $html .= '</div>';
2602
        $html .= '</div>';
2603
2604
        return $html;
2605
    }
2606
2607
    /**
2608
     * Get a HTML code for a icon by Font Awesome.
2609
     *
2610
     * @param string     $name            The icon name
2611
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2612
     * @param bool       $fixWidth        Optional. Whether add the fw class
2613
     * @param string     $additionalClass Optional. Additional class
2614
     *
2615
     * @return string
2616
     */
2617
    public static function returnFontAwesomeIcon(
2618
        $name,
2619
        $size = '',
2620
        $fixWidth = false,
2621
        $additionalClass = ''
2622
    ) {
2623
        $className = "fa fa-$name";
2624
2625
        if ($fixWidth) {
2626
            $className .= ' fa-fw';
2627
        }
2628
2629
        switch ($size) {
2630
            case 'xs':
2631
            case 'sm':
2632
            case 'lg':
2633
                $className .= " fa-{$size}";
2634
                break;
2635
            case 2:
2636
            case 3:
2637
            case 4:
2638
            case 5:
2639
                $className .= " fa-{$size}x";
2640
                break;
2641
        }
2642
2643
        if (!empty($additionalClass)) {
2644
            $className .= " $additionalClass";
2645
        }
2646
2647
        $icon = self::tag('em', null, ['class' => $className]);
2648
2649
        return "$icon ";
2650
    }
2651
2652
    /**
2653
     * @param string     $title
2654
     * @param string     $content
2655
     * @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...
2656
     * @param array      $params
2657
     * @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...
2658
     * @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...
2659
     * @param bool|true  $open
2660
     * @param bool|false $fullClickable
2661
     *
2662
     * @return string|null
2663
     *
2664
     * @todo rework function to easy use
2665
     */
2666
    public static function panelCollapse(
2667
        $title,
2668
        $content,
2669
        $id = null,
2670
        $params = [],
2671
        $idAccordion = null,
2672
        $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

2672
        /** @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...
2673
        $open = true,
2674
        $fullClickable = false
2675
    ) {
2676
        if (!empty($idAccordion)) {
2677
            $headerClass = '';
2678
            $headerClass .= $fullClickable ? 'center-block ' : '';
2679
            $headerClass .= $open ? '' : 'collapsed';
2680
            $contentClass = 'panel-collapse collapse ';
2681
            $contentClass .= $open ? 'in' : '';
2682
            $ariaExpanded = $open ? 'true' : 'false';
2683
            $html = <<<HTML
2684
            
2685
                <div class="card" id="$id">
2686
                    <div class="card-header">                        
2687
                        $title                        
2688
                    </div>                    
2689
                    <div class="card-body">$content</div>                    
2690
                </div>
2691
            
2692
HTML;
2693
        } else {
2694
            if (!empty($id)) {
2695
                $params['id'] = $id;
2696
            }
2697
            $params['class'] = 'card';
2698
            $html = null;
2699
            if (!empty($title)) {
2700
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2701
            }
2702
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2703
            $html = self::div($html, $params);
2704
        }
2705
2706
        return $html;
2707
    }
2708
2709
    /**
2710
     * Returns the string "1 day ago" with a link showing the exact date time.
2711
     *
2712
     * @param string $dateTime in UTC or a DateTime in UTC
2713
     *
2714
     * @return string
2715
     */
2716
    public static function dateToStringAgoAndLongDate($dateTime)
2717
    {
2718
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2719
            return '';
2720
        }
2721
2722
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2723
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2724
        }
2725
2726
        return self::tip(
2727
            date_to_str_ago($dateTime),
2728
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2729
            //api_get_local_time($dateTime)
2730
        );
2731
    }
2732
2733
    /**
2734
     * @param array  $userInfo
2735
     * @param string $status
2736
     * @param string $toolbar
2737
     *
2738
     * @return string
2739
     */
2740
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2741
    {
2742
        if (empty($userInfo)) {
2743
            return '';
2744
        }
2745
2746
        if (!empty($status)) {
2747
            $status = '<div class="items-user-status">'.$status.'</div>';
2748
        }
2749
2750
        if (!empty($toolbar)) {
2751
            $toolbar = '<div class="btn-group float-right">'.$toolbar.'</div>';
2752
        }
2753
2754
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">                    
2755
                    <img src="'.$userInfo['avatar'].'" class="rounded">
2756
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>                    
2757
                    <div class="card-body">                       
2758
                       <div class="card-title">
2759
                       '.$status.'
2760
                       '.$toolbar.'
2761
                       </div> 
2762
                    </div>
2763
                    <hr />
2764
              </div>';
2765
    }
2766
2767
    /**
2768
     * @param string $fileName
2769
     * @param string $fileUrl
2770
     *
2771
     * @return string
2772
     */
2773
    public static function fileHtmlGuesser($fileName, $fileUrl)
2774
    {
2775
        $data = pathinfo($fileName);
2776
2777
        //$content = self::url($data['basename'], $fileUrl);
2778
        $content = '';
2779
        switch ($data['extension']) {
2780
            case 'webm':
2781
            case 'mp4':
2782
            case 'ogg':
2783
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2784
                // Allows video to play when loading during an ajax call
2785
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2786
                break;
2787
            case 'jpg':
2788
            case 'jpeg':
2789
            case 'gif':
2790
            case 'png':
2791
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2792
                break;
2793
            default:
2794
                //$html = self::url($data['basename'], $fileUrl);
2795
                break;
2796
        }
2797
        //$html = self::url($content, $fileUrl, ['ajax']);
2798
2799
        return $content;
2800
    }
2801
2802
    /**
2803
     * @param string $frameName
2804
     *
2805
     * @return string
2806
     */
2807
    public static function getFrameReadyBlock($frameName)
2808
    {
2809
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
2810
        $features = api_get_configuration_value('video_features');
2811
        $bowerJsFiles = [];
2812
        $bowerCSSFiles = [];
2813
        if (!empty($features) && isset($features['features'])) {
2814
            foreach ($features['features'] as $feature) {
2815
                if ($feature === 'vrview') {
2816
                    continue;
2817
                }
2818
                $defaultFeatures[] = $feature;
2819
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
2820
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
2821
            }
2822
        }
2823
2824
        $translateHtml = '';
2825
        $translate = api_get_configuration_value('translate_html');
2826
        if ($translate) {
2827
            $translateHtml = '{type:"script", id:"_fr4", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2828
        }
2829
2830
        $counter = 10;
2831
        $extraMediaFiles = '';
2832
        foreach ($bowerJsFiles as $file) {
2833
            $extraMediaFiles .= '{type: "script", id: "media_'.$counter.'", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"},';
2834
            $counter++;
2835
        }
2836
2837
        foreach ($bowerCSSFiles as $file) {
2838
            $extraMediaFiles .= '{type: "stylesheet", id: "media_'.$counter.'", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"},';
2839
            $counter++;
2840
        }
2841
2842
        $defaultFeatures = implode("','", $defaultFeatures);
2843
        $frameReady = '
2844
          $.frameReady(function() {
2845
            $(function() {
2846
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({                    
2847
                    pluginPath: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/",            
2848
                    features: ["'.$defaultFeatures.'"],
2849
                    success: function(mediaElement, originalNode, instance) {
2850
                    },
2851
                    vrPath: "'.api_get_path(WEB_PUBLIC_PATH).'assets/vrview/build/vrview.js"
2852
                });
2853
            });
2854
          }, "'.$frameName.'",
2855
          {
2856
            load: [
2857
                { type:"script", id:"_fr1", src:"'.api_get_jquery_web_path().'"},
2858
                { type:"script", id:"_fr7", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
2859
                { type:"script", id:"_fr4", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js"},
2860
                { type:"stylesheet", id:"_fr5", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
2861
                { type:"stylesheet", id:"_fr6", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/theme.css"},
2862
                { type:"script", id:"_fr2", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2863
                { type:"stylesheet", id:"_fr7", src:"'.api_get_path(WEB_PUBLIC_PATH).'css/dialog.css"},
2864
                { type:"script", id:"_fr3", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2865
                {type: "script", id: "_media1", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/mediaelement-and-player.min.js"},
2866
                {type: "stylesheet", id: "_media2", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/build/mediaelementplayer.min.css"},                
2867
                {type: "stylesheet", id: "_media4", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/plugins/vrview/vrview.css"},
2868
                {type: "script", id: "_media4", src: "'.api_get_path(WEB_PUBLIC_PATH).'assets/mediaelement/plugins/vrview/vrview.js"},
2869
                '.$extraMediaFiles.'
2870
                '.$translateHtml.'
2871
            ]
2872
          });';
2873
2874
        return $frameReady;
2875
    }
2876
2877
    /**
2878
     * @param string $image
2879
     * @param int    $size
2880
     *
2881
     * @return string
2882
     */
2883
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2884
    {
2885
        return self::return_icon($image, '', [], $size, false, true);
2886
    }
2887
2888
    /**
2889
     * @param string $image
2890
     * @param int    $size
2891
     * @param string $name
2892
     *
2893
     * @return string
2894
     */
2895
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
2896
    {
2897
        return self::return_icon($image, $name, [], $size);
2898
    }
2899
2900
    public static function dropdownMenu($items = [], array $attr = [])
2901
    {
2902
        $links = null;
2903
        $url = null;
2904
        foreach ($items as $row) {
2905
            $url = self::url($row['icon'].$row['item'], $row['url'], ['class' => 'dropdown-item']);
2906
            $links .= self::tag('li', $url);
2907
        }
2908
        $html = self::tag('ul', $links, $attr);
2909
2910
        return  $html;
2911
    }
2912
2913
    /**
2914
     * @param $id
2915
     *
2916
     * @return array|mixed
2917
     */
2918
    public static function randomColor($id)
2919
    {
2920
        static $colors = [];
2921
2922
        if (!empty($colors[$id])) {
2923
            return $colors[$id];
2924
        } else {
2925
            $color = substr(md5(time() * $id), 0, 6);
2926
            $c1 = hexdec(substr($color, 0, 2));
2927
            $c2 = hexdec(substr($color, 2, 2));
2928
            $c3 = hexdec(substr($color, 4, 2));
2929
            $luminosity = $c1 + $c2 + $c3;
2930
2931
            $type = '#000000';
2932
            if ($luminosity < (255 + 255 + 255) / 2) {
2933
                $type = '#FFFFFF';
2934
            }
2935
2936
            $result = [
2937
                'color' => '#'.$color,
2938
                'luminosity' => $type,
2939
            ];
2940
            $colors[$id] = $result;
2941
2942
            return $result; // example: #fc443a
2943
        }
2944
    }
2945
}
2946