Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/inc/lib/display.lib.php (1 issue)

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\ExtraField;
7
use ChamiloSession as Session;
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 = '',
63
        $help = null,
64
        $page_header = null
65
    ) {
66
        $origin = api_get_origin();
67
        $showHeader = true;
68
        if (isset($origin) && ($origin == 'learnpath' || $origin == 'mobileapp')) {
69
            $showHeader = false;
70
        }
71
72
        if (Session::read('origin') == 'mobileapp') {
73
            $showHeader = false;
74
        }
75
76
        /* USER_IN_ANON_SURVEY is defined in fillsurvey.php when survey is marked as anonymous survey */
77
        $userInAnonSurvey = defined('USER_IN_ANON_SURVEY') && USER_IN_ANON_SURVEY;
78
79
        self::$global_template = new Template($tool_name, $showHeader, $showHeader, false, $userInAnonSurvey);
80
        self::$global_template->assign('user_in_anon_survey', $userInAnonSurvey);
81
82
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
83
        if (empty($help)) {
84
            $currentURL = api_get_self();
85
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
86
            $toolList = self::toolList();
87
            if (!empty($matches)) {
88
                foreach ($matches as $match) {
89
                    if (in_array($match, $toolList)) {
90
                        $help = explode('_', $match);
91
                        $help = array_map('ucfirst', $help);
92
                        $help = implode('', $help);
93
                        break;
94
                    }
95
                }
96
            }
97
        }
98
99
        self::$global_template->setHelp($help);
100
101
        if (!empty(self::$preview_style)) {
102
            self::$global_template->preview_theme = self::$preview_style;
103
            self::$global_template->set_system_parameters();
104
            self::$global_template->setCssFiles();
105
            self::$global_template->set_js_files();
106
            self::$global_template->setCssCustomFiles();
107
        }
108
109
        if (!empty($page_header)) {
110
            self::$global_template->assign('header', $page_header);
111
        }
112
113
        echo self::$global_template->show_header_template();
114
    }
115
116
    /**
117
     * Displays the reduced page header (without banner).
118
     */
119
    public static function display_reduced_header()
120
    {
121
        global $show_learnpath, $tool_name;
122
        self::$global_template = new Template(
123
            $tool_name,
124
            false,
125
            false,
126
            $show_learnpath
127
        );
128
        echo self::$global_template->show_header_template();
129
    }
130
131
    /**
132
     * Display no header.
133
     */
134
    public static function display_no_header()
135
    {
136
        global $tool_name, $show_learnpath;
137
        $disable_js_and_css_files = true;
138
        self::$global_template = new Template(
139
            $tool_name,
140
            false,
141
            false,
142
            $show_learnpath
143
        );
144
    }
145
146
    /**
147
     * Displays the reduced page header (without banner).
148
     */
149
    public static function set_header()
150
    {
151
        global $show_learnpath, $tool_name;
152
        self::$global_template = new Template(
153
            $tool_name,
154
            false,
155
            false,
156
            $show_learnpath
157
        );
158
    }
159
160
    /**
161
     * Display the page footer.
162
     */
163
    public static function display_footer()
164
    {
165
        echo self::$global_template->show_footer_template();
166
    }
167
168
    /**
169
     * Display the page footer.
170
     */
171
    public static function display_reduced_footer()
172
    {
173
        echo '</body></html>';
174
    }
175
176
    /**
177
     * Displays the tool introduction of a tool.
178
     *
179
     * @author Patrick Cool <[email protected]>, Ghent University
180
     *
181
     * @param string $tool          these are the constants that are used for indicating the tools
182
     * @param array  $editor_config Optional configuration settings for the online editor.
183
     *                              return: $tool return a string array list with the "define" in main_api.lib
184
     *
185
     * @return string html code for adding an introduction
186
     */
187
    public static function display_introduction_section(
188
        $tool,
189
        $editor_config = null
190
    ) {
191
        echo self::return_introduction_section($tool, $editor_config);
192
    }
193
194
    /**
195
     * @param string $tool
196
     * @param array  $editor_config
197
     */
198
    public static function return_introduction_section(
199
        $tool,
200
        $editor_config = null
201
    ) {
202
        $moduleId = $tool;
203
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
204
            $introduction_section = null;
205
            require api_get_path(SYS_INC_PATH).'introductionSection.inc.php';
206
207
            return $introduction_section;
208
        }
209
    }
210
211
    /**
212
     * Displays a table.
213
     *
214
     * @param array  $header          Titles for the table header
215
     *                                each item in this array can contain 3 values
216
     *                                - 1st element: the column title
217
     *                                - 2nd element: true or false (column sortable?)
218
     *                                - 3th element: additional attributes for
219
     *                                th-tag (eg for column-width)
220
     *                                - 4the element: additional attributes for the td-tags
221
     * @param array  $content         2D-array with the tables content
222
     * @param array  $sorting_options Keys are:
223
     *                                'column' = The column to use as sort-key
224
     *                                'direction' = SORT_ASC or SORT_DESC
225
     * @param array  $paging_options  Keys are:
226
     *                                'per_page_default' = items per page when switching from
227
     *                                full-    list to per-page-view
228
     *                                'per_page' = number of items to show per page
229
     *                                'page_nr' = The page to display
230
     * @param array  $query_vars      Additional variables to add in the query-string
231
     * @param array  $form_actions
232
     * @param string $style           The style that the table will show. You can set 'table' or 'grid'
233
     * @param string $tableName
234
     * @param string $tableId
235
     *
236
     * @author [email protected]
237
     */
238
    public static function display_sortable_table(
239
        $header,
240
        $content,
241
        $sorting_options = [],
242
        $paging_options = [],
243
        $query_vars = null,
244
        $form_actions = [],
245
        $style = 'table',
246
        $tableName = 'tablename',
247
        $tableId = ''
248
    ) {
249
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
250
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
251
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId);
252
        if (is_array($query_vars)) {
253
            $table->set_additional_parameters($query_vars);
254
        }
255
        if ($style === 'table') {
256
            if (is_array($header) && count($header) > 0) {
257
                foreach ($header as $index => $header_item) {
258
                    $table->set_header(
259
                        $index,
260
                        isset($header_item[0]) ? $header_item[0] : null,
261
                        isset($header_item[1]) ? $header_item[1] : null,
262
                        isset($header_item[2]) ? $header_item[2] : null,
263
                        isset($header_item[3]) ? $header_item[3] : null
264
                    );
265
                }
266
            }
267
            $table->set_form_actions($form_actions);
268
            $table->display();
269
        } else {
270
            $table->display_grid();
271
        }
272
    }
273
274
    /**
275
     * Returns an HTML table with sortable column (through complete page refresh).
276
     *
277
     * @param array  $header
278
     * @param array  $content         Array of row arrays
279
     * @param array  $sorting_options
280
     * @param array  $paging_options
281
     * @param array  $query_vars
282
     * @param array  $form_actions
283
     * @param string $style
284
     *
285
     * @return string HTML string for array
286
     */
287
    public static function return_sortable_table(
288
        $header,
289
        $content,
290
        $sorting_options = [],
291
        $paging_options = [],
292
        $query_vars = null,
293
        $form_actions = [],
294
        $style = 'table'
295
    ) {
296
        ob_start();
297
        self::display_sortable_table(
298
            $header,
299
            $content,
300
            $sorting_options,
301
            $paging_options,
302
            $query_vars,
303
            $form_actions,
304
            $style
305
        );
306
        $content = ob_get_contents();
307
        ob_end_clean();
308
309
        return $content;
310
    }
311
312
    /**
313
     * Shows a nice grid.
314
     *
315
     * @param string grid name (important to create css)
316
     * @param array header content
317
     * @param array array with the information to show
318
     * @param array $paging_options Keys are:
319
     *                              'per_page_default' = items per page when switching from
320
     *                              full-    list to per-page-view
321
     *                              'per_page' = number of items to show per page
322
     *                              'page_nr' = The page to display
323
     *                              'hide_navigation' =  true to hide the navigation
324
     * @param array $query_vars     Additional variables to add in the query-string
325
     * @param array $form_actions   actions Additional variables to add in the query-string
326
     * @param mixed An array with bool values to know which columns show.
327
     * i.e: $visibility_options= array(true, false) we will only show the first column
328
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
329
     */
330
    public static function display_sortable_grid(
331
        $name,
332
        $header,
333
        $content,
334
        $paging_options = [],
335
        $query_vars = null,
336
        $form_actions = [],
337
        $visibility_options = true,
338
        $sort_data = true,
339
        $grid_class = []
340
    ) {
341
        echo self::return_sortable_grid(
342
            $name,
343
            $header,
344
            $content,
345
            $paging_options,
346
            $query_vars,
347
            $form_actions,
348
            $visibility_options,
349
            $sort_data,
350
            $grid_class
351
        );
352
    }
353
354
    /**
355
     * Gets a nice grid in html string.
356
     *
357
     * @param string grid name (important to create css)
358
     * @param array header content
359
     * @param array array with the information to show
360
     * @param array $paging_options Keys are:
361
     *                              'per_page_default' = items per page when switching from
362
     *                              full-    list to per-page-view
363
     *                              'per_page' = number of items to show per page
364
     *                              'page_nr' = The page to display
365
     *                              'hide_navigation' =  true to hide the navigation
366
     * @param array $query_vars     Additional variables to add in the query-string
367
     * @param mixed An array with bool values to know which columns show. i.e:
368
     *  $visibility_options= array(true, false) we will only show the first column
369
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
370
     * @param bool  true for sorting data or false otherwise
371
     * @param array grid classes
372
     *
373
     * @return string html grid
374
     */
375
    public static function return_sortable_grid(
376
        $name,
377
        $header,
378
        $content,
379
        $paging_options = [],
380
        $query_vars = null,
381
        $form_actions = [],
382
        $visibility_options = true,
383
        $sort_data = true,
384
        $grid_class = [],
385
        $elementCount = 0
386
    ) {
387
        $column = 0;
388
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
389
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
390
        $table->total_number_of_items = intval($elementCount);
391
        if (is_array($query_vars)) {
392
            $table->set_additional_parameters($query_vars);
393
        }
394
395
        return $table->display_simple_grid(
396
            $visibility_options,
397
            $paging_options['hide_navigation'],
398
            $default_items_per_page,
399
            $sort_data,
400
            $grid_class
401
        );
402
    }
403
404
    /**
405
     * Displays a table with a special configuration.
406
     *
407
     * @param array $header          Titles for the table header
408
     *                               each item in this array can contain 3 values
409
     *                               - 1st element: the column title
410
     *                               - 2nd element: true or false (column sortable?)
411
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
412
     *                               - 4the element: additional attributes for the td-tags
413
     * @param array $content         2D-array with the tables content
414
     * @param array $sorting_options Keys are:
415
     *                               'column' = The column to use as sort-key
416
     *                               'direction' = SORT_ASC or SORT_DESC
417
     * @param array $paging_options  Keys are:
418
     *                               'per_page_default' = items per page when switching from full list to per-page-view
419
     *                               'per_page' = number of items to show per page
420
     *                               'page_nr' = The page to display
421
     * @param array $query_vars      Additional variables to add in the query-string
422
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
423
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
424
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column
425
     * @param array $form_actions    Set optional forms actions
426
     *
427
     * @author Julio Montoya
428
     */
