Passed
Push — master ( e739b7...1cdc43 )
by Julito
10:11
created

Display::encrypted_mailto_link()   F

Complexity

Conditions 13
Paths 352

Size

Total Lines 68
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 37
nc 352
nop 4
dl 0
loc 68
rs 3.8833
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        $addExtraContent = false
629
    ) {
630
        if (is_null($clickable_text)) {
631
            $clickable_text = $email;
632
        }
633
634
        // "mailto:" already present?
635
        if (substr($email, 0, 7) != 'mailto:') {
636
            $email = 'mailto:'.$email;
637
        }
638
639
        // Class (stylesheet) defined?
640
        if ($style_class != '') {
641
            $style_class = ' class="'.$style_class.'"';
642
        }
643
644
        // Encrypt email
645
        $hmail = '';
646
        for ($i = 0; $i < strlen($email); $i++) {
647
            $hmail .= '&#'.ord($email[$i]).';';
648
        }
649
650
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
651
652
        if ($value) {
653
            $hmail .= '?';
654
            if (!api_is_anonymous()) {
655
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
656
            }
657
            if ($addExtraContent) {
658
                $content = '';
659
                if (!api_is_anonymous()) {
660
                    $userInfo = api_get_user_info();
661
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
662
663
                    $courseInfo = api_get_course_info();
664
                    if (!empty($courseInfo)) {
665
                        $content .= get_lang('Course').': ';
666
                        $content .= $courseInfo['name'];
667
                        $sessionInfo = api_get_session_info(api_get_session_id());
668
                        if (!empty($sessionInfo)) {
669
                            $content .= ' '.$sessionInfo['name'].' <br />';
670
                        }
671
                    }
672
                }
673
                $hmail .= '&body='.rawurlencode($content);
674
            }
675
        }
676
677
        $hclickable_text = '';
678
        // Encrypt clickable text if @ is present
679
        if (strpos($clickable_text, '@')) {
680
            for ($i = 0; $i < strlen($clickable_text); $i++) {
681
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
682
            }
683
        } else {
684
            $hclickable_text = @htmlspecialchars(
685
                $clickable_text,
686
                ENT_QUOTES,
687
                api_get_system_encoding()
688
            );
689
        }
690
        // Return encrypted mailto hyperlink
691
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
692
    }
693
694
    /**
695
     * Returns an mailto icon hyperlink.
696
     *
697
     * @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...
698
     * @param string  icon source file from the icon lib
699
     * @param int  icon size from icon lib
700
     * @param string  optional, class from stylesheet
701
     *
702
     * @return string encrypted mailto hyperlink
703
     */
704
    public static function icon_mailto_link(
705
        $email,
706
        $icon_file = "mail.png",
707
        $icon_size = 22,
708
        $style_class = ''
709
    ) {
710
        // "mailto:" already present?
711
        if (substr($email, 0, 7) != 'mailto:') {
712
            $email = 'mailto:'.$email;
713
        }
714
        // Class (stylesheet) defined?
715
        if ($style_class != '') {
716
            $style_class = ' class="'.$style_class.'"';
717
        }
718
        // Encrypt email
719
        $hmail = '';
720
        for ($i = 0; $i < strlen($email); $i++) {
721
            $hmail .= '&#'.ord($email[
722
            $i]).';';
723
        }
724
        // icon html code
725
        $icon_html_source = self::return_icon(
726
            $icon_file,
727
            $hmail,
728
            '',
729
            $icon_size
730
        );
731
        // Return encrypted mailto hyperlink
732
733
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
734
    }
735
736
    /**
737
     * Prints an <option>-list with all letters (A-Z).
738
     *
739
     * @param string $selected_letter The letter that should be selected
740
     *
741
     * @todo This is English language specific implementation.
742
     * It should be adapted for the other languages.
743
     *
744
     * @return string
745
     */
746
    public static function get_alphabet_options($selectedLetter = '')
747
    {
748
        $result = '';
749
        for ($i = 65; $i <= 90; $i++) {
750
            $letter = chr($i);
751
            $result .= '<option value="'.$letter.'"';
752
            if ($selectedLetter == $letter) {
753
                $result .= ' selected="selected"';
754
            }
755
            $result .= '>'.$letter.'</option>';
756
        }
757
758
        return $result;
759
    }