429
    public static function display_sortable_config_table(
430
        $table_name,
431
        $header,
432
        $content,
433
        $sorting_options = [],
434
        $paging_options = [],
435
        $query_vars = null,
436
        $column_show = [],
437
        $column_order = [],
438
        $form_actions = []
439
    ) {
440
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
441
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
442
443
        $table = new SortableTableFromArrayConfig(
444
            $content,
445
            $column,
446
            $default_items_per_page,
447
            $table_name,
448
            $column_show,
449
            $column_order
450
        );
451
452
        if (is_array($query_vars)) {
453
            $table->set_additional_parameters($query_vars);
454
        }
455
        // Show or hide the columns header
456
        if (is_array($column_show)) {
457
            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...
458
                if (!empty($column_show[$i])) {
459
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
460
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
461
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
462
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
463
                    $table->set_header($i, $val0, $val1, $val2, $val3);
464
                }
465
            }
466
        }
467
        $table->set_form_actions($form_actions);
468
        $table->display();
469
    }
470
471
    /**
472
     * @param string $message
473
     * @param string $type
474
     * @param bool   $filter
475
     */
476
    public static function return_message_and_translate(
477
        $message,
478
        $type = 'normal',
479
        $filter = true
480
    ) {
481
        $message = get_lang($message);
482
        echo self::return_message($message, $type, $filter);
483
    }
484
485
    /**
486
     * Returns a div html string with.
487
     *
488
     * @param string $message
489
     * @param string $type    Example: confirm, normal, warning, error
490
     * @param bool   $filter  Whether to XSS-filter or not
491
     *
492
     * @return string Message wrapped into an HTML div
493
     */
494
    public static function return_message(
495
        $message,
496
        $type = 'normal',
497
        $filter = true
498
    ) {
499
        if (empty($message)) {
500
            return '';
501
        }
502
503
        if ($filter) {
504
            $message = api_htmlentities(
505
                $message,
506
                ENT_QUOTES,
507
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
508
            );
509
        }
510
511
        $class = '';
512
        switch ($type) {
513
            case 'warning':
514
                $class .= 'alert alert-warning';
515
                break;
516
            case 'error':
517
                $class .= 'alert alert-danger';
518
                break;
519
            case 'confirmation':
520
            case 'confirm':
521
            case 'success':
522
                $class .= 'alert alert-success';
523
                break;
524
            case 'normal':
525
            default:
526
                $class .= 'alert alert-info';
527
        }
528
529
        return self::div($message, ['class' => $class]);
530
    }
531
532
    /**
533
     * Returns an encrypted mailto hyperlink.
534
     *
535
     * @param string  e-mail
536
     * @param string  clickable text
537
     * @param string  optional, class from stylesheet
538
     * @param bool $addExtraContent
539
     *
540
     * @return string encrypted mailto hyperlink
541
     */
542
    public static function encrypted_mailto_link(
543
        $email,
544
        $clickable_text = null,
545
        $style_class = '',
546
        $addExtraContent = false
547
    ) {
548
        if (is_null($clickable_text)) {
549
            $clickable_text = $email;
550
        }
551
552
        // "mailto:" already present?
553
        if (substr($email, 0, 7) !== 'mailto:') {
554
            $email = 'mailto:'.$email;
555
        }
556
557
        // Class (stylesheet) defined?
558
        if ($style_class !== '') {
559
            $style_class = ' class="'.$style_class.'"';
560
        }
561
562
        // Encrypt email
563
        $hmail = '';
564
        for ($i = 0; $i < strlen($email); $i++) {
565
            $hmail .= '&#'.ord($email[$i]).';';
566
        }
567
568
        $value = api_get_configuration_value('add_user_course_information_in_mailto');
569
570
        if ($value) {
571
            if (api_get_setting('allow_email_editor') === 'false') {
572
                $hmail .= '?';
573
            }
574
575
            if (!api_is_anonymous()) {
576
                $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName'));
577
            }
578
            if ($addExtraContent) {
579
                $content = '';
580
                if (!api_is_anonymous()) {
581
                    $userInfo = api_get_user_info();
582
                    $content .= get_lang('User').': '.$userInfo['complete_name']."\n";
583
584
                    $courseInfo = api_get_course_info();
585
                    if (!empty($courseInfo)) {
586
                        $content .= get_lang('Course').': ';
587
                        $content .= $courseInfo['name'];
588
                        $sessionInfo = api_get_session_info(api_get_session_id());
589
                        if (!empty($sessionInfo)) {
590
                            $content .= ' '.$sessionInfo['name'].' <br />';
591
                        }
592
                    }
593
                }
594
595
                if (!empty($content)) {
596
                    $hmail .= '&body='.rawurlencode($content);
597
                }
598
            }
599
        }
600
601
        $hclickable_text = '';
602
        // Encrypt clickable text if @ is present
603
        if (strpos($clickable_text, '@')) {
604
            for ($i = 0; $i < strlen($clickable_text); $i++) {
605
                $hclickable_text .= '&#'.ord($clickable_text[$i]).';';
606
            }
607
        } else {
608
            $hclickable_text = @htmlspecialchars(
609
                $clickable_text,
610
                ENT_QUOTES,
611
                api_get_system_encoding()
612
            );
613
        }
614
        // Return encrypted mailto hyperlink
615
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
616
    }
617
618
    /**
619
     * Returns an mailto icon hyperlink.
620
     *
621
     * @param string  e-mail
622
     * @param string  icon source file from the icon lib
623
     * @param int  icon size from icon lib
624
     * @param string  optional, class from stylesheet
625
     *
626
     * @return string encrypted mailto hyperlink
627
     */
628
    public static function icon_mailto_link(
629
        $email,
630
        $icon_file = "mail.png",
631
        $icon_size = 22,
632
        $style_class = ''
633
    ) {
634
        // "mailto:" already present?
635
        if (substr($email, 0, 7) != 'mailto:') {
636
            $email = 'mailto:'.$email;
637
        }
638
        // Class (stylesheet) defined?
639
        if ($style_class != '') {
640
            $style_class = ' class="'.$style_class.'"';
641
        }
642
        // Encrypt email
643
        $hmail = '';
644
        for ($i = 0; $i < strlen($email); $i++) {
645
            $hmail .= '&#'.ord($email[
646
            $i]).';';
647
        }
648
        // icon html code
649
        $icon_html_source = self::return_icon(
650
            $icon_file,
651
            $hmail,
652
            '',
653
            $icon_size
654
        );
655
        // Return encrypted mailto hyperlink
656
657
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
658
    }
659
660
    /**
661
     * Prints an <option>-list with all letters (A-Z).
662
     *
663
     * @todo This is English language specific implementation.
664
     * It should be adapted for the other languages.
665
     *
666
     * @return string
667
     */
668
    public static function get_alphabet_options($selectedLetter = '')
669
    {
670
        $result = '';
671
        for ($i = 65; $i <= 90; $i++) {
672
            $letter = chr($i);
673
            $result .= '<option value="'.$letter.'"';
674
            if ($selectedLetter == $letter) {
675
                $result .= ' selected="selected"';
676
            }
677
            $result .= '>'.$letter.'</option>';
678
        }
679
680
        return $result;
681
    }
682
683
    /**
684
     * Get the options withing a select box within the given values.
685
     *
686
     * @param int   Min value
687
     * @param int   Max value
688
     * @param int   Default value
689
     *
690
     * @return string HTML select options
691
     */
692
    public static function get_numeric_options($min, $max, $selected_num = 0)
693
    {
694
        $result = '';
695
        for ($i = $min; $i <= $max; $i++) {
696
            $result .= '<option value="'.$i.'"';
697
            if (is_int($selected_num)) {
698
                if ($selected_num == $i) {
699
                    $result .= ' selected="selected"';
700
                }
701
            }
702
            $result .= '>'.$i.'</option>';
703
        }
704
705
        return $result;
706
    }
707
708
    /**
709
     * This public function displays an icon.
710
     *
711
     * @param string   The filename of the file (in the main/img/ folder
712
     * @param string   The alt text (probably a language variable)
713
     * @param array    additional attributes (for instance height, width, onclick, ...)
714
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
715
     */
716
    public static function display_icon(
717
        $image,
718
        $alt_text = '',
719
        $additional_attributes = [],
720
        $size = null
721
    ) {
722
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
723
    }
724
725
    /**
726
     * Gets the path of an icon.
727
     *
728
     * @param string $icon
729
     * @param int    $size
730
     *
731
     * @return string
732
     */
733
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
734
    {
735
        return self::return_icon($icon, null, null, $size, null, true, false);
736
    }
737
738
    /**
739
     * This public function returns the HTML code for an icon.
740
     *
741
     * @param string $image                 The filename of the file (in the main/img/ folder
742
     * @param string $alt_text              The alt text (probably a language variable)
743
     * @param array  $additional_attributes Additional attributes (for instance height, width, onclick, ...)
744
     * @param int    $size                  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
745
     * @param bool   $show_text             Whether to show the text next (usually under) the icon
746
     * @param bool   $return_only_path      Whether we only want the path to the icon or the whole HTML tag
747
     * @param bool   $loadThemeIcon         Whether we want to allow an overloaded theme icon, if it exists, to replace the default icon
748
     *
749
     * @return string An HTML string of the right <img> tag
750
     *
751
     * @author Patrick Cool <[email protected]>, Ghent University 2006
752
     * @author Julio Montoya 2010 Function improved, adding image constants
753
     * @author Yannick Warnier 2011 Added size handler
754
     *
755
     * @version Feb 2011
756
     */
757
    public static function return_icon(
758
        $image,
759
        $alt_text = '',
760
        $additional_attributes = [],
761
        $size = ICON_SIZE_SMALL,
762
        $show_text = true,
763
        $return_only_path = false,
764
        $loadThemeIcon = true
765
    ) {
766
        $code_path = api_get_path(SYS_CODE_PATH);
767
        $w_code_path = api_get_path(WEB_CODE_PATH);
768
        // The following path is checked to see if the file exist. It's
769
        // important to use the public path (i.e. web/css/) rather than the
770
        // internal path (/app/Resource/public/css/) because the path used
771
        // in the end must be the public path
772
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
773
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
774
775
        // Avoid issues with illegal string offset for legacy calls to this
776
        // method with an empty string rather than null or an empty array
777
        if (empty($additional_attributes)) {
778
            $additional_attributes = [];
779
        }
780
781
        $image = trim($image);
782
783
        if (isset($size)) {
784
            $size = intval($size);
785
        } else {
786
            $size = ICON_SIZE_SMALL;
787
        }
788
789
        $size_extra = $size.'/';
790
        $icon = $w_code_path.'img/'.$image;
791
        $theme = 'themes/chamilo/icons/';
792
793
        if ($loadThemeIcon) {
794
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
795
            if (is_file($alternateCssPath.$theme.$image)) {
796
                $icon = $alternateWebCssPath.$theme.$image;
797
            }
798
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
799
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
800
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
801
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
802
                //Checking the main/img/icons/XXX/ folder
803
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
804
            }
805
        } else {
806
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
807
                // Checking the main/img/icons/XXX/ folder
808
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
809
            }