760
761
    /**
762
     * Get the options withing a select box within the given values.
763
     *
764
     * @param int   Min value
765
     * @param int   Max value
766
     * @param int   Default value
767
     *
768
     * @return string HTML select options
769
     */
770
    public static function get_numeric_options($min, $max, $selected_num = 0)
771
    {
772
        $result = '';
773
        for ($i = $min; $i <= $max; $i++) {
774
            $result .= '<option value="'.$i.'"';
775
            if (is_int($selected_num)) {
776
                if ($selected_num == $i) {
777
                    $result .= ' selected="selected"';
778
                }
779
            }
780
            $result .= '>'.$i.'</option>';
781
        }
782
783
        return $result;
784
    }
785
786
    /**
787
     * This public function displays an icon.
788
     *
789
     * @param string   The filename of the file (in the main/img/ folder
790
     * @param string   The alt text (probably a language variable)
791
     * @param array    additional attributes (for instance height, width, onclick, ...)
792
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
793
     */
794
    public static function display_icon(
795
        $image,
796
        $alt_text = '',
797
        $additional_attributes = [],
798
        $size = null
799
    ) {
800
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
801
    }
802
803
    /**
804
     * Gets the path of an icon.
805
     *
806
     * @param string $icon
807
     * @param int    $size
808
     *
809
     * @return string
810
     */
811
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
812
    {
813
        return self::return_icon($icon, null, null, $size, null, true, false);
814
    }
815
816
    /**
817
     * This public function returns the htmlcode for an icon.
818
     *
819
     * @param string   The filename of the file (in the main/img/ folder
820
     * @param string   The alt text (probably a language variable)
821
     * @param array    Additional attributes (for instance height, width, onclick, ...)
822
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
823
     *
824
     * @return string An HTML string of the right <img> tag
825
     *
826
     * @author Patrick Cool <[email protected]>, Ghent University 2006
827
     * @author Julio Montoya 2010 Function improved, adding image constants
828
     * @author Yannick Warnier 2011 Added size handler
829
     *
830
     * @version Feb 2011
831
     */
832
    public static function return_icon(
833
        $image,
834
        $alt_text = '',
835
        $additional_attributes = [],
836
        $size = ICON_SIZE_SMALL,
837
        $show_text = true,
838
        $return_only_path = false,
839
        $loadThemeIcon = true
840
    ) {
841
        $code_path = api_get_path(SYS_PUBLIC_PATH);
842
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
843
        // The following path is checked to see if the file exist. It's
844
        // important to use the public path (i.e. web/css/) rather than the
845
        // internal path (/app/Resource/public/css/) because the path used
846
        // in the end must be the public path
847
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
848
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
849
850
        // Avoid issues with illegal string offset for legacy calls to this
851
        // method with an empty string rather than null or an empty array
852
        if (empty($additional_attributes)) {
853
            $additional_attributes = [];
854
        }
855
856
        $image = trim($image);
857
858
        if (isset($size)) {
859
            $size = intval($size);
860
        } else {
861
            $size = ICON_SIZE_SMALL;
862
        }
863
864
        $size_extra = $size.'/';
865
        $icon = $w_code_path.'img/'.$image;
866
        $theme = 'themes/chamilo/icons/';
867
868
        if ($loadThemeIcon) {
869
            // @todo with chamilo 2 code
870
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
871
            if (is_file($alternateCssPath.$theme.$image)) {
872
                $icon = $alternateWebCssPath.$theme.$image;
873
            }
874
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
875
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
876
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
877
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
878
                //Checking the main/img/icons/XXX/ folder
879
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
880
            }
881
        } else {
882
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
883
                // Checking the main/img/icons/XXX/ folder
884
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
885
            }
886
        }
887
888
        // Special code to enable SVG - refs #7359 - Needs more work
889
        // The code below does something else to "test out" SVG: for each icon,
890
        // it checks if there is an SVG version. If so, it uses it.
891
        // When moving this to production, the return_icon() calls should
892
        // ask for the SVG version directly
893
        $svgIcons = api_get_setting('icons_mode_svg');
894
        if ($svgIcons == 'true' && $return_only_path == false) {
895
            $svgImage = substr($image, 0, -3).'svg';
896
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
897
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
898
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
899
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
900
            }
901
902
            if (empty($additional_attributes['height'])) {
903
                $additional_attributes['height'] = $size;
904
            }
905
            if (empty($additional_attributes['width'])) {
906
                $additional_attributes['width'] = $size;
907
            }
908
        }
909
910
        $icon = api_get_cdn_path($icon);
911
912
        if ($return_only_path) {
913
            return $icon;
914
        }
915
916
        $img = self::img($icon, $alt_text, $additional_attributes);
917
        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...
918
            if ($show_text) {
919
                $img = "$img $alt_text";
920
            }
921
        }
922
923
        return $img;
924
    }
925
926
    /**
927
     * Returns the htmlcode for an image.
928
     *
929
     * @param string $image_path            the filename of the file (in the main/img/ folder
930
     * @param string $alt_text              the alt text (probably a language variable)
931
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
932
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
933
     *
934
     * @return string
935
     *
936
     * @author Julio Montoya 2010
937
     */
938
    public static function img(
939
        $image_path,
940
        $alt_text = '',
941
        $additional_attributes = null,
942
        $filterPath = true
943
    ) {
944
        if (empty($image_path)) {
945
            // For some reason, the call to img() happened without a proper
946
            // image. Log the error and return an empty string to avoid
947
            // breaking the HTML
948
            $trace = debug_backtrace();
949
            $caller = $trace[1];
950
            //error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
951
            return '';
952
        }
953
        // Sanitizing the parameter $image_path
954
        if ($filterPath) {
955
            $image_path = Security::filter_img_path($image_path);
956
        }
957
958
        // alt text = the image name if there is none provided (for XHTML compliance)
959
        if ($alt_text == '') {
960
            $alt_text = basename($image_path);
961
        }
962
963
        if (empty($additional_attributes)) {
964
            $additional_attributes = [];
965
        }
966
967
        $additional_attributes['src'] = $image_path;
968
969
        if (empty($additional_attributes['alt'])) {
970
            $additional_attributes['alt'] = $alt_text;
971
        }
972
        if (empty($additional_attributes['title'])) {
973
            $additional_attributes['title'] = $alt_text;
974
        }
975
976
        return self::tag('img', '', $additional_attributes);
977
    }
978
979
    /**
980
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
981
     *
982
     * @param string $tag                   the tag name
983
     * @param string $content               the tag's content
984
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
985
     *
986
     * @return string
987
     *
988
     * @author Julio Montoya 2010
989
     */
990
    public static function tag($tag, $content, $additional_attributes = [])
991
    {
992
        $attribute_list = '';
993
        // Managing the additional attributes
994
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
995
            $attribute_list = '';
996
            foreach ($additional_attributes as $key => &$value) {
997
                $attribute_list .= $key.'="'.$value.'" ';
998
            }
999
        }
1000
        //some tags don't have this </XXX>
1001
        if (in_array($tag, ['img', 'input', 'br'])) {
1002
            $return_value = '<'.$tag.' '.$attribute_list.' />';
1003
        } else {
1004
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
1005
        }
1006
1007
        return $return_value;
1008
    }
1009
1010
    /**
1011
     * Creates a URL anchor.
1012
     *
1013
     * @param string $name
1014
     * @param string $url
1015
     * @param array  $attributes
1016
     *
1017
     * @return string
1018
     */
1019
    public static function url($name, $url, $attributes = [])
1020
    {
1021
        if (!empty($url)) {
1022
            $url = preg_replace('#&amp;#', '&', $url);
1023
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
1024
            $attributes['href'] = $url;
1025
        }
1026
1027
        return self::tag('a', $name, $attributes);
1028
    }
1029
1030
    /**
1031
     * Creates a div tag.
1032
     *
1033
     * @param string $content
1034
     * @param array  $attributes
1035
     *
1036
     * @return string
1037
     */