810
        }
811
812
        // Special code to enable SVG - refs #7359 - Needs more work
813
        // The code below does something else to "test out" SVG: for each icon,
814
        // it checks if there is an SVG version. If so, it uses it.
815
        // When moving this to production, the return_icon() calls should
816
        // ask for the SVG version directly
817
        $svgIcons = api_get_setting('icons_mode_svg');
818
        if ($svgIcons === 'true' && $return_only_path == false) {
819
            $svgImage = substr($image, 0, -3).'svg';
820
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
821
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
822
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
823
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
824
            }
825
826
            if (empty($additional_attributes['height'])) {
827
                $additional_attributes['height'] = $size;
828
            }
829
            if (empty($additional_attributes['width'])) {
830
                $additional_attributes['width'] = $size;
831
            }
832
        }
833
834
        $icon = api_get_cdn_path($icon);
835
836
        if ($return_only_path) {
837
            return $icon;
838
        }
839
840
        $img = self::img($icon, $alt_text, $additional_attributes);
841
        if (SHOW_TEXT_NEAR_ICONS == true && !empty($alt_text)) {
842
            if ($show_text) {
843
                $img = "$img $alt_text";
844
            }
845
        }
846
847
        return $img;
848
    }
849
850
    /**
851
     * Returns the HTML code for an image.
852
     *
853
     * @param string $image_path            the filename of the file (in the main/img/ folder
854
     * @param string $alt_text              the alt text (probably a language variable)
855
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
856
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
857
     *
858
     * @return string
859
     *
860
     * @author Julio Montoya 2010
861
     */
862
    public static function img(
863
        $image_path,
864
        $alt_text = '',
865
        $additional_attributes = null,
866
        $filterPath = true
867
    ) {
868
        if (empty($image_path)) {
869
            // For some reason, the call to img() happened without a proper
870
            // image. Log the error and return an empty string to avoid
871
            // breaking the HTML
872
            $trace = debug_backtrace();
873
            $caller = $trace[1];
874
            error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
875
876
            return '';
877
        }
878
        // Sanitizing the parameter $image_path
879
        if ($filterPath) {
880
            $image_path = Security::filter_img_path($image_path);
881
        }
882
883
        // alt text = the image name if there is none provided (for XHTML compliance)
884
        if ($alt_text == '') {
885
            $alt_text = basename($image_path);
886
        }
887
888
        if (empty($additional_attributes)) {
889
            $additional_attributes = [];
890
        }
891
892
        $additional_attributes['src'] = $image_path;
893
894
        if (empty($additional_attributes['alt'])) {
895
            $additional_attributes['alt'] = $alt_text;
896
        }
897
        if (empty($additional_attributes['title'])) {
898
            $additional_attributes['title'] = $alt_text;
899
        }
900
901
        return self::tag('img', '', $additional_attributes);
902
    }
903
904
    /**
905
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
906
     *
907
     * @param string $tag                   the tag name
908
     * @param string $content               the tag's content
909
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
910
     *
911
     * @return string
912
     *
913
     * @author Julio Montoya 2010
914
     */
915
    public static function tag($tag, $content, $additional_attributes = [])
916
    {
917
        $attribute_list = '';
918
        // Managing the additional attributes
919
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
920
            $attribute_list = '';
921
            foreach ($additional_attributes as $key => &$value) {
922
                $attribute_list .= $key.'="'.$value.'" ';
923
            }
924
        }
925
        //some tags don't have this </XXX>
926
        if (in_array($tag, ['img', 'input', 'br'])) {
927
            $return_value = '<'.$tag.' '.$attribute_list.' />';
928
        } else {
929
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
930
        }
931
932
        return $return_value;
933
    }
934
935
    /**
936
     * Creates a URL anchor.
937
     *
938
     * @param string $name
939
     * @param string $url
940
     * @param array  $attributes
941
     *
942
     * @return string
943
     */
944
    public static function url($name, $url, $attributes = [])
945
    {
946
        if (!empty($url)) {
947
            $url = preg_replace('#&amp;#', '&', $url);
948
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
949
            $attributes['href'] = $url;
950
        }
951
952
        return self::tag('a', $name, $attributes);
953
    }
954
955
    /**
956
     * Creates a div tag.
957
     *
958
     * @param string $content
959
     * @param array  $attributes
960
     *
961
     * @return string
962
     */
963
    public static function div($content, $attributes = [])
964
    {
965
        return self::tag('div', $content, $attributes);
966
    }
967
968
    /**
969
     * Creates a span tag.
970
     */
971
    public static function span($content, $attributes = [])
972
    {
973
        return self::tag('span', $content, $attributes);
974
    }
975
976
    /**
977
     * Displays an HTML input tag.
978
     */
979
    public static function input($type, $name, $value, $attributes = [])
980
    {
981
        if (isset($type)) {
982
            $attributes['type'] = $type;
983
        }
984
        if (isset($name)) {
985
            $attributes['name'] = $name;
986
        }
987
        if (isset($value)) {
988
            $attributes['value'] = $value;
989
        }
990
991
        return self::tag('input', '', $attributes);
992
    }
993
994
    /**
995
     * @param $name
996
     * @param $value
997
     * @param array $attributes
998
     *
999
     * @return string
1000
     */
1001
    public static function button($name, $value, $attributes = [])
1002
    {
1003
        if (!empty($name)) {
1004
            $attributes['name'] = $name;
1005
        }
1006
1007
        return self::tag('button', $value, $attributes);
1008
    }
1009
1010
    /**
1011
     * Displays an HTML select tag.
1012
     *
1013
     * @param string $name
1014
     * @param array  $values
1015
     * @param int    $default
1016
     * @param array  $extra_attributes
1017
     * @param bool   $show_blank_item
1018
     * @param null   $blank_item_text
1019
     *
1020
     * @return string
1021
     */
1022
    public static function select(
1023
        $name,
1024
        $values,
1025
        $default = -1,
1026
        $extra_attributes = [],
1027
        $show_blank_item = true,
1028
        $blank_item_text = ''
1029
    ) {
1030
        $html = '';
1031
        $extra = '';
1032
        $default_id = 'id="'.$name.'" ';
1033
        $extra_attributes = array_merge(['class' => 'form-control'], $extra_attributes);
1034
        foreach ($extra_attributes as $key => $parameter) {
1035
            if ($key == 'id') {
1036
                $default_id = '';
1037
            }
1038
            $extra .= $key.'="'.$parameter.'" ';
1039
        }
1040
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1041
1042
        if ($show_blank_item) {
1043
            if (empty($blank_item_text)) {
1044
                $blank_item_text = get_lang('Select');
1045
            } else {
1046
                $blank_item_text = Security::remove_XSS($blank_item_text);
1047
            }
1048
            $html .= self::tag(
1049
                'option',
1050
                '-- '.$blank_item_text.' --',
1051
                ['value' => '-1']
1052
            );
1053
        }
1054
        if ($values) {
1055
            foreach ($values as $key => $value) {
1056
                if (is_array($value) && isset($value['name'])) {
1057
                    $value = $value['name'];
1058
                }
1059
                $html .= '<option value="'.$key.'"';
1060
1061
                if (is_array($default)) {
1062
                    foreach ($default as $item) {
1063
                        if ($item == $key) {
1064
                            $html .= ' selected="selected"';
1065
                            break;
1066
                        }
1067
                    }
1068
                } else {
1069
                    if ($default == $key) {
1070
                        $html .= ' selected="selected"';
1071
                    }
1072
                }
1073
1074
                $html .= '>'.$value.'</option>';
1075
            }
1076
        }
1077
        $html .= '</select>';
1078
1079
        return $html;
1080
    }
1081
1082
    /**
1083
     * Creates a tab menu
1084
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1085
     * in the $htmlHeadXtra variable before the display_header
1086
     * Add this script.
1087
     *
1088
     * @example
1089
     * <script>
1090
                </script>
1091
     * @param array  $headers       list of the tab titles
1092
     * @param array  $items
1093
     * @param string $id            id of the container of the tab in the example "tabs"
1094
     * @param array  $attributes    for the ul
1095
     * @param array  $ul_attributes
1096
     * @param int    $selected
1097
     *
1098
     * @return string
1099
     */
1100
    public static function tabs(
1101
        $headers,
1102
        $items,
1103
        $id = 'tabs',
1104
        $attributes = [],
1105
        $ul_attributes = [],
1106
        $selected = ''
1107
    ) {
1108
        if (empty($headers) || count($headers) == 0) {
1109
            return '';
1110
        }
1111
1112
        $lis = '';
1113
        $i = 1;
1114
        foreach ($headers as $item) {
1115
            $active = '';
1116
            if ($i == 1) {
1117
                $active = ' active';
1118
            }
1119
1120
            if (!empty($selected)) {
1121
                $active = '';
1122
                if ($selected == $i) {
1123
                    $active = ' active';
1124
                }
1125
            }
1126
1127
            $item = self::tag(
1128
                'a',
1129
                $item,
1130
                [
1131
                    'href' => '#'.$id.'-'.$i,
1132
                    'role' => 'tab',
1133
                    'data-toggle' => 'tab',
1134
                    'id' => $id.$i,
1135
                ]
1136
            );
1137
            $ul_attributes['role'] = 'presentation';
1138
            $ul_attributes['class'] = $active;
1139
            $lis .= self::tag('li', $item, $ul_attributes);
1140
            $i++;
1141
        }
1142
1143
        $ul = self::tag(
1144
            'ul',
1145
            $lis,
1146
            [
1147
                'class' => 'nav nav-tabs tabs-margin',
1148
                'role' => 'tablist',
1149
                'id' => 'ul_'.$id,
1150
            ]
1151
        );
1152
1153
        $i = 1;
1154
        $divs = '';
1155
        foreach ($items as $content) {
1156
            $active = '';
1157
            if ($i == 1) {
1158
                $active = ' active';
1159
            }
1160
1161
            if (!empty($selected)) {
1162
                $active = '';
1163
                if ($selected == $i) {
1164
                    $active = ' active';
1165
                }
1166
            }
1167
1168
            $divs .= self::tag(
1169
                'div',
1170
                $content,
1171
                ['id' => $id.'-'.$i, 'class' => 'tab-pane '.$active, 'role' => 'tabpanel']
1172
            );
1173
            $i++;
1174
        }
1175
1176
        $attributes['id'] = $id;
1177
        $attributes['role'] = 'tabpanel';
1178
        $attributes['class'] = 'tab-wrapper';
1179
1180
        $main_div = self::tag(
1181
            'div',
1182
            $ul.self::tag('div', $divs, ['class' => 'tab-content']),
1183
            $attributes
1184
        );
1185
1186
        return $main_div;
1187
    }
1188
1189
    /**
1190
     * @param $headers
1191
     * @param null $selected
1192
     *
1193
     * @return string
1194
     */
1195
    public static function tabsOnlyLink($headers, $selected = null)
1196
    {
1197
        $id = uniqid();
1198
        $i = 1;
1199
        $lis = null;
1200
        foreach ($headers as $item) {
1201
            $class = null;
1202
            if ($i == $selected) {
1203
                $class = 'active';
1204
            }
1205
            $item = self::tag(
1206
                'a',
1207
                $item['content'],
1208
                ['id' => $id.'-'.$i, 'href' => $item['url']]
1209
            );
1210
            $lis .= self::tag('li', $item, ['class' => $class]);
1211
            $i++;
1212
        }
1213
1214
        return self::tag(
1215
            'ul',
1216
            $lis,
1217
            ['class' => 'nav nav-tabs tabs-margin']
1218
        );
1219
    }
1220
1221
    /**
1222
     * In order to display a grid using jqgrid you have to:.
1223
     *
1224
     * @example
1225
     * After your Display::display_header function you have to add the nex javascript code:
1226
     * <script>
1227
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1228
     *   // for more information of this function check the grid_js() function
1229
     * </script>
1230
     * //Then you have to call the grid_html
1231
     * echo Display::grid_html('my_grid_name');
1232
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1233
     *
1234
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1235
     *
1236
     * @return string html
1237
     */
1238
    public static function grid_html($div_id)
1239
    {
1240
        $table = self::tag('table', '', ['id' => $div_id]);
1241
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1242
1243
        return $table;
1244
    }
1245
1246
    /**
1247
     * @param string $label
1248
     * @param string $form_item
1249
     *
1250
     * @return string
1251
     */
1252
    public static function form_row($label, $form_item)
1253
    {
1254
        $label = self::tag('label', $label, ['class' => 'col-sm-2 control-label']);
1255
        $form_item = self::div($form_item, ['class' => 'col-sm-10']);
1256
1257
        return self::div($label.$form_item, ['class' => 'form-group']);
1258
    }
1259
1260
    /**
1261
     * This is a wrapper to use the jqgrid in Chamilo.
1262
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1263
     * This function need to be in the ready jquery function
1264
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1265
     * In order to work this function needs the Display::grid_html function with the same div id.
1266
     *
1267
     * @param string $div_id       div id
1268
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1269
     * @param array  $column_names Visible columns (you should use get_lang).
1270
     *                             An array in which we place the names of the columns.
1271
     *                             This is the text that appears in the head of the grid (Header layer).
1272
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1273
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1274
     *                             This is the most important part of the grid.
1275
     *                             For a full description of all valid values see colModel API. See the url above.
1276
     * @param array  $extra_params extra parameters
1277
     * @param array  $data         data that will be loaded
1278
     * @param string $formatter    A string that will be appended to the JSON returned
1279
     * @param bool   $fixed_width  not implemented yet
1280
     *
1281
     * @return string the js code
1282
     */
1283
    public static function grid_js(
1284
        $div_id,
1285
        $url,
1286
        $column_names,
1287
        $column_model,
1288
        $extra_params,
1289
        $data = [],
1290
        $formatter = '',
1291
        $fixed_width = false
1292
    ) {
1293
        $obj = new stdClass();
1294
        $obj->first = 'first';
1295
1296
        if (!empty($url)) {
1297
            $obj->url = $url;
1298
        }
1299
1300
        //This line should only be used/modified in case of having characters
1301
        // encoding problems - see #6159
1302
        //$column_names = array_map("utf8_encode", $column_names);
1303
        $obj->colNames = $column_names;
1304
        $obj->colModel = $column_model;
1305
        $obj->pager = '#'.$div_id.'_pager';
1306
        $obj->datatype = 'json';
1307
        $obj->viewrecords = 'true';
1308
        $all_value = 10000000;
1309
1310
        // Sets how many records we want to view in the grid
1311
        $obj->rowNum = 20;
1312
1313
        // Default row quantity
1314
        if (!isset($extra_params['rowList'])) {
1315
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1316
            $rowList = api_get_configuration_value('table_row_list');
1317
            if (!empty($rowList) && isset($rowList['options'])) {
1318
                $rowList = $rowList['options'];
1319
                $rowList[] = $all_value;
1320
                $extra_params['rowList'] = $rowList;
1321
            }
1322
        }
1323
1324
        $defaultRow = api_get_configuration_value('table_default_row');
1325
        if (!empty($defaultRow)) {
1326
            $obj->rowNum = (int) $defaultRow;
1327
        }
1328
1329
        $json = '';
1330
        if (!empty($extra_params['datatype'])) {
1331
            $obj->datatype = $extra_params['datatype'];
1332
        }
1333
1334
        // Row even odd style.
1335
        $obj->altRows = true;
1336
        if (!empty($extra_params['altRows'])) {
1337
            $obj->altRows = $extra_params['altRows'];
1338
        }
1339
1340
        if (!empty($extra_params['sortname'])) {
1341
            $obj->sortname = $extra_params['sortname'];
1342
        }
1343
1344
        if (!empty($extra_params['sortorder'])) {
1345
            $obj->sortorder = $extra_params['sortorder'];
1346
        }
1347
1348
        if (!empty($extra_params['rowList'])) {
1349
            $obj->rowList = $extra_params['rowList'];
1350
        }
1351
1352
        if (!empty($extra_params['rowNum'])) {
1353
            $obj->rowNum = $extra_params['rowNum'];
1354
        } else {
1355
            // Try to load max rows from Session
1356
            $urlInfo = parse_url($url);
1357
            if (isset($urlInfo['query'])) {
1358
                parse_str($urlInfo['query'], $query);
1359
                if (isset($query['a'])) {
1360
                    $action = $query['a'];
1361
                    // This value is set in model.ajax.php
1362
                    $savedRows = Session::read('max_rows_'.$action);
1363
                    if (!empty($savedRows)) {
1364
                        $obj->rowNum = $savedRows;
1365
                    }
1366
                }
1367
            }
1368
        }
1369
1370
        if (!empty($extra_params['viewrecords'])) {
1371
            $obj->viewrecords = $extra_params['viewrecords'];
1372
        }
1373
1374
        $beforeSelectRow = null;
1375
        if (isset($extra_params['beforeSelectRow'])) {
1376
            $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', ';
1377
            unset($extra_params['beforeSelectRow']);
1378
        }
1379
1380
        $beforeProcessing = '';
1381
        if (isset($extra_params['beforeProcessing'])) {
1382
            $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },';
1383
            unset($extra_params['beforeProcessing']);
1384
        }
1385
1386
        $beforeRequest = '';
1387
        if (isset($extra_params['beforeRequest'])) {
1388
            $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },';
1389
            unset($extra_params['beforeRequest']);
1390
        }
1391
1392
        $gridComplete = '';
1393
        if (isset($extra_params['gridComplete'])) {
1394
            $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },';
1395
            unset($extra_params['gridComplete']);
1396
        }
1397
1398
        // Adding extra params
1399
        if (!empty($extra_params)) {
1400
            foreach ($extra_params as $key => $element) {
1401
                // the groupHeaders key gets a special treatment
1402
                if ($key != 'groupHeaders') {
1403
                    $obj->$key = $element;
1404
                }
1405
            }
1406
        }
1407
1408
        // Adding static data.
1409
        if (!empty($data)) {
1410
            $data_var = $div_id.'_data';
1411
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1412
            $obj->data = $data_var;
1413
            $obj->datatype = 'local';
1414
            $json .= "\n";
1415
        }
1416
1417
        $obj->end = 'end';
1418
1419
        $json_encode = json_encode($obj);
1420
1421
        if (!empty($data)) {
1422
            //Converts the "data":"js_variable" to "data":js_variable,
1423
            // otherwise it will not work
1424
            $json_encode = str_replace('"data":"'.$data_var.'"', '"data":'.$data_var.'', $json_encode);
1425
        }
1426
1427
        // Fixing true/false js values that doesn't need the ""
1428
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1429
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1430
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1431
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1432
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1433
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1434
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1435
1436
        if (api_get_configuration_value('allow_compilatio_tool') &&
1437
            (strpos($_SERVER['REQUEST_URI'], 'work/work.php') !== false ||
1438
             strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php') != false
1439
            )
1440
        ) {
1441
            $json_encode = str_replace('"function () { compilatioInit() }"',
1442
                'function () { compilatioInit() }',
1443
                $json_encode
1444
            );
1445
        }
1446
        // Creating the jqgrid element.
1447
        $json .= '$("#'.$div_id.'").jqGrid({';
1448
        //$json .= $beforeSelectRow;
1449
        $json .= $gridComplete;
1450
        $json .= $beforeProcessing;
1451
        $json .= $beforeRequest;
1452
        $json .= $json_encode;
1453
        $json .= '});';
1454
1455
        // Grouping headers option
1456
        if (isset($extra_params['groupHeaders'])) {
1457
            $groups = '';
1458
            foreach ($extra_params['groupHeaders'] as $group) {
1459
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1460
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1461
            }
1462
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1463
                "useColSpanStyle" : false,
1464
                "groupHeaders"    : [
1465
                    '.$groups.'
1466
                ]
1467
            });';
1468
        }
1469
1470
        $all_text = addslashes(get_lang('All'));
1471
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1472
        $json .= "\n";
1473
        // Adding edit/delete icons.
1474
        $json .= $formatter;
1475
1476
        return $json;
1477
    }
1478
1479
    /**
1480
     * @param array $headers
1481
     * @param array $rows
1482
     * @param array $attributes
1483
     *
1484
     * @return string
1485
     */
1486
    public static function table($headers, $rows, $attributes = [])
1487
    {
1488
        if (empty($attributes)) {
1489
            $attributes['class'] = 'table table-hover table-striped data_table';
1490
        }
1491
        $table = new HTML_Table($attributes);
1492
        $row = 0;
1493
        $column = 0;
1494
1495
        // Course headers
1496
        if (!empty($headers)) {
1497
            foreach ($headers as $item) {
1498
                $table->setHeaderContents($row, $column, $item);
1499
                $column++;
1500
            }
1501
            $row = 1;
1502
            $column = 0;
1503
        }
1504
1505
        if (!empty($rows)) {
1506
            foreach ($rows as $content) {
1507
                $table->setCellContents($row, $column, $content);
1508
                $row++;
1509
            }
1510
        }
1511
1512
        return $table->toHtml();
1513
    }
1514
1515
    /**
1516
     * Returns the "what's new" icon notifications.
1517
     *
1518
     * The general logic of this function is to track the last time the user
1519
     * entered the course and compare to what has changed inside this course
1520
     * since then, based on the item_property table inside this course. Note that,
1521
     * if the user never entered the course before, he will not see notification
1522
     * icons. This function takes session ID into account (if any) and only shows
1523
     * the corresponding notifications.
1524
     *
1525
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1526
     * @param bool  $loadAjax
1527
     *
1528
     * @return string The HTML link to be shown next to the course
1529
     */