1038
    public static function div($content, $attributes = [])
1039
    {
1040
        return self::tag('div', $content, $attributes);
1041
    }
1042
1043
    /**
1044
     * Creates a span tag.
1045
     */
1046
    public static function span($content, $attributes = [])
1047
    {
1048
        return self::tag('span', $content, $attributes);
1049
    }
1050
1051
    /**
1052
     * Displays an HTML input tag.
1053
     */
1054
    public static function input($type, $name, $value, $attributes = [])
1055
    {
1056
        if (isset($type)) {
1057
            $attributes['type'] = $type;
1058
        }
1059
        if (isset($name)) {
1060
            $attributes['name'] = $name;
1061
        }
1062
        if (isset($value)) {
1063
            $attributes['value'] = $value;
1064
        }
1065
1066
        return self::tag('input', '', $attributes);
1067
    }
1068
1069
    /**
1070
     * @param $name
1071
     * @param $value
1072
     * @param array $attributes
1073
     *
1074
     * @return string
1075
     */
1076
    public static function button($name, $value, $attributes = [])
1077
    {
1078
        if (!empty($name)) {
1079
            $attributes['name'] = $name;
1080
        }
1081
1082
        return self::tag('button', $value, $attributes);
1083
    }
1084
1085
    /**
1086
     * Displays an HTML select tag.
1087
     *
1088
     * @param string $name
1089
     * @param array  $values
1090
     * @param int    $default
1091
     * @param array  $extra_attributes
1092
     * @param bool   $show_blank_item
1093
     * @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...
1094
     *
1095
     * @return string
1096
     */
1097
    public static function select(
1098
        $name,
1099
        $values,
1100
        $default = -1,
1101
        $extra_attributes = [],
1102
        $show_blank_item = true,
1103
        $blank_item_text = ''
1104
    ) {
1105
        $html = '';
1106
        $extra = '';
1107
        $default_id = 'id="'.$name.'" ';
1108
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1109
        foreach ($extra_attributes as $key => $parameter) {
1110
            if ($key == 'id') {
1111
                $default_id = '';
1112
            }
1113
            $extra .= $key.'="'.$parameter.'" ';
1114
        }
1115
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1116
1117
        if ($show_blank_item) {
1118
            if (empty($blank_item_text)) {
1119
                $blank_item_text = get_lang('Select');
1120
            } else {
1121
                $blank_item_text = Security::remove_XSS($blank_item_text);
1122
            }
1123
            $html .= self::tag(
1124
                'option',
1125
                '-- '.$blank_item_text.' --',
1126
                ['value' => '-1']
1127
            );
1128
        }
1129
        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...
1130
            foreach ($values as $key => $value) {
1131
                if (is_array($value) && isset($value['name'])) {
1132
                    $value = $value['name'];
1133
                }
1134
                $html .= '<option value="'.$key.'"';
1135
1136
                if (is_array($default)) {
1137
                    foreach ($default as $item) {
1138
                        if ($item == $key) {
1139
                            $html .= ' selected="selected"';
1140
                            break;
1141
                        }
1142
                    }
1143
                } else {
1144
                    if ($default == $key) {
1145
                        $html .= ' selected="selected"';
1146
                    }
1147
                }
1148
1149
                $html .= '>'.$value.'</option>';
1150
            }
1151
        }
1152
        $html .= '</select>';
1153
1154
        return $html;
1155
    }
1156
1157
    /**
1158
     * Creates a tab menu
1159
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1160
     * in the $htmlHeadXtra variable before the display_header
1161
     * Add this script.
1162
     *
1163
     * @example
1164
     * <script>
1165
                </script>
1166
     * @param array  $headers       list of the tab titles
1167
     * @param array  $items
1168
     * @param string $id            id of the container of the tab in the example "tabs"
1169
     * @param array  $attributes    for the ul
1170
     * @param array  $ul_attributes
1171
     *
1172
     * @return string
1173
     */
1174
    public static function tabs(
1175
        $headers,
1176
        $items,
1177
        $id = 'tabs',
1178
        $attributes = [],
1179
        $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

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

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

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