1530
    public static function show_notification($courseInfo, $loadAjax = true)
1531
    {
1532
        if (empty($courseInfo)) {
1533
            return '';
1534
        }
1535
1536
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1537
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1538
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1539
        $course_code = Database::escape_string($courseInfo['code']);
1540
1541
        $user_id = api_get_user_id();
1542
        $course_id = (int) $courseInfo['real_id'];
1543
        $sessionId = (int) $courseInfo['id_session'];
1544
        $status = (int) $courseInfo['status'];
1545
1546
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1547
1548
        if ($loadNotificationsByAjax) {
1549
            if ($loadAjax) {
1550
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1551
                Session::write($id, true);
1552
1553
                return '<span id ="'.$id.'" class="course_notification"></span>';
1554
            }
1555
        }
1556
1557
        // Get the user's last access dates to all tools of this course
1558
        $sql = "SELECT *
1559
                FROM $t_track_e_access
1560
                WHERE
1561
                    c_id = $course_id AND
1562
                    access_user_id = '$user_id' AND
1563
                    access_session_id ='".$sessionId."'
1564
                ORDER BY access_date DESC
1565
                LIMIT 1
1566
                ";
1567
        $result = Database::query($sql);
1568
1569
        // latest date by default is the creation date
1570
        $latestDate = $courseInfo['creation_date'];
1571
        if (Database::num_rows($result)) {
1572
            $row = Database::fetch_array($result, 'ASSOC');
1573
            $latestDate = $row['access_date'];
1574
        }
1575
1576
        $sessionCondition = api_get_session_condition(
1577
            $sessionId,
1578
            true,
1579
            false,
1580
            'session_id'
1581
        );
1582
1583
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1584
        // Get current tools in course
1585
        $sql = "SELECT name, link, image
1586
                FROM $course_tool_table
1587
                WHERE
1588
                    c_id = $course_id AND
1589
                    visibility = '1' AND
1590
                    name NOT IN ('".implode("','", $hideTools)."')
1591
                ";
1592
        $result = Database::query($sql);
1593
        $tools = Database::store_result($result);
1594
1595
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1596
        $group_ids[] = 0; //add group 'everyone'
1597
        $notifications = [];
1598
        if ($tools) {
1599
            foreach ($tools as $tool) {
1600
                $toolName = $tool['name'];
1601
                $toolName = Database::escape_string($toolName);
1602
                // Fix to get student publications
1603
                $toolCondition = " tool = '$toolName' AND ";
1604
                if ($toolName == 'student_publication' || $toolName == 'work') {
1605
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1606
                }
1607
1608
                $toolName = addslashes($toolName);
1609
1610
                $sql = "SELECT * FROM $tool_edit_table
1611
                        WHERE
1612
                            c_id = $course_id AND
1613
                            $toolCondition
1614
                            lastedit_type NOT LIKE '%Deleted%' AND
1615
                            lastedit_type NOT LIKE '%deleted%' AND
1616
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1617
                            lastedit_date > '$latestDate' AND
1618
                            lastedit_user_id != $user_id $sessionCondition AND
1619
                            visibility != 2 AND
1620
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1621
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1622
                        ORDER BY lastedit_date DESC
1623
                        LIMIT 1";
1624
                $result = Database::query($sql);
1625
1626
                $latestChange = Database::fetch_array($result, 'ASSOC');
1627
1628
                if ($latestChange) {
1629
                    $latestChange['link'] = $tool['link'];
1630
                    $latestChange['image'] = $tool['image'];
1631
                    $latestChange['tool'] = $tool['name'];
1632
                    $notifications[$toolName] = $latestChange;
1633
                }
1634
            }
1635
        }
1636
1637
        // Show all tool icons where there is something new.
1638
        $return = '';
1639
        foreach ($notifications as $notification) {
1640
            $toolName = $notification['tool'];
1641
            if (!(
1642
                    $notification['visibility'] == '1' ||
1643
                    ($status == '1' && $notification['visibility'] == '0') ||
1644
                    !isset($notification['visibility'])
1645
                )
1646
            ) {
1647
                continue;
1648
            }
1649
1650
            if ($toolName == TOOL_SURVEY) {
1651
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1652
                if (!empty($survey_info)) {
1653
                    $invited_users = SurveyUtil::get_invited_users(
1654
                        $survey_info['code'],
1655
                        $course_code
1656
                    );
1657
                    if (!in_array($user_id, $invited_users['course_users'])) {
1658
                        continue;
1659
                    }
1660
                }
1661
            }
1662
1663
            if ($notification['tool'] == TOOL_LEARNPATH) {
1664
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $courseInfo)) {
1665
                    continue;
1666
                }
1667
            }
1668
1669
            if ($notification['tool'] == TOOL_DROPBOX) {
1670
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1671
            }
1672
1673
            if ($notification['tool'] == 'work' &&
1674
                $notification['lastedit_type'] == 'DirectoryCreated'
1675
            ) {
1676
                $notification['lastedit_type'] = 'WorkAdded';
1677
            }
1678
1679
            $lastDate = api_get_local_time($notification['lastedit_date']);
1680
            $type = $notification['lastedit_type'];
1681
            if ($type == 'CalendareventVisible') {
1682
                $type = 'Visible';
1683
            }
1684
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1685
1686
            if (strpos($notification['link'], '?') === false) {
1687
                $notification['link'] = $notification['link'].'?notification=1';
1688
            } else {
1689
                $notification['link'] = $notification['link'].'&notification=1';
1690
            }
1691
1692
            $image = substr($notification['image'], 0, -4).'.png';
1693
1694
            $return .= self::url(
1695
                self::return_icon($image, $label),
1696
                api_get_path(WEB_CODE_PATH).
1697
                $notification['link'].'&cidReq='.$course_code.
1698
                '&ref='.$notification['ref'].
1699
                '&gidReq='.$notification['to_group_id'].
1700
                '&id_session='.$sessionId
1701
            ).PHP_EOL;
1702
        }
1703
1704
        return $return;
1705
    }
1706
1707
    /**
1708
     * Get the session box details as an array.
1709
     *
1710
     * @param int       Session ID
1711
     *
1712
     * @return array Empty array or session array
1713
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1714
     */
1715
    public static function getSessionTitleBox($session_id)
1716
    {
1717
        global $nosession;
1718
1719
        if (!$nosession) {
1720
            global $now, $date_start, $date_end;
1721
        }
1722
        $output = [];
1723
        if (!$nosession) {
1724
            $session_info = api_get_session_info($session_id);
1725
            $coachInfo = [];
1726
            if (!empty($session_info['id_coach'])) {
1727
                $coachInfo = api_get_user_info($session_info['id_coach']);
1728
            }
1729
1730
            $session = [];
1731
            $session['category_id'] = $session_info['session_category_id'];
1732
            $session['title'] = $session_info['name'];
1733
            $session['coach_id'] = $session['id_coach'] = $session_info['id_coach'];
1734
            $session['dates'] = '';
1735
            $session['coach'] = '';
1736
            if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1737
                $session['coach'] = get_lang('GeneralCoach').': '.$coachInfo['complete_name'];
1738
            }
1739
1740
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1741
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1742
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1743
            ) {
1744
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1745
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1746
                    $session['duration'] = $daysLeft >= 0
1747
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1748
                        : get_lang('YourSessionTimeHasExpired');
1749
                }
1750
                $active = true;
1751
            } else {
1752
                $dates = SessionManager::parseSessionDates($session_info, true);
1753
                $session['dates'] = $dates['access'];
1754
                if (api_get_setting('show_session_coach') === 'true' && isset($coachInfo['complete_name'])) {
1755
                    $session['coach'] = $coachInfo['complete_name'];
1756
                }
1757
                $active = $date_start <= $now && $date_end >= $now;
1758
            }
1759
            $session['active'] = $active;
1760
            $session['session_category_id'] = $session_info['session_category_id'];
1761
            $session['visibility'] = $session_info['visibility'];
1762
            $session['num_users'] = $session_info['nbr_users'];
1763
            $session['num_courses'] = $session_info['nbr_courses'];
1764
            $session['description'] = $session_info['description'];
1765
            $session['show_description'] = $session_info['show_description'];
1766
1767
            $entityManager = Database::getManager();
1768
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1769
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(
1770
                ExtraField::SESSION_FIELD_TYPE,
1771
                $session_id
1772
            );
1773
1774
            $session['extra_fields'] = [];
1775
            foreach ($extraFieldValues as $value) {
1776
                $session['extra_fields'][] = [
1777
                    'field' => [
1778
                        'variable' => $value->getField()->getVariable(),
1779
                        'display_text' => $value->getField()->getDisplayText(),
1780
                    ],
1781
                    'value' => $value->getValue(),
1782
                ];
1783
            }
1784
1785
            $output = $session;
1786
        }
1787
1788
        return $output;
1789
    }
1790
1791
    /**
1792
     * Return the five star HTML.
1793
     *
1794
     * @param string $id              of the rating ul element
1795
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1796
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1797
     * @param bool   $add_div_wrapper add a div wrapper
1798
     *
1799
     * @return string
1800
     */
1801
    public static function return_rating_system(
1802
        $id,
1803
        $url,
1804
        $point_info = [],
1805
        $add_div_wrapper = true
1806
    ) {
1807
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1808
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1809
1810
        if (!empty($percentage)) {
1811
            $percentage = $percentage * 125 / 100;
1812
        }
1813
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1814
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1815
1816
        $html = '<ul id="'.$id.'" class="star-rating">
1817
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1818
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1819
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1820
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1821
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1822
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1823
                </ul>';
1824
1825
        $labels = [];
1826
1827
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1828
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1829
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1830
1831
        if (!$add_div_wrapper && api_is_anonymous()) {
1832
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1833
        }
1834
1835
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1836
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1837
1838
        if ($add_div_wrapper) {
1839
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1840
        }
1841
1842
        return $html;
1843
    }
1844
1845
    /**
1846
     * @param string $title
1847
     * @param string $second_title
1848
     * @param string $size
1849
     * @param bool   $filter
1850
     *
1851
     * @return string
1852
     */
1853
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1854
    {
1855
        if ($filter) {
1856
            $title = Security::remove_XSS($title);
1857
        }
1858
1859
        if (!empty($second_title)) {
1860
            if ($filter) {
1861
                $second_title = Security::remove_XSS($second_title);
1862
            }
1863
            $title .= "<small> $second_title</small>";
1864
        }
1865
1866
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1867
    }
1868
1869
    public static function page_header_and_translate($title, $second_title = null)
1870
    {
1871
        $title = get_lang($title);
1872
1873
        return self::page_header($title, $second_title);
1874
    }
1875
1876
    public static function page_subheader_and_translate($title, $second_title = null)
1877
    {
1878
        $title = get_lang($title);
1879
1880
        return self::page_subheader($title, $second_title);
1881
    }
1882
1883
    public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = [])
1884
    {
1885
        if (!empty($second_title)) {
1886
            $second_title = Security::remove_XSS($second_title);
1887
            $title .= "<small> $second_title<small>";
1888
        }
1889
        $attributes['class'] = 'page-header';
1890
1891
        return self::tag($size, Security::remove_XSS($title), $attributes);
1892
    }
1893
1894
    public static function page_subheader2($title, $second_title = null)
1895
    {
1896
        return self::page_header($title, $second_title, 'h4');
1897
    }
1898
1899
    public static function page_subheader3($title, $second_title = null)
1900
    {
1901
        return self::page_header($title, $second_title, 'h5');
1902
    }
1903
1904
    /**
1905
     * @param array $list
1906
     *
1907
     * @return string|null
1908
     */
1909
    public static function description($list)
1910
    {
1911
        $html = null;
1912
        if (!empty($list)) {
1913
            $html = '<dl class="dl-horizontal">';
1914
            foreach ($list as $item) {
1915
                $html .= '<dt>'.$item['title'].'</dt>';
1916
                $html .= '<dd>'.$item['content'].'</dd>';
1917
            }
1918
            $html .= '</dl>';
1919
        }
1920
1921
        return $html;
1922
    }
1923
1924
    /**
1925
     * @param int    $percentage      int value between 0 and 100
1926
     * @param bool   $show_percentage
1927
     * @param string $extra_info
1928
     * @param string $class           danger/success/infowarning
1929
     *
1930
     * @return string
1931
     */
1932
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '')
1933
    {
1934
        $percentage = (int) $percentage;
1935
        $class = empty($class) ? '' : "progress-bar-$class";
1936
1937
        $div = '<div class="progress">
1938
                <div
1939
                    class="progress-bar progress-bar-striped '.$class.'"
1940
                    role="progressbar"
1941
                    aria-valuenow="'.$percentage.'"
1942
                    aria-valuemin="0"
1943
                    aria-valuemax="100"
1944
                    style="width: '.$percentage.'%;"
1945
                >';
1946
        if ($show_percentage) {
1947
            $div .= $percentage.'%';
1948
        } else {
1949
            if (!empty($extra_info)) {
1950
                $div .= $extra_info;
1951
            }
1952
        }
1953
        $div .= '</div></div>';
1954
1955
        return $div;
1956
    }
1957
1958
    /**
1959
     * @param string $count
1960
     * @param string $type
1961
     *
1962
     * @return string|null
1963
     */
1964
    public static function badge($count, $type = "warning")
1965
    {
1966
        $class = '';
1967
1968
        switch ($type) {
1969
            case 'success':
1970
                $class = 'badge-success';
1971
                break;
1972
            case 'warning':
1973
                $class = 'badge-warning';
1974
                break;
1975
            case 'important':
1976
                $class = 'badge-important';
1977
                break;
1978
            case 'info':
1979
                $class = 'badge-info';
1980
                break;
1981
            case 'inverse':
1982
                $class = 'badge-inverse';
1983
                break;
1984
        }
1985
1986
        if (!empty($count)) {
1987
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1988
        }
1989
1990
        return null;
1991
    }
1992
1993
    /**
1994
     * @param array $badge_list
1995
     *
1996
     * @return string
1997
     */
1998
    public static function badge_group($badge_list)
1999
    {
2000
        $html = '<div class="badge-group">';
2001
        foreach ($badge_list as $badge) {
2002
            $html .= $badge;
2003
        }
2004
        $html .= '</div>';
2005
2006
        return $html;
2007
    }
2008
2009
    /**
2010
     * @param string $content
2011
     * @param string $type
2012
     *
2013
     * @return string
2014
     */
2015
    public static function label($content, $type = 'default')
2016
    {
2017
        switch ($type) {
2018
            case 'success':
2019
                $class = 'label-success';
2020
                break;
2021
            case 'warning':
2022
                $class = 'label-warning';
2023
                break;
2024
            case 'important':
2025
            case 'danger':
2026
                $class = 'label-danger';
2027
                break;
2028
            case 'info':
2029
                $class = 'label-info';
2030
                break;
2031
            case 'primary':
2032
                $class = 'label-primary';
2033
                break;
2034
            default:
2035
                $class = 'label-default';
2036
                break;
2037
        }
2038
2039
        $html = '';
2040
        if (!empty($content)) {
2041
            $html = '<span class="label '.$class.'">';
2042
            $html .= $content;
2043
            $html .= '</span>';
2044
        }
2045
2046
        return $html;
2047
    }
2048
2049
    /**
2050
     * @param array  $items
2051
     * @param string $class
2052
     *
2053
     * @return string|null
2054
     */
2055
    public static function actions($items, $class = 'new_actions')
2056
    {
2057
        $html = null;
2058
        if (!empty($items)) {
2059
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2060
            foreach ($items as $value) {
2061
                $class = null;
2062
                if (isset($value['active']) && $value['active']) {
2063
                    $class = 'class ="active"';
2064
                }
2065
2066
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2067
                    $class = 'class ="active"';
2068
                }
2069
                $html .= "<li $class >";
2070
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2071
                $html .= self::url($value['content'], $value['url'], $attributes);
2072
                $html .= '</li>';
2073
            }
2074
            $html .= '</ul></div>';
2075
            $html .= '<br />';
2076
        }
2077
2078
        return $html;
2079
    }
2080
2081
    /**
2082
     * Prints a tooltip.
2083
     *
2084
     * @param string $text
2085
     * @param string $tip
2086
     *
2087
     * @return string
2088
     */
2089
    public static function tip($text, $tip)
2090
    {
2091
        if (empty($tip)) {
2092
            return $text;
2093
        }
2094
2095
        return self::span(
2096
            $text,
2097
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2098
        );
2099
    }
2100
2101
    /**
2102
     * @param array  $items
2103
     * @param string $type
2104
     * @param null   $id
2105
     *
2106
     * @return string|null
2107
     */
2108
    public static function generate_accordion($items, $type = 'jquery', $id = null)
2109
    {
2110
        $html = null;
2111
        if (!empty($items)) {
2112
            if (empty($id)) {
2113
                $id = api_get_unique_id();
2114
            }
2115
            if ($type == 'jquery') {
2116
                $html = '<div class="accordion_jquery" id="'.$id.'">'; //using jquery
2117
            } else {
2118
                $html = '<div class="accordion" id="'.$id.'">'; //using bootstrap
2119
            }
2120
2121
            $count = 1;
2122
            foreach ($items as $item) {
2123
                $html .= '<div class="accordion-my-group">';
2124
                $html .= '<div class="accordion-heading">
2125
                            <a class="accordion-toggle" data-toggle="collapse" data-parent="#'.$id.'" href="#collapse'.$count.'">
2126
                            '.$item['title'].'
2127
                            </a>
2128
                          </div>';
2129
2130
                $html .= '<div id="collapse'.$count.'" class="accordion-body">';
2131
                $html .= '<div class="accordion-my-inner">
2132
                            '.$item['content'].'
2133
                            </div>
2134
                          </div>';
2135
            }
2136
            $html .= '</div>';
2137
        }
2138
2139
        return $html;
2140
    }
2141
2142
    /**
2143
     * @param array $buttons
2144
     *
2145
     * @return string
2146
     */
2147
    public static function groupButton($buttons)
2148
    {
2149
        $html = '<div class="btn-group" role="group">';
2150
        foreach ($buttons as $button) {
2151
            $html .= $button;
2152
        }
2153
        $html .= '</div>';
2154
2155
        return $html;
2156
    }
2157
2158
    /**
2159
     * @todo use twig
2160
     *
2161
     * @param string $title
2162
     * @param array  $elements
2163
     * @param bool   $alignToRight
2164
     *
2165
     * @return string
2166
     */
2167
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2168
    {
2169
        $html = '<div class="btn-group">
2170
                <button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
2171
                '.$title.'
2172
                <span class="caret"></span></button>
2173
                <ul class="dropdown-menu '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2174
        foreach ($elements as $item) {
2175
            $html .= self::tag('li', self::url($item['title'], $item['href']));
2176
        }
2177
        $html .= '</ul>
2178
            </div>';
2179
2180
        return $html;
2181
    }
2182
2183
    /**
2184
     * @param string $file
2185
     * @param array  $params
2186
     *
2187
     * @return string|null
2188
     */
2189
    public static function getMediaPlayer($file, $params = [])
2190
    {
2191
        $fileInfo = pathinfo($file);
2192
2193
        $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : '';
2194
        $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2195
        $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2196
        $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2197
2198
        switch ($fileInfo['extension']) {
2199
            case 'mp3':
2200
            case 'webm':
2201
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'">';
2202
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2203
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2204
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2205
                          </object>';
2206
                $html .= '</audio>';
2207
2208
                return $html;
2209
                break;
2210
            case 'wav':
2211
            case 'ogg':
2212
                $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'"></audio>';
2213
2214
                return $html;
2215
                break;
2216
        }
2217
2218
        return null;
2219
    }
2220
2221
    /**
2222
     * @param int    $nextValue
2223
     * @param array  $list
2224
     * @param int    $current
2225
     * @param int    $fixedValue
2226
     * @param array  $conditions
2227
     * @param string $link
2228
     * @param bool   $isMedia
2229
     * @param bool   $addHeaders
2230
     * @param array  $linkAttributes
2231
     *
2232
     * @return string
2233
     */
2234
    public static function progressPaginationBar(
2235
        $nextValue,
2236
        $list,
2237
        $current,
2238
        $fixedValue = null,
2239
        $conditions = [],
2240
        $link = null,
2241
        $isMedia = false,
2242
        $addHeaders = true,
2243
        $linkAttributes = []
2244
    ) {
2245
        if ($addHeaders) {
2246
            $pagination_size = 'pagination-mini';
2247
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2248
        } else {
2249
            $html = null;
2250
        }
2251
        $affectAllItems = false;
2252
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2253
            $affectAllItems = true;
2254
        }
2255
        $localCounter = 0;
2256
        foreach ($list as $itemId) {
2257
            $isCurrent = false;
2258
            if ($affectAllItems) {
2259
                $isCurrent = true;
2260
            } else {
2261
                if (!$isMedia) {
2262
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2263
                }
2264
            }
2265
            $html .= self::parsePaginationItem(
2266
                $itemId,
2267
                $isCurrent,
2268
                $conditions,
2269
                $link,
2270
                $nextValue,
2271
                $isMedia,
2272
                $localCounter,
2273
                $fixedValue,
2274
                $linkAttributes
2275
            );
2276
            $localCounter++;
2277
        }
2278
        if ($addHeaders) {
2279
            $html .= '</ul></div>';
2280
        }
2281
2282
        return $html;
2283
    }
2284
2285
    /**
2286
     * @param int    $itemId
2287
     * @param bool   $isCurrent
2288
     * @param array  $conditions
2289
     * @param string $link
2290
     * @param int    $nextValue
2291
     * @param bool   $isMedia
2292
     * @param int    $localCounter
2293
     * @param int    $fixedValue
2294
     * @param array  $linkAttributes
2295
     *
2296
     * @return string
2297
     */
2298
    public static function parsePaginationItem(
2299
        $itemId,
2300
        $isCurrent,
2301
        $conditions,
2302
        $link,
2303
        $nextValue = 0,
2304
        $isMedia = false,
2305
        $localCounter = null,
2306
        $fixedValue = null,
2307
        $linkAttributes = []
2308
    ) {
2309
        $defaultClass = 'before';
2310
        $class = $defaultClass;
2311
        foreach ($conditions as $condition) {
2312
            $array = isset($condition['items']) ? $condition['items'] : [];
2313
            $class_to_applied = $condition['class'];
2314
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2315
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2316
            switch ($type) {
2317
                case 'positive':
2318
                    if (in_array($itemId, $array)) {
2319
                        if ($mode == 'overwrite') {
2320
                            $class = " $defaultClass $class_to_applied";
2321
                        } else {
2322
                            $class .= " $class_to_applied";
2323
                        }
2324
                    }
2325
                    break;
2326
                case 'negative':
2327
                    if (!in_array($itemId, $array)) {
2328
                        if ($mode == 'overwrite') {
2329
                            $class = " $defaultClass $class_to_applied";
2330
                        } else {
2331
                            $class .= " $class_to_applied";
2332
                        }
2333
                    }
2334
                    break;
2335
            }
2336
        }
2337
        if ($isCurrent) {
2338
            $class = 'before current';
2339
        }
2340
        if ($isMedia && $isCurrent) {
2341
            $class = 'before current';
2342
        }
2343
        if (empty($link)) {
2344
            $link_to_show = '#';
2345
        } else {
2346
            $link_to_show = $link.($nextValue + $localCounter);
2347
        }
2348
        $label = $nextValue + $localCounter + 1;
2349
        if ($isMedia) {
2350
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2351
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2352
        }
2353
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2354
2355
        return '<li class = "'.$class.'">'.$link.'</li>';
2356
    }
2357
2358
    /**
2359
     * @param int $current
2360
     * @param int $total
2361
     *
2362
     * @return string
2363
     */
2364
    public static function paginationIndicator($current, $total)
2365
    {
2366
        $html = null;
2367
        if (!empty($current) && !empty($total)) {
2368
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2369
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2370
        }
2371
2372
        return $html;
2373
    }
2374
2375
    /**
2376
     * @param $url
2377
     * @param $currentPage
2378
     * @param $pagesCount
2379
     * @param $totalItems
2380
     *
2381
     * @return string
2382
     */
2383
    public static function getPagination($url, $currentPage, $pagesCount, $totalItems)
2384
    {
2385
        $pagination = '';
2386
        if ($totalItems > 1 && $pagesCount > 1) {
2387
            $pagination .= '<ul class="pagination">';
2388
            for ($i = 0; $i < $pagesCount; $i++) {
2389
                $newPage = $i + 1;
2390
                if ($currentPage == $newPage) {
2391
                    $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2392
                } else {
2393
                    $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>';
2394
                }
2395
            }
2396
            $pagination .= '</ul>';
2397
        }
2398
2399
        return $pagination;
2400
    }
2401
2402
    /**
2403
     * Adds a message in the queue.
2404
     *
2405
     * @param string $message
2406
     */
2407
    public static function addFlash($message)
2408
    {
2409
        $messages = Session::read('flash_messages');
2410
        if (empty($messages)) {
2411
            $messages[] = $message;
2412
        } else {
2413
            array_push($messages, $message);
2414
        }
2415
        Session::write('flash_messages', $messages);
2416
    }
2417
2418
    /**
2419
     * @return string
2420
     */
2421
    public static function getFlashToString()
2422
    {
2423
        $messages = Session::read('flash_messages');
2424
        $messageToString = '';
2425
        if (!empty($messages)) {
2426
            foreach ($messages as $message) {
2427
                $messageToString .= $message;
2428
            }
2429
        }
2430
2431
        return $messageToString;
2432
    }
2433
2434
    /**
2435
     * Shows the message from the session.
2436
     */
2437
    public static function showFlash()
2438
    {
2439
        echo self::getFlashToString();
2440
    }
2441
2442
    /**
2443
     * Destroys the message session.
2444
     */
2445
    public static function cleanFlashMessages()
2446
    {
2447
        Session::erase('flash_messages');
2448
    }
2449
2450
    /**
2451
     * Get the profile edition link for a user.
2452
     *
2453
     * @param int  $userId  The user id
2454
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2455
     *
2456
     * @return string The link
2457
     */
2458
    public static function getProfileEditionLink($userId, $asAdmin = false)
2459
    {
2460
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2461
        if ($asAdmin) {
2462
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2463
        }
2464
2465
        if (api_get_setting('sso_authentication') === 'true') {
2466
            $subSSOClass = api_get_setting('sso_authentication_subclass');
2467
            $objSSO = null;
2468
2469
            if (!empty($subSSOClass)) {
2470
                $file = api_get_path(SYS_CODE_PATH)."auth/sso/sso.$subSSOClass.class.php";
2471
                if (file_exists($file)) {
2472
                    require_once $file;
2473
                    $subSSOClass = 'sso'.$subSSOClass;
2474
                    $objSSO = new $subSSOClass();
2475
                } else {
2476
                    throw new Exception("$subSSOClass file not set");
2477
                }
2478
            } else {
2479
                $objSSO = new sso();
2480
            }
2481
2482
            $editProfileUrl = $objSSO->generateProfileEditingURL(
2483
                $userId,
2484
                $asAdmin
2485
            );
2486
        }
2487
2488
        return $editProfileUrl;
2489
    }
2490
2491
    /**
2492
     * Get the vCard for a user.
2493
     *
2494
     * @param int $userId The user id
2495
     *
2496
     * @return string *.*vcf file
2497
     */
2498
    public static function getVCardUserLink($userId)
2499
    {
2500
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2501
2502
        return $vCardUrl;
2503
    }
2504
2505
    /**
2506
     * @param string $content
2507
     * @param string $title
2508
     * @param string $footer
2509
     * @param string $type            primary|success|info|warning|danger
2510
     * @param string $extra
2511
     * @param string $id
2512
     * @param string $backgroundColor
2513
     * @param string $extraClass
2514
     *
2515
     * @return string
2516
     */
2517
    public static function panel(
2518
        $content,
2519
        $title = '',
2520
        $footer = '',
2521
        $type = 'default',
2522
        $extra = '',
2523
        $id = '',
2524
        $backgroundColor = '',
2525
        $extraClass = ''
2526
    ) {
2527
        $headerStyle = '';
2528
        if (!empty($backgroundColor)) {
2529
            $headerStyle = 'style = "color: white; background-color: '.$backgroundColor.'" ';
2530
        }
2531
2532
        $title = !empty($title) ? '<div class="panel-heading" '.$headerStyle.' ><h3 class="panel-title">'.$title.'</h3>'.$extra.'</div>' : '';
2533
2534
        if (empty($title) && !empty($extra)) {
2535
            $title = '<div class="panel-heading" '.$headerStyle.' >'.$extra.'</div>';
2536
        }
2537
2538
        $footer = !empty($footer) ? '<div class="panel-footer">'.$footer.'</div>' : '';
2539
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2540
        $style = !in_array($type, $typeList) ? 'default' : $type;
2541
2542
        if (!empty($id)) {
2543
            $id = " id='$id'";
2544
        }
2545
2546
        return '
2547
            <div '.$id.' class="panel panel-'.$style.' '.$extraClass.' ">
2548
                '.$title.'
2549
                '.self::contentPanel($content).'
2550
                '.$footer.'
2551
            </div>'
2552
        ;
2553
    }
2554
2555
    /**
2556
     * @param string $content
2557
     *
2558
     * @return string
2559
     */
2560
    public static function contentPanel($content)
2561
    {
2562
        if (empty($content)) {
2563
            return '';
2564
        }
2565
2566
        return '<div class="panel-body">'.$content.'</div>';
2567
    }
2568
2569
    /**
2570
     * Get the button HTML with an Awesome Font icon.
2571
     *
2572
     * @param string $text        The button content
2573
     * @param string $url         The url to button
2574
     * @param string $icon        The Awesome Font class for icon
2575
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2576
     * @param array  $attributes  The additional attributes
2577
     * @param bool   $includeText
2578
     *
2579
     * @return string The button HTML
2580
     */
2581
    public static function toolbarButton(
2582
        $text,
2583
        $url,
2584
        $icon = 'check',
2585
        $type = 'default',
2586
        array $attributes = [],
2587
        $includeText = true
2588
    ) {
2589
        $buttonClass = "btn btn-$type";
2590
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2591
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2592
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2593
2594
        if (!$includeText) {
2595
            $text = '<span class="sr-only">'.$text.'</span>';
2596
        }
2597
2598
        return self::url("$icon $text", $url, $attributes);
2599
    }
2600
2601
    /**
2602
     * @param string $id
2603
     * @param array  $content
2604
     * @param array  $colsWidth Optional. Columns width
2605
     *
2606
     * @return string
2607
     */
2608
    public static function toolbarAction($id, $content, $colsWidth = [])
2609
    {
2610
        $col = count($content);
2611
2612
        if (!$colsWidth) {
2613
            $width = 12 / $col;
2614
            array_walk($content, function () use ($width, &$colsWidth) {
2615
                $colsWidth[] = $width;
2616
            });
2617
        }
2618
2619
        $html = '<div id="'.$id.'" class="actions">';
2620
        $html .= '<div class="row">';
2621
2622
        for ($i = 0; $i < $col; $i++) {
2623
            $class = 'col-sm-'.$colsWidth[$i];
2624
2625
            if ($col > 1) {
2626
                if ($i > 0 && $i < count($content) - 1) {
2627
                    $class .= ' text-center';
2628
                } elseif ($i === count($content) - 1) {
2629
                    $class .= ' text-right';
2630
                }
2631
            }
2632
2633
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2634
        }
2635
2636
        $html .= '</div>';
2637
        $html .= '</div>';
2638
2639
        return $html;
2640
    }
2641
2642
    /**
2643
     * Get a HTML code for a icon by Font Awesome.
2644
     *
2645
     * @param string     $name            The icon name. Example: "mail-reply"
2646
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2647
     * @param bool       $fixWidth        Optional. Whether add the fw class
2648
     * @param string     $additionalClass
2649
     * @param string     $title
2650
     *
2651
     * @return string
2652
     */
2653
    public static function returnFontAwesomeIcon(
2654
        $name,
2655
        $size = '',
2656
        $fixWidth = false,
2657
        $additionalClass = '',
2658
        $title = ''
2659
    ) {
2660
        $className = "fa fa-$name";
2661
2662
        if ($fixWidth) {
2663
            $className .= ' fa-fw';
2664
        }
2665
2666
        switch ($size) {
2667
            case 'lg':
2668
                $className .= ' fa-lg';
2669
                break;
2670
            case 2:
2671
            case 3:
2672
            case 4:
2673
            case 5:
2674
                $className .= " fa-{$size}x";
2675
                break;
2676
        }
2677
2678
        if (!empty($additionalClass)) {
2679
            $className .= " $additionalClass";
2680
        }
2681
2682
        $icon = self::tag('em', null, ['class' => $className, 'title' => $title]);
2683
2684
        return "$icon ";
2685
    }
2686
2687
    /**
2688
     * @param string     $title
2689
     * @param string     $content
2690
     * @param null       $id
2691
     * @param array      $params
2692
     * @param null       $idAccordion
2693
     * @param null       $idCollapse
2694
     * @param bool|true  $open
2695
     * @param bool|false $fullClickable
2696
     *
2697
     * @return string|null
2698
     *
2699
     * @todo rework function to easy use
2700
     */
2701
    public static function panelCollapse(
2702
        $title,
2703
        $content,
2704
        $id = null,
2705
        $params = [],
2706
        $idAccordion = null,
2707
        $idCollapse = null,
2708
        $open = true,
2709
        $fullClickable = false
2710
    ) {
2711
        if (!empty($idAccordion)) {
2712
            $headerClass = '';
2713
            $headerClass .= $fullClickable ? 'center-block ' : '';
2714
            $headerClass .= $open ? '' : 'collapsed';
2715
            $contentClass = 'panel-collapse collapse ';
2716
            $contentClass .= $open ? 'in ' : '';
2717
            $contentClass .= $params['class'] ?? '';
2718
            $ariaExpanded = $open ? 'true' : 'false';
2719
2720
            $attributes = [
2721
                'id' => $idCollapse,
2722
                'class' => $contentClass,
2723
                'role' => 'tabpanel',
2724
            ];
2725
2726
            if (!empty($params)) {
2727
                $attributes = array_merge(
2728
                    $params,
2729
                    $attributes
2730
                );
2731
            }
2732
2733
            $collapseDiv = self::div('<div class="panel-body">'.$content.'</div>', $attributes);
2734
2735
            $html = <<<HTML
2736
                <div class="panel-group" id="$idAccordion" role="tablist" aria-multiselectable="true">
2737
                    <div class="panel panel-default" id="$id">
2738
                        <div class="panel-heading" role="tab">
2739
                            <h4 class="panel-title">
2740
                                <a
2741
                                    class="$headerClass"
2742
                                    role="button" data-toggle="collapse"
2743
                                    data-parent="#$idAccordion" href="#$idCollapse"
2744
                                    aria-expanded="$ariaExpanded"
2745
                                    aria-controls="$idCollapse">$title</a>
2746
                            </h4>
2747
                        </div>
2748
                        $collapseDiv
2749
                    </div>
2750
                </div>
2751
HTML;
2752
        } else {
2753
            if (!empty($id)) {
2754
                $params['id'] = $id;
2755
            }
2756
            $params['class'] = 'panel panel-default';
2757
            $html = null;
2758
            if (!empty($title)) {
2759
                $html .= '<div class="panel-heading">'.$title.'</div>'.PHP_EOL;
2760
            }
2761
            $html .= '<div class="panel-body">'.$content.'</div>'.PHP_EOL;
2762
            $html = self::div($html, $params);
2763
        }
2764
2765
        return $html;
2766
    }
2767
2768
    /**
2769
     * Returns the string "1 day ago" with a link showing the exact date time.
2770
     *
2771
     * @param string $dateTime in UTC or a DateTime in UTC
2772
     *
2773
     * @return string
2774
     */
2775
    public static function dateToStringAgoAndLongDate($dateTime)
2776
    {
2777
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2778
            return '';
2779
        }
2780
2781
        if ($dateTime instanceof \DateTime) {
2782
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2783
        }
2784
2785
        return self::tip(
2786
            date_to_str_ago($dateTime),
2787
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2788
            //api_get_local_time($dateTime)
2789
        );
2790
    }
2791
2792
    /**
2793
     * @param array  $userInfo
2794
     * @param string $status
2795
     * @param string $toolbar
2796
     *
2797
     * @return string
2798
     */
2799
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2800
    {
2801
        if (empty($userInfo)) {
2802
            return '';
2803
        }
2804
2805
        if (!empty($status)) {
2806
            $status = '<div class="items-user-status">'.$status.'</div>';
2807
        }
2808
2809
        if (!empty($toolbar)) {
2810
            $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>';
2811
        }
2812
2813
        return '<div id="user_card_'.$userInfo['id'].'" class="col-md-12">
2814
                    <div class="row">
2815
                        <div class="col-md-2">
2816
                            <img src="'.$userInfo['avatar'].'" class="img-responsive img-circle">
2817
                        </div>
2818
                        <div class="col-md-10">
2819
                           <p>'.$userInfo['complete_name'].'</p>
2820
                           <div class="row">
2821
                           <div class="col-md-2">
2822
                           '.$status.'
2823
                           </div>
2824
                           <div class="col-md-10">
2825
                           '.$toolbar.'
2826
                           </div>
2827
                           </div>
2828
                        </div>
2829
                    </div>
2830
                    <hr />
2831
              </div>';
2832
    }
2833
2834
    /**
2835
     * @param string $fileName
2836
     * @param string $fileUrl
2837
     *
2838
     * @return string
2839
     */
2840
    public static function fileHtmlGuesser($fileName, $fileUrl)
2841
    {
2842
        $data = pathinfo($fileName);
2843
2844
        //$content = self::url($data['basename'], $fileUrl);
2845
        $content = '';
2846
        switch ($data['extension']) {
2847
            case 'webm':
2848
            case 'mp4':
2849
            case 'ogg':
2850
                $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>';
2851
                // Allows video to play when loading during an ajax call
2852
                $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>";
2853
                break;
2854
            case 'jpg':
2855
            case 'jpeg':
2856
            case 'gif':
2857
            case 'png':
2858
                $content = '<img class="img-responsive" src="'.$fileUrl.'" />';
2859
                break;
2860
            default:
2861
                //$html = self::url($data['basename'], $fileUrl);
2862
                break;
2863
        }
2864
        //$html = self::url($content, $fileUrl, ['ajax']);
2865
2866
        return $content;
2867
    }
2868
2869
    /**
2870
     * @param string $frameName
2871
     *
2872
     * @return string
2873
     */
2874
    public static function getFrameReadyBlock($frameName, $itemType = '')
2875
    {
2876
        $webPublicPath = api_get_path(WEB_PUBLIC_PATH);
2877
        $webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
2878
2879
        $videoFeatures = [
2880
            'playpause',
2881
            'current',
2882
            'progress',
2883
            'duration',
2884
            'tracks',
2885
            'volume',
2886
            'fullscreen',
2887
            'vrview',
2888
            'markersrolls',
2889
        ];
2890
        $features = api_get_configuration_value('video_features');
2891
        $videoPluginsJS = [];
2892
        $videoPluginCSS = [];
2893
        if (!empty($features) && isset($features['features'])) {
2894
            foreach ($features['features'] as $feature) {
2895
                if ($feature === 'vrview') {
2896
                    continue;
2897
                }
2898
                $defaultFeatures[] = $feature;
2899
                $videoPluginsJS[] = "mediaelement/plugins/$feature/$feature.min.js";
2900
                $videoPluginCSS[] = "mediaelement/plugins/$feature/$feature.min.css";
2901
            }
2902
        }
2903
2904
        $videoPluginFiles = '';
2905
        foreach ($videoPluginsJS as $file) {
2906
            $videoPluginFiles .= '{type: "script", src: "'.$webJsPath.$file.'"},';
2907
        }
2908
2909
        $videoPluginCssFiles = '';
2910
        foreach ($videoPluginCSS as $file) {
2911
            $videoPluginCssFiles .= '{type: "stylesheet", src: "'.$webJsPath.$file.'"},';
2912
        }
2913
2914
        $translateHtml = '';
2915
        $translate = api_get_configuration_value('translate_html');
2916
        if ($translate) {
2917
            $translateHtml = '{type:"script", src:"'.api_get_path(WEB_AJAX_PATH).'lang.ajax.php?a=translate_html&'.api_get_cidreq().'"},';
2918
        }
2919
2920
        $fixLinkSetting = api_get_configuration_value('lp_fix_embed_content');
2921
        $fixLink = '';
2922
        if ($fixLinkSetting) {
2923
            $fixLink = '{type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'fixlinks.js"},';
2924
        }
2925
2926
        $videoFeatures = implode("','", $videoFeatures);
2927
        $frameReady = '
2928
        $.frameReady(function() {
2929
             $(function () {
2930
                $("video:not(.skip), audio:not(.skip)").mediaelementplayer({
2931
                    pluginPath: "'.$webJsPath.'mediaelement/plugins/",
2932
                    features: [\''.$videoFeatures.'\'],
2933
                    success: function(mediaElement, originalNode, instance) {
2934
                        '.ChamiloApi::getQuizMarkersRollsJS().'
2935
                    },
2936
                    vrPath: "'.$webPublicPath.'assets/vrview/build/vrview.js"
2937
                });
2938
            });
2939
        },
2940
        "'.$frameName.'",
2941
        ';
2942
2943
        if ('quiz' === $itemType) {
2944
            $jquery = '
2945
                '.$fixLink.'
2946
                {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2947
                {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2948
                {type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
2949
                    deps: [
2950
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.js"},
2951
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/markersrolls/markersrolls.min.js"},
2952
                    '.$videoPluginFiles.'
2953
                ]},
2954
                '.$translateHtml.'
2955
            ';
2956
        } else {
2957
            $jquery = '
2958
                {type:"script", src:"'.api_get_jquery_web_path().'", deps: [
2959
                '.$fixLink.'
2960
                {type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
2961
                {type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
2962
                {type:"script", src:"'.$webPublicPath.'assets/jquery-ui/jquery-ui.min.js"},
2963
                {type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
2964
                    deps: [
2965
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.js"},
2966
                    {type:"script", src: "'.$webJsPath.'mediaelement/plugins/markersrolls/markersrolls.min.js"},
2967
                    '.$videoPluginFiles.'
2968
                ]},
2969
                '.$translateHtml.'
2970
            ]},';
2971
        }
2972
2973
        $frameReady .= '
2974
        [
2975
            '.$jquery.'
2976
            '.$videoPluginCssFiles.'
2977
            {type:"script", src:"'.$webPublicPath.'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
2978
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
2979
            {type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/theme.css"},
2980
            {type:"stylesheet", src:"'.$webPublicPath.'css/dialog.css"},
2981
            {type:"stylesheet", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelementplayer.min.css"},
2982
            {type:"stylesheet", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.css"},
2983
        ]);';
2984
2985
        return $frameReady;
2986
    }
2987
2988
    /**
2989
     * @param string $image
2990
     * @param int    $size
2991
     *
2992
     * @return string
2993
     */
2994
    public static function get_icon_path($image, $size = ICON_SIZE_SMALL)
2995
    {
2996
        return self::return_icon($image, '', [], $size, false, true);
2997
    }
2998
2999
    /**
3000
     * @param string $image
3001
     * @param int    $size
3002
     * @param string $name
3003
     *
3004
     * @return string
3005
     */
3006
    public static function get_image($image, $size = ICON_SIZE_SMALL, $name = '')
3007
    {
3008
        return self::return_icon($image, $name, [], $size);
3009
    }
3010
}
3011