| Total Complexity | 406 |
| Total Lines | 3037 |
| Duplicated Lines | 0 % |
| Changes | 3 | ||
| Bugs | 0 | Features | 0 |
Complex classes like Display often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Display, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 28 | class Display |
||
| 29 | { |
||
| 30 | /** @var Template */ |
||
| 31 | public static $global_template; |
||
| 32 | public static $preview_style = null; |
||
| 33 | public static $legacyTemplate; |
||
| 34 | |||
| 35 | public function __construct() |
||
| 36 | { |
||
| 37 | } |
||
| 38 | |||
| 39 | /** |
||
| 40 | * @return array |
||
| 41 | */ |
||
| 42 | public static function toolList() |
||
| 43 | { |
||
| 44 | return [ |
||
| 45 | 'group', |
||
| 46 | 'work', |
||
| 47 | 'glossary', |
||
| 48 | 'forum', |
||
| 49 | 'course_description', |
||
| 50 | 'gradebook', |
||
| 51 | 'attendance', |
||
| 52 | 'course_progress', |
||
| 53 | 'notebook', |
||
| 54 | ]; |
||
| 55 | } |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Displays the page header. |
||
| 59 | * |
||
| 60 | * @param string The name of the page (will be showed in the page title) |
||
| 61 | * @param string Optional help file name |
||
| 62 | * @param string $page_header |
||
| 63 | */ |
||
| 64 | public static function display_header( |
||
| 65 | $tool_name = '', |
||
| 66 | $help = null, |
||
| 67 | $page_header = null |
||
| 68 | ) { |
||
| 69 | global $interbreadcrumb; |
||
| 70 | $interbreadcrumb[] = ['url' => '#', 'name' => $tool_name]; |
||
| 71 | |||
| 72 | ob_start(); |
||
| 73 | |||
| 74 | return true; |
||
| 75 | } |
||
| 76 | |||
| 77 | /** |
||
| 78 | * Displays the reduced page header (without banner). |
||
| 79 | */ |
||
| 80 | public static function display_reduced_header() |
||
| 81 | { |
||
| 82 | ob_start(); |
||
| 83 | self::$legacyTemplate = '@ChamiloCore/Layout/no_layout.html.twig'; |
||
| 84 | |||
| 85 | return true; |
||
| 86 | } |
||
| 87 | |||
| 88 | /** |
||
| 89 | * Display no header. |
||
| 90 | */ |
||
| 91 | public static function display_no_header() |
||
| 92 | { |
||
| 93 | global $tool_name, $show_learnpath; |
||
| 94 | self::$global_template = new Template( |
||
| 95 | $tool_name, |
||
| 96 | false, |
||
| 97 | false, |
||
| 98 | $show_learnpath |
||
| 99 | ); |
||
| 100 | } |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Display the page footer. |
||
| 104 | */ |
||
| 105 | public static function display_footer() |
||
| 106 | { |
||
| 107 | $contents = ob_get_contents(); |
||
| 108 | if (ob_get_length()) { |
||
| 109 | ob_end_clean(); |
||
| 110 | } |
||
| 111 | $tpl = '@ChamiloCore/Layout/layout_one_col.html.twig'; |
||
| 112 | if (!empty(self::$legacyTemplate)) { |
||
| 113 | $tpl = self::$legacyTemplate; |
||
| 114 | } |
||
| 115 | $response = new Response(); |
||
| 116 | $params['content'] = $contents; |
||
| 117 | global $interbreadcrumb, $htmlHeadXtra; |
||
| 118 | |||
| 119 | $courseInfo = api_get_course_info(); |
||
| 120 | if (!empty($courseInfo)) { |
||
| 121 | $url = $courseInfo['course_public_url']; |
||
| 122 | $sessionId = api_get_session_id(); |
||
| 123 | if (!empty($sessionId)) { |
||
| 124 | $url .= '?sid='.$sessionId; |
||
| 125 | } |
||
| 126 | |||
| 127 | if (!empty($interbreadcrumb)) { |
||
| 128 | array_unshift( |
||
| 129 | $interbreadcrumb, |
||
| 130 | ['name' => $courseInfo['title'], 'url' => $url] |
||
| 131 | ); |
||
| 132 | } |
||
| 133 | } |
||
| 134 | |||
| 135 | if (empty($interbreadcrumb)) { |
||
| 136 | $interbreadcrumb = []; |
||
| 137 | } else { |
||
| 138 | $interbreadcrumb = array_filter( |
||
| 139 | $interbreadcrumb, |
||
| 140 | function ($item) { |
||
| 141 | return isset($item['name']) && !empty($item['name']); |
||
| 142 | } |
||
| 143 | ); |
||
| 144 | } |
||
| 145 | |||
| 146 | $params['legacy_javascript'] = $htmlHeadXtra; |
||
| 147 | $params['legacy_breadcrumb'] = json_encode(array_values($interbreadcrumb)); |
||
| 148 | |||
| 149 | Template::setVueParams($params); |
||
| 150 | $content = Container::getTwig()->render($tpl, $params); |
||
| 151 | $response->setContent($content); |
||
| 152 | $response->send(); |
||
| 153 | exit; |
||
| 154 | } |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Display the page footer. |
||
| 158 | */ |
||
| 159 | public static function display_reduced_footer() |
||
| 160 | { |
||
| 161 | return self::display_footer(); |
||
| 162 | } |
||
| 163 | |||
| 164 | /** |
||
| 165 | * Displays the tool introduction of a tool. |
||
| 166 | * |
||
| 167 | * @author Patrick Cool <[email protected]>, Ghent University |
||
| 168 | * |
||
| 169 | * @param string $tool these are the constants that are used for indicating the tools |
||
| 170 | * @param array $editor_config Optional configuration settings for the online editor. |
||
| 171 | * return: $tool return a string array list with the "define" in main_api.lib |
||
| 172 | * |
||
| 173 | * @return string html code for adding an introduction |
||
| 174 | */ |
||
| 175 | public static function display_introduction_section( |
||
| 176 | $tool, |
||
| 177 | $editor_config = null |
||
| 178 | ) { |
||
| 179 | // @todo replace introduction section with a vue page. |
||
| 180 | return; |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * @param string $tool |
||
| 185 | * @param array $editor_config |
||
| 186 | */ |
||
| 187 | public static function return_introduction_section( |
||
| 188 | $tool, |
||
| 189 | $editor_config = null |
||
| 190 | ) { |
||
| 191 | } |
||
| 192 | |||
| 193 | /** |
||
| 194 | * Displays a table. |
||
| 195 | * |
||
| 196 | * @param array $header Titles for the table header |
||
| 197 | * each item in this array can contain 3 values |
||
| 198 | * - 1st element: the column title |
||
| 199 | * - 2nd element: true or false (column sortable?) |
||
| 200 | * - 3th element: additional attributes for |
||
| 201 | * th-tag (eg for column-width) |
||
| 202 | * - 4the element: additional attributes for the td-tags |
||
| 203 | * @param array $content 2D-array with the tables content |
||
| 204 | * @param array $sorting_options Keys are: |
||
| 205 | * 'column' = The column to use as sort-key |
||
| 206 | * 'direction' = SORT_ASC or SORT_DESC |
||
| 207 | * @param array $paging_options Keys are: |
||
| 208 | * 'per_page_default' = items per page when switching from |
||
| 209 | * full- list to per-page-view |
||
| 210 | * 'per_page' = number of items to show per page |
||
| 211 | * 'page_nr' = The page to display |
||
| 212 | * @param array $query_vars Additional variables to add in the query-string |
||
| 213 | * @param array $form_actions |
||
| 214 | * @param string $style The style that the table will show. You can set 'table' or 'grid' |
||
| 215 | * @param string $tableName |
||
| 216 | * @param string $tableId |
||
| 217 | * |
||
| 218 | * @author [email protected] |
||
| 219 | */ |
||
| 220 | public static function display_sortable_table( |
||
| 221 | $header, |
||
| 222 | $content, |
||
| 223 | $sorting_options = [], |
||
| 224 | $paging_options = [], |
||
| 225 | $query_vars = null, |
||
| 226 | $form_actions = [], |
||
| 227 | $style = 'table', |
||
| 228 | $tableName = 'tablename', |
||
| 229 | $tableId = '' |
||
| 230 | ) { |
||
| 231 | $column = $sorting_options['column'] ?? 0; |
||
| 232 | $default_items_per_page = $paging_options['per_page'] ?? 20; |
||
| 233 | $table = new SortableTableFromArray($content, $column, $default_items_per_page, $tableName, null, $tableId); |
||
| 234 | if (is_array($query_vars)) { |
||
| 235 | $table->set_additional_parameters($query_vars); |
||
| 236 | } |
||
| 237 | if ('table' === $style) { |
||
| 238 | if (is_array($header) && count($header) > 0) { |
||
| 239 | foreach ($header as $index => $header_item) { |
||
| 240 | $table->set_header( |
||
| 241 | $index, |
||
| 242 | isset($header_item[0]) ? $header_item[0] : null, |
||
| 243 | isset($header_item[1]) ? $header_item[1] : null, |
||
| 244 | isset($header_item[2]) ? $header_item[2] : null, |
||
| 245 | isset($header_item[3]) ? $header_item[3] : null |
||
| 246 | ); |
||
| 247 | } |
||
| 248 | } |
||
| 249 | $table->set_form_actions($form_actions); |
||
| 250 | $table->display(); |
||
| 251 | } else { |
||
| 252 | $table->display_grid(); |
||
| 253 | } |
||
| 254 | } |
||
| 255 | |||
| 256 | /** |
||
| 257 | * Returns an HTML table with sortable column (through complete page refresh). |
||
| 258 | * |
||
| 259 | * @param array $header |
||
| 260 | * @param array $content Array of row arrays |
||
| 261 | * @param array $sorting_options |
||
| 262 | * @param array $paging_options |
||
| 263 | * @param array $query_vars |
||
| 264 | * @param array $form_actions |
||
| 265 | * @param string $style |
||
| 266 | * |
||
| 267 | * @return string HTML string for array |
||
| 268 | */ |
||
| 269 | public static function return_sortable_table( |
||
| 270 | $header, |
||
| 271 | $content, |
||
| 272 | $sorting_options = [], |
||
| 273 | $paging_options = [], |
||
| 274 | $query_vars = null, |
||
| 275 | $form_actions = [], |
||
| 276 | $style = 'table' |
||
| 277 | ) { |
||
| 278 | ob_start(); |
||
| 279 | self::display_sortable_table( |
||
| 280 | $header, |
||
| 281 | $content, |
||
| 282 | $sorting_options, |
||
| 283 | $paging_options, |
||
| 284 | $query_vars, |
||
| 285 | $form_actions, |
||
| 286 | $style |
||
| 287 | ); |
||
| 288 | $content = ob_get_contents(); |
||
| 289 | ob_end_clean(); |
||
| 290 | |||
| 291 | return $content; |
||
| 292 | } |
||
| 293 | |||
| 294 | /** |
||
| 295 | * Shows a nice grid. |
||
| 296 | * |
||
| 297 | * @param string grid name (important to create css) |
||
| 298 | * @param array header content |
||
| 299 | * @param array array with the information to show |
||
| 300 | * @param array $paging_options Keys are: |
||
| 301 | * 'per_page_default' = items per page when switching from |
||
| 302 | * full- list to per-page-view |
||
| 303 | * 'per_page' = number of items to show per page |
||
| 304 | * 'page_nr' = The page to display |
||
| 305 | * 'hide_navigation' = true to hide the navigation |
||
| 306 | * @param array $query_vars Additional variables to add in the query-string |
||
| 307 | * @param mixed An array with bool values to know which columns show. |
||
| 308 | * i.e: $visibility_options= array(true, false) we will only show the first column |
||
| 309 | * Can be also only a bool value. TRUE: show all columns, FALSE: show nothing |
||
| 310 | */ |
||
| 311 | public static function display_sortable_grid( |
||
| 312 | $name, |
||
| 313 | $header, |
||
| 314 | $content, |
||
| 315 | $paging_options = [], |
||
| 316 | $query_vars = null, |
||
| 317 | $form_actions = [], |
||
| 318 | $visibility_options = true, |
||
| 319 | $sort_data = true, |
||
| 320 | $grid_class = [] |
||
| 321 | ) { |
||
| 322 | echo self::return_sortable_grid( |
||
| 323 | $name, |
||
| 324 | $header, |
||
| 325 | $content, |
||
| 326 | $paging_options, |
||
| 327 | $query_vars, |
||
| 328 | $form_actions, |
||
| 329 | $visibility_options, |
||
| 330 | $sort_data, |
||
| 331 | $grid_class |
||
| 332 | ); |
||
| 333 | } |
||
| 334 | |||
| 335 | /** |
||
| 336 | * Gets a nice grid in html string. |
||
| 337 | * |
||
| 338 | * @param string grid name (important to create css) |
||
| 339 | * @param array header content |
||
| 340 | * @param array array with the information to show |
||
| 341 | * @param array $paging_options Keys are: |
||
| 342 | * 'per_page_default' = items per page when switching from |
||
| 343 | * full- list to per-page-view |
||
| 344 | * 'per_page' = number of items to show per page |
||
| 345 | * 'page_nr' = The page to display |
||
| 346 | * 'hide_navigation' = true to hide the navigation |
||
| 347 | * @param array $query_vars Additional variables to add in the query-string |
||
| 348 | * @param mixed An array with bool values to know which columns show. i.e: |
||
| 349 | * $visibility_options= array(true, false) we will only show the first column |
||
| 350 | * Can be also only a bool value. TRUE: show all columns, FALSE: show nothing |
||
| 351 | * @param bool true for sorting data or false otherwise |
||
| 352 | * @param array grid classes |
||
| 353 | * |
||
| 354 | * @return string html grid |
||
| 355 | */ |
||
| 356 | public static function return_sortable_grid( |
||
| 357 | $name, |
||
| 358 | $header, |
||
| 359 | $content, |
||
| 360 | $paging_options = [], |
||
| 361 | $query_vars = null, |
||
| 362 | $form_actions = [], |
||
| 363 | $visibility_options = true, |
||
| 364 | $sort_data = true, |
||
| 365 | $grid_class = [], |
||
| 366 | $elementCount = 0 |
||
| 367 | ) { |
||
| 368 | $column = 0; |
||
| 369 | $default_items_per_page = $paging_options['per_page'] ?? 20; |
||
| 370 | $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name); |
||
| 371 | $table->total_number_of_items = (int) $elementCount; |
||
| 372 | if (is_array($query_vars)) { |
||
| 373 | $table->set_additional_parameters($query_vars); |
||
| 374 | } |
||
| 375 | |||
| 376 | return $table->display_simple_grid( |
||
| 377 | $visibility_options, |
||
| 378 | $paging_options['hide_navigation'], |
||
| 379 | $default_items_per_page, |
||
| 380 | $sort_data, |
||
| 381 | $grid_class |
||
| 382 | ); |
||
| 383 | } |
||
| 384 | |||
| 385 | /** |
||
| 386 | * Displays a table with a special configuration. |
||
| 387 | * |
||
| 388 | * @param array $header Titles for the table header |
||
| 389 | * each item in this array can contain 3 values |
||
| 390 | * - 1st element: the column title |
||
| 391 | * - 2nd element: true or false (column sortable?) |
||
| 392 | * - 3th element: additional attributes for th-tag (eg for column-width) |
||
| 393 | * - 4the element: additional attributes for the td-tags |
||
| 394 | * @param array $content 2D-array with the tables content |
||
| 395 | * @param array $sorting_options Keys are: |
||
| 396 | * 'column' = The column to use as sort-key |
||
| 397 | * 'direction' = SORT_ASC or SORT_DESC |
||
| 398 | * @param array $paging_options Keys are: |
||
| 399 | * 'per_page_default' = items per page when switching from full list to per-page-view |
||
| 400 | * 'per_page' = number of items to show per page |
||
| 401 | * 'page_nr' = The page to display |
||
| 402 | * @param array $query_vars Additional variables to add in the query-string |
||
| 403 | * @param array $column_show Array of binaries 1= show columns 0. hide a column |
||
| 404 | * @param array $column_order An array of integers that let us decide how the columns are going to be sort. |
||
| 405 | * i.e: $column_order=array('1''4','3','4'); The 2nd column will be order like the 4th column |
||
| 406 | * @param array $form_actions Set optional forms actions |
||
| 407 | * |
||
| 408 | * @author Julio Montoya |
||
| 409 | */ |
||
| 410 | public static function display_sortable_config_table( |
||
| 411 | $table_name, |
||
| 412 | $header, |
||
| 413 | $content, |
||
| 414 | $sorting_options = [], |
||
| 415 | $paging_options = [], |
||
| 416 | $query_vars = null, |
||
| 417 | $column_show = [], |
||
| 418 | $column_order = [], |
||
| 419 | $form_actions = [] |
||
| 420 | ) { |
||
| 421 | $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0; |
||
| 422 | $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20; |
||
| 423 | |||
| 424 | $table = new SortableTableFromArrayConfig( |
||
| 425 | $content, |
||
| 426 | $column, |
||
| 427 | $default_items_per_page, |
||
| 428 | $table_name, |
||
| 429 | $column_show, |
||
| 430 | $column_order |
||
| 431 | ); |
||
| 432 | |||
| 433 | if (is_array($query_vars)) { |
||
| 434 | $table->set_additional_parameters($query_vars); |
||
| 435 | } |
||
| 436 | // Show or hide the columns header |
||
| 437 | if (is_array($column_show)) { |
||
| 438 | for ($i = 0; $i < count($column_show); $i++) { |
||
| 439 | if (!empty($column_show[$i])) { |
||
| 440 | $val0 = isset($header[$i][0]) ? $header[$i][0] : null; |
||
| 441 | $val1 = isset($header[$i][1]) ? $header[$i][1] : null; |
||
| 442 | $val2 = isset($header[$i][2]) ? $header[$i][2] : null; |
||
| 443 | $val3 = isset($header[$i][3]) ? $header[$i][3] : null; |
||
| 444 | $table->set_header($i, $val0, $val1, $val2, $val3); |
||
| 445 | } |
||
| 446 | } |
||
| 447 | } |
||
| 448 | $table->set_form_actions($form_actions); |
||
| 449 | $table->display(); |
||
| 450 | } |
||
| 451 | |||
| 452 | /** |
||
| 453 | * Returns a div html string with. |
||
| 454 | * |
||
| 455 | * @param string $message |
||
| 456 | * @param string $type Example: confirm, normal, warning, error |
||
| 457 | * @param bool $filter Whether to XSS-filter or not |
||
| 458 | * |
||
| 459 | * @return string Message wrapped into an HTML div |
||
| 460 | */ |
||
| 461 | public static function return_message(string $message, string $type = 'normal', bool $filter = true): string |
||
| 462 | { |
||
| 463 | if (empty($message)) { |
||
| 464 | return ''; |
||
| 465 | } |
||
| 466 | |||
| 467 | if ($filter) { |
||
| 468 | $message = api_htmlentities( |
||
| 469 | $message, |
||
| 470 | ENT_QUOTES |
||
| 471 | ); |
||
| 472 | } |
||
| 473 | |||
| 474 | $class = ''; |
||
| 475 | switch ($type) { |
||
| 476 | case 'warning': |
||
| 477 | $class .= 'alert alert-warning'; |
||
| 478 | break; |
||
| 479 | case 'error': |
||
| 480 | $class .= 'alert alert-danger'; |
||
| 481 | break; |
||
| 482 | case 'confirmation': |
||
| 483 | case 'confirm': |
||
| 484 | case 'success': |
||
| 485 | $class .= 'alert alert-success'; |
||
| 486 | break; |
||
| 487 | case 'normal': |
||
| 488 | case 'info': |
||
| 489 | default: |
||
| 490 | $class .= 'alert alert-info'; |
||
| 491 | } |
||
| 492 | |||
| 493 | return self::div($message, ['class' => $class]); |
||
| 494 | } |
||
| 495 | |||
| 496 | /** |
||
| 497 | * Returns an encrypted mailto hyperlink. |
||
| 498 | * |
||
| 499 | * @param string e-mail |
||
| 500 | * @param string clickable text |
||
| 501 | * @param string optional, class from stylesheet |
||
| 502 | * @param bool $addExtraContent |
||
| 503 | * |
||
| 504 | * @return string encrypted mailto hyperlink |
||
| 505 | */ |
||
| 506 | public static function encrypted_mailto_link( |
||
| 507 | $email, |
||
| 508 | $clickable_text = null, |
||
| 509 | $style_class = '', |
||
| 510 | $addExtraContent = false |
||
| 511 | ) { |
||
| 512 | if (is_null($clickable_text)) { |
||
| 513 | $clickable_text = $email; |
||
| 514 | } |
||
| 515 | |||
| 516 | // "mailto:" already present? |
||
| 517 | if ('mailto:' !== substr($email, 0, 7)) { |
||
| 518 | $email = 'mailto:'.$email; |
||
| 519 | } |
||
| 520 | |||
| 521 | // Class (stylesheet) defined? |
||
| 522 | if ('' !== $style_class) { |
||
| 523 | $style_class = ' class="'.$style_class.'"'; |
||
| 524 | } |
||
| 525 | |||
| 526 | // Encrypt email |
||
| 527 | $hmail = ''; |
||
| 528 | for ($i = 0; $i < strlen($email); $i++) { |
||
| 529 | $hmail .= '&#'.ord($email[$i]).';'; |
||
| 530 | } |
||
| 531 | |||
| 532 | $value = ('true' === api_get_setting('profile.add_user_course_information_in_mailto')); |
||
| 533 | |||
| 534 | if ($value) { |
||
| 535 | if ('false' === api_get_setting('allow_email_editor')) { |
||
| 536 | $hmail .= '?'; |
||
| 537 | } |
||
| 538 | |||
| 539 | if (!api_is_anonymous()) { |
||
| 540 | $hmail .= '&subject='.Security::remove_XSS(api_get_setting('siteName')); |
||
| 541 | } |
||
| 542 | if ($addExtraContent) { |
||
| 543 | $content = ''; |
||
| 544 | if (!api_is_anonymous()) { |
||
| 545 | $userInfo = api_get_user_info(); |
||
| 546 | $content .= get_lang('User').': '.$userInfo['complete_name']."\n"; |
||
| 547 | |||
| 548 | $courseInfo = api_get_course_info(); |
||
| 549 | if (!empty($courseInfo)) { |
||
| 550 | $content .= get_lang('Course').': '; |
||
| 551 | $content .= $courseInfo['name']; |
||
| 552 | $sessionInfo = api_get_session_info(api_get_session_id()); |
||
| 553 | if (!empty($sessionInfo)) { |
||
| 554 | $content .= ' '.$sessionInfo['name'].' <br />'; |
||
| 555 | } |
||
| 556 | } |
||
| 557 | } |
||
| 558 | $hmail .= '&body='.rawurlencode($content); |
||
| 559 | } |
||
| 560 | } |
||
| 561 | |||
| 562 | $hclickable_text = ''; |
||
| 563 | // Encrypt clickable text if @ is present |
||
| 564 | if (strpos($clickable_text, '@')) { |
||
| 565 | for ($i = 0; $i < strlen($clickable_text); $i++) { |
||
| 566 | $hclickable_text .= '&#'.ord($clickable_text[$i]).';'; |
||
| 567 | } |
||
| 568 | } else { |
||
| 569 | $hclickable_text = @htmlspecialchars( |
||
| 570 | $clickable_text, |
||
| 571 | ENT_QUOTES, |
||
| 572 | api_get_system_encoding() |
||
| 573 | ); |
||
| 574 | } |
||
| 575 | // Return encrypted mailto hyperlink |
||
| 576 | return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>'; |
||
| 577 | } |
||
| 578 | |||
| 579 | /** |
||
| 580 | * Prints an <option>-list with all letters (A-Z). |
||
| 581 | * |
||
| 582 | * @todo This is English language specific implementation. |
||
| 583 | * It should be adapted for the other languages. |
||
| 584 | * |
||
| 585 | * @return string |
||
| 586 | */ |
||
| 587 | public static function get_alphabet_options($selectedLetter = '') |
||
| 588 | { |
||
| 589 | $result = ''; |
||
| 590 | for ($i = 65; $i <= 90; $i++) { |
||
| 591 | $letter = chr($i); |
||
| 592 | $result .= '<option value="'.$letter.'"'; |
||
| 593 | if ($selectedLetter == $letter) { |
||
| 594 | $result .= ' selected="selected"'; |
||
| 595 | } |
||
| 596 | $result .= '>'.$letter.'</option>'; |
||
| 597 | } |
||
| 598 | |||
| 599 | return $result; |
||
| 600 | } |
||
| 601 | |||
| 602 | /** |
||
| 603 | * Get the options withing a select box within the given values. |
||
| 604 | * |
||
| 605 | * @param int Min value |
||
| 606 | * @param int Max value |
||
| 607 | * @param int Default value |
||
| 608 | * |
||
| 609 | * @return string HTML select options |
||
| 610 | */ |
||
| 611 | public static function get_numeric_options($min, $max, $selected_num = 0) |
||
| 612 | { |
||
| 613 | $result = ''; |
||
| 614 | for ($i = $min; $i <= $max; $i++) { |
||
| 615 | $result .= '<option value="'.$i.'"'; |
||
| 616 | if (is_int($selected_num)) { |
||
| 617 | if ($selected_num == $i) { |
||
| 618 | $result .= ' selected="selected"'; |
||
| 619 | } |
||
| 620 | } |
||
| 621 | $result .= '>'.$i.'</option>'; |
||
| 622 | } |
||
| 623 | |||
| 624 | return $result; |
||
| 625 | } |
||
| 626 | |||
| 627 | /** |
||
| 628 | * Gets the path of an icon. |
||
| 629 | * |
||
| 630 | * @param string $icon |
||
| 631 | * @param int $size |
||
| 632 | * |
||
| 633 | * @return string |
||
| 634 | */ |
||
| 635 | public static function returnIconPath($icon, $size = ICON_SIZE_SMALL) |
||
| 636 | { |
||
| 637 | return self::return_icon($icon, null, null, $size, null, true, false); |
||
| 638 | } |
||
| 639 | |||
| 640 | /** |
||
| 641 | * This public function returns the htmlcode for an icon. |
||
| 642 | * |
||
| 643 | * @param string The filename of the file (in the main/img/ folder |
||
| 644 | * @param string The alt text (probably a language variable) |
||
| 645 | * @param array Additional attributes (for instance height, width, onclick, ...) |
||
| 646 | * @param int The wanted width of the icon (to be looked for in the corresponding img/icons/ folder) |
||
| 647 | * |
||
| 648 | * @return string An HTML string of the right <img> tag |
||
| 649 | * |
||
| 650 | * @author Patrick Cool <[email protected]>, Ghent University 2006 |
||
| 651 | * @author Julio Montoya 2010 Function improved, adding image constants |
||
| 652 | * @author Yannick Warnier 2011 Added size handler |
||
| 653 | * |
||
| 654 | * @version Feb 2011 |
||
| 655 | */ |
||
| 656 | public static function return_icon( |
||
| 657 | string $image, |
||
| 658 | ?string $alt_text = '', |
||
| 659 | ?array $additional_attributes = [], |
||
| 660 | ?int $size = ICON_SIZE_SMALL, |
||
| 661 | ?bool $show_text = true, |
||
| 662 | ?bool $return_only_path = false, |
||
| 663 | ?bool $loadThemeIcon = true |
||
| 664 | ) { |
||
| 665 | $code_path = api_get_path(SYS_PUBLIC_PATH); |
||
| 666 | $w_code_path = api_get_path(WEB_PUBLIC_PATH); |
||
| 667 | // The following path is checked to see if the file exists. It's |
||
| 668 | // important to use the public path (i.e. web/css/) rather than the |
||
| 669 | // internal path (/app/Resource/public/css/) because the path used |
||
| 670 | // in the end must be the public path |
||
| 671 | $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/'; |
||
| 672 | $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/'; |
||
| 673 | |||
| 674 | // Avoid issues with illegal string offset for legacy calls to this |
||
| 675 | // method with an empty string rather than null or an empty array |
||
| 676 | if (empty($additional_attributes)) { |
||
| 677 | $additional_attributes = []; |
||
| 678 | } |
||
| 679 | |||
| 680 | $image = trim($image); |
||
| 681 | |||
| 682 | if (isset($size)) { |
||
| 683 | $size = (int) $size; |
||
| 684 | } else { |
||
| 685 | $size = ICON_SIZE_SMALL; |
||
| 686 | } |
||
| 687 | |||
| 688 | $size_extra = $size.'/'; |
||
| 689 | $icon = $w_code_path.'img/'.$image; |
||
| 690 | $theme = 'themes/chamilo/icons/'; |
||
| 691 | |||
| 692 | if ($loadThemeIcon) { |
||
| 693 | // @todo with chamilo 2 code |
||
| 694 | $theme = 'themes/'.api_get_visual_theme().'/icons/'; |
||
| 695 | if (is_file($alternateCssPath.$theme.$image)) { |
||
| 696 | $icon = $alternateWebCssPath.$theme.$image; |
||
| 697 | } |
||
| 698 | // Checking the theme icons folder example: var/themes/chamilo/icons/XXX |
||
| 699 | if (is_file($alternateCssPath.$theme.$size_extra.$image)) { |
||
| 700 | $icon = $alternateWebCssPath.$theme.$size_extra.$image; |
||
| 701 | } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) { |
||
| 702 | //Checking the main/img/icons/XXX/ folder |
||
| 703 | $icon = $w_code_path.'img/icons/'.$size_extra.$image; |
||
| 704 | } |
||
| 705 | } else { |
||
| 706 | if (is_file($code_path.'img/icons/'.$size_extra.$image)) { |
||
| 707 | // Checking the main/img/icons/XXX/ folder |
||
| 708 | $icon = $w_code_path.'img/icons/'.$size_extra.$image; |
||
| 709 | } |
||
| 710 | } |
||
| 711 | |||
| 712 | if ($return_only_path) { |
||
| 713 | $svgImage = substr($image, 0, -3).'svg'; |
||
| 714 | if (is_file($code_path.$theme.'svg/'.$svgImage)) { |
||
| 715 | $icon = $w_code_path.$theme.'svg/'.$svgImage; |
||
| 716 | } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) { |
||
| 717 | $icon = $w_code_path.'img/icons/svg/'.$svgImage; |
||
| 718 | } |
||
| 719 | |||
| 720 | if (empty($additional_attributes['height'])) { |
||
| 721 | $additional_attributes['height'] = $size; |
||
| 722 | } |
||
| 723 | if (empty($additional_attributes['width'])) { |
||
| 724 | $additional_attributes['width'] = $size; |
||
| 725 | } |
||
| 726 | } |
||
| 727 | |||
| 728 | if ($return_only_path) { |
||
| 729 | return $icon; |
||
| 730 | } |
||
| 731 | |||
| 732 | $img = self::img($icon, $alt_text, $additional_attributes); |
||
| 733 | if (SHOW_TEXT_NEAR_ICONS && !empty($alt_text)) { |
||
| 734 | if ($show_text) { |
||
| 735 | $img = "$img $alt_text"; |
||
| 736 | } |
||
| 737 | } |
||
| 738 | |||
| 739 | return $img; |
||
| 740 | } |
||
| 741 | |||
| 742 | /** |
||
| 743 | * Returns the HTML code for an image. |
||
| 744 | * |
||
| 745 | * @param string $image_path the filename of the file (in the main/img/ folder |
||
| 746 | * @param ?string $alt_text the alt text (probably a language variable) |
||
| 747 | * @param ?array $additional_attributes (for instance, height, width, onclick, ...) |
||
| 748 | * @param ?bool $filterPath Optional. Whether filter the image path. Default is true |
||
| 749 | * |
||
| 750 | * @return string |
||
| 751 | * |
||
| 752 | * @author Julio Montoya 2010 |
||
| 753 | */ |
||
| 754 | public static function img( |
||
| 755 | string $image_path, |
||
| 756 | ?string $alt_text = '', |
||
| 757 | ?array $additional_attributes = null, |
||
| 758 | ?bool $filterPath = true |
||
| 759 | ): string { |
||
| 760 | if (empty($image_path)) { |
||
| 761 | return ''; |
||
| 762 | } |
||
| 763 | // Sanitizing the parameter $image_path |
||
| 764 | if ($filterPath) { |
||
| 765 | $image_path = Security::filter_img_path($image_path); |
||
| 766 | } |
||
| 767 | |||
| 768 | // alt text = the image name if there is none provided (for XHTML compliance) |
||
| 769 | if ('' == $alt_text) { |
||
| 770 | $alt_text = basename($image_path); |
||
| 771 | } |
||
| 772 | |||
| 773 | if (empty($additional_attributes)) { |
||
| 774 | $additional_attributes = []; |
||
| 775 | } |
||
| 776 | |||
| 777 | $additional_attributes['src'] = $image_path; |
||
| 778 | |||
| 779 | if (empty($additional_attributes['alt'])) { |
||
| 780 | $additional_attributes['alt'] = $alt_text; |
||
| 781 | } |
||
| 782 | if (empty($additional_attributes['title'])) { |
||
| 783 | $additional_attributes['title'] = $alt_text; |
||
| 784 | } |
||
| 785 | |||
| 786 | return self::tag('img', '', $additional_attributes); |
||
| 787 | } |
||
| 788 | |||
| 789 | /** |
||
| 790 | * Returns the HTML code for a tag (h3, h1, div, a, button), etc. |
||
| 791 | * |
||
| 792 | * @param string $tag the tag name |
||
| 793 | * @param string $content the tag's content |
||
| 794 | * @param array $additional_attributes (for instance, height, width, onclick, ...) |
||
| 795 | * |
||
| 796 | * @return string |
||
| 797 | * |
||
| 798 | * @author Julio Montoya 2010 |
||
| 799 | */ |
||
| 800 | public static function tag($tag, $content, $additional_attributes = []) |
||
| 801 | { |
||
| 802 | $attribute_list = ''; |
||
| 803 | // Managing the additional attributes |
||
| 804 | if (!empty($additional_attributes) && is_array($additional_attributes)) { |
||
| 805 | $attribute_list = ''; |
||
| 806 | foreach ($additional_attributes as $key => &$value) { |
||
| 807 | $attribute_list .= $key.'="'.$value.'" '; |
||
| 808 | } |
||
| 809 | } |
||
| 810 | //some tags don't have this </XXX> |
||
| 811 | if (in_array($tag, ['img', 'input', 'br'])) { |
||
| 812 | $return_value = '<'.$tag.' '.$attribute_list.' />'; |
||
| 813 | } else { |
||
| 814 | $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>'; |
||
| 815 | } |
||
| 816 | |||
| 817 | return $return_value; |
||
| 818 | } |
||
| 819 | |||
| 820 | /** |
||
| 821 | * Creates a URL anchor. |
||
| 822 | * |
||
| 823 | * @param string $name |
||
| 824 | * @param ?string $url |
||
| 825 | * @param ?array $attributes |
||
| 826 | * |
||
| 827 | * @return string |
||
| 828 | */ |
||
| 829 | public static function url(string $name, ?string $url, ?array $attributes = []): string |
||
| 830 | { |
||
| 831 | if (!empty($url)) { |
||
| 832 | $url = preg_replace('#&#', '&', $url); |
||
| 833 | $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8'); |
||
| 834 | $attributes['href'] = $url; |
||
| 835 | } |
||
| 836 | |||
| 837 | return self::tag('a', $name, $attributes); |
||
| 838 | } |
||
| 839 | |||
| 840 | /** |
||
| 841 | * Creates a div tag. |
||
| 842 | * |
||
| 843 | * @param string $content |
||
| 844 | * @param ?array $attributes |
||
| 845 | * |
||
| 846 | * @return string |
||
| 847 | */ |
||
| 848 | public static function div(string $content, ?array $attributes = []): string |
||
| 849 | { |
||
| 850 | return self::tag('div', $content, $attributes); |
||
| 851 | } |
||
| 852 | |||
| 853 | /** |
||
| 854 | * Creates a span tag. |
||
| 855 | */ |
||
| 856 | public static function span(string $content, ?array $attributes = []): string |
||
| 857 | { |
||
| 858 | return self::tag('span', $content, $attributes); |
||
| 859 | } |
||
| 860 | |||
| 861 | /** |
||
| 862 | * Displays an HTML input tag. |
||
| 863 | */ |
||
| 864 | public static function input($type, $name, $value, $attributes = []) |
||
| 865 | { |
||
| 866 | if (isset($type)) { |
||
| 867 | $attributes['type'] = $type; |
||
| 868 | } |
||
| 869 | if (isset($name)) { |
||
| 870 | $attributes['name'] = $name; |
||
| 871 | } |
||
| 872 | if (isset($value)) { |
||
| 873 | $attributes['value'] = $value; |
||
| 874 | } |
||
| 875 | |||
| 876 | if ('checkbox' === $type) { |
||
| 877 | $attributes['class'] ??= 'p-checkbox-input'; |
||
| 878 | } |
||
| 879 | |||
| 880 | $inputBase = self::tag('input', '', $attributes); |
||
| 881 | |||
| 882 | if ('checkbox' === $type) { |
||
| 883 | $isChecked = isset($attributes['checked']) && 'checked' === $attributes['checked']; |
||
| 884 | $compontentCheckedClass = $isChecked ? 'p-checkbox-checked' : ''; |
||
| 885 | |||
| 886 | return <<<HTML |
||
| 887 | <div class="p-checkbox p-component $compontentCheckedClass"> |
||
| 888 | $inputBase |
||
| 889 | <div class="p-checkbox-box"> |
||
| 890 | <svg class="p-icon p-checkbox-icon" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> |
||
| 891 | <path d="M4.86199 11.5948C4.78717 11.5923 4.71366 11.5745 4.64596 11.5426C4.57826 11.5107 4.51779 11.4652 4.46827 11.4091L0.753985 7.69483C0.683167 7.64891 0.623706 7.58751 0.580092 7.51525C0.536478 7.44299 0.509851 7.36177 0.502221 7.27771C0.49459 7.19366 0.506156 7.10897 0.536046 7.03004C0.565935 6.95111 0.613367 6.88 0.674759 6.82208C0.736151 6.76416 0.8099 6.72095 0.890436 6.69571C0.970973 6.67046 1.05619 6.66385 1.13966 6.67635C1.22313 6.68886 1.30266 6.72017 1.37226 6.76792C1.44186 6.81567 1.4997 6.8786 1.54141 6.95197L4.86199 10.2503L12.6397 2.49483C12.7444 2.42694 12.8689 2.39617 12.9932 2.40745C13.1174 2.41873 13.2343 2.47141 13.3251 2.55705C13.4159 2.64268 13.4753 2.75632 13.4938 2.87973C13.5123 3.00315 13.4888 3.1292 13.4271 3.23768L5.2557 11.4091C5.20618 11.4652 5.14571 11.5107 5.07801 11.5426C5.01031 11.5745 4.9368 11.5923 4.86199 11.5948Z" fill="currentColor"></path> |
||
| 892 | </svg> |
||
| 893 | </div> |
||
| 894 | </div> |
||
| 895 | HTML; |
||
| 896 | } |
||
| 897 | |||
| 898 | if ('text' === $type) { |
||
| 899 | $attributes['class'] = isset($attributes['class']) |
||
| 900 | ? $attributes['class'].' p-inputtext p-component ' |
||
| 901 | : 'p-inputtext p-component '; |
||
| 902 | } |
||
| 903 | |||
| 904 | return self::tag('input', '', $attributes); |
||
| 905 | } |
||
| 906 | |||
| 907 | /** |
||
| 908 | * Displays an HTML select tag. |
||
| 909 | */ |
||
| 910 | public static function select( |
||
| 911 | string $name, |
||
| 912 | array $values, |
||
| 913 | mixed $default = -1, |
||
| 914 | array $extra_attributes = [], |
||
| 915 | bool $show_blank_item = true, |
||
| 916 | string $blank_item_text = '' |
||
| 917 | ): string { |
||
| 918 | $html = ''; |
||
| 919 | $extra = ''; |
||
| 920 | $default_id = 'id="'.$name.'" '; |
||
| 921 | $extra_attributes = array_merge( |
||
| 922 | ['class' => 'p-select p-component p-inputwrapper p-inputwrapper-filled'], |
||
| 923 | $extra_attributes |
||
| 924 | ); |
||
| 925 | foreach ($extra_attributes as $key => $parameter) { |
||
| 926 | if ('id' == $key) { |
||
| 927 | $default_id = ''; |
||
| 928 | } |
||
| 929 | $extra .= $key.'="'.$parameter.'" '; |
||
| 930 | } |
||
| 931 | $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>'; |
||
| 932 | |||
| 933 | if ($show_blank_item) { |
||
| 934 | if (empty($blank_item_text)) { |
||
| 935 | $blank_item_text = get_lang('Select'); |
||
| 936 | } else { |
||
| 937 | $blank_item_text = Security::remove_XSS($blank_item_text); |
||
| 938 | } |
||
| 939 | $html .= self::tag( |
||
| 940 | 'option', |
||
| 941 | '-- '.$blank_item_text.' --', |
||
| 942 | ['value' => '-1'] |
||
| 943 | ); |
||
| 944 | } |
||
| 945 | if ($values) { |
||
| 946 | foreach ($values as $key => $value) { |
||
| 947 | if (is_array($value) && isset($value['name'])) { |
||
| 948 | $value = $value['name']; |
||
| 949 | } |
||
| 950 | $html .= '<option value="'.$key.'"'; |
||
| 951 | |||
| 952 | if (is_array($default)) { |
||
| 953 | foreach ($default as $item) { |
||
| 954 | if ($item == $key) { |
||
| 955 | $html .= ' selected="selected"'; |
||
| 956 | break; |
||
| 957 | } |
||
| 958 | } |
||
| 959 | } else { |
||
| 960 | if ($default == $key) { |
||
| 961 | $html .= ' selected="selected"'; |
||
| 962 | } |
||
| 963 | } |
||
| 964 | |||
| 965 | $html .= '>'.$value.'</option>'; |
||
| 966 | } |
||
| 967 | } |
||
| 968 | $html .= '</select>'; |
||
| 969 | |||
| 970 | return $html; |
||
| 971 | } |
||
| 972 | |||
| 973 | /** |
||
| 974 | * @param $name |
||
| 975 | * @param $value |
||
| 976 | * @param array $attributes |
||
| 977 | * |
||
| 978 | * @return string |
||
| 979 | */ |
||
| 980 | public static function button($name, $value, $attributes = []) |
||
| 981 | { |
||
| 982 | if (!empty($name)) { |
||
| 983 | $attributes['name'] = $name; |
||
| 984 | } |
||
| 985 | |||
| 986 | return self::tag('button', $value, $attributes); |
||
| 987 | } |
||
| 988 | |||
| 989 | /** |
||
| 990 | * Creates a tab menu |
||
| 991 | * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css |
||
| 992 | * in the $htmlHeadXtra variable before the display_header |
||
| 993 | * Add this script. |
||
| 994 | * |
||
| 995 | * @param array $headers list of the tab titles |
||
| 996 | * @param array $items |
||
| 997 | * @param string $id id of the container of the tab in the example "tabs" |
||
| 998 | * @param array $attributes for the ul |
||
| 999 | * @param array $ul_attributes |
||
| 1000 | * @param string $selected |
||
| 1001 | * |
||
| 1002 | * @return string |
||
| 1003 | */ |
||
| 1004 | public static function tabs( |
||
| 1005 | $headers, |
||
| 1006 | $items, |
||
| 1007 | $id = 'tabs', |
||
| 1008 | $attributes = [], |
||
| 1009 | $ul_attributes = [], |
||
| 1010 | $selected = '' |
||
| 1011 | ) { |
||
| 1012 | if (empty($headers) || 0 === count($headers)) { |
||
| 1013 | return ''; |
||
| 1014 | } |
||
| 1015 | |||
| 1016 | // --------------------------------------------------------------------- |
||
| 1017 | // Build tab headers |
||
| 1018 | // --------------------------------------------------------------------- |
||
| 1019 | $lis = ''; |
||
| 1020 | $i = 1; |
||
| 1021 | foreach ($headers as $item) { |
||
| 1022 | $isActive = (empty($selected) && 1 === $i) || (!empty($selected) && (int) $selected === $i); |
||
| 1023 | $activeClass = $isActive ? ' active' : ''; |
||
| 1024 | $ariaSelected = $isActive ? 'true' : 'false'; |
||
| 1025 | |||
| 1026 | $item = self::tag( |
||
| 1027 | 'a', |
||
| 1028 | $item, |
||
| 1029 | [ |
||
| 1030 | 'href' => 'javascript:void(0)', |
||
| 1031 | 'class' => 'nav-item nav-link text-primary'.$activeClass, |
||
| 1032 | '@click' => "openTab = $i", |
||
| 1033 | 'id' => $id.$i.'-tab', |
||
| 1034 | 'data-toggle' => 'tab', |
||
| 1035 | 'role' => 'tab', |
||
| 1036 | 'aria-controls' => $id.'-'.$i, |
||
| 1037 | 'aria-selected' => $ariaSelected, |
||
| 1038 | ] |
||
| 1039 | ); |
||
| 1040 | |||
| 1041 | $lis .= $item; |
||
| 1042 | $i++; |
||
| 1043 | } |
||
| 1044 | |||
| 1045 | $ul = self::tag( |
||
| 1046 | 'nav', |
||
| 1047 | $lis, |
||
| 1048 | [ |
||
| 1049 | 'id' => 'nav_'.$id, |
||
| 1050 | 'class' => 'nav nav-tabs bg-white px-3 pt-3 border-bottom-0', |
||
| 1051 | 'role' => 'tablist', |
||
| 1052 | ] |
||
| 1053 | ); |
||
| 1054 | |||
| 1055 | // --------------------------------------------------------------------- |
||
| 1056 | // Build tab contents |
||
| 1057 | // --------------------------------------------------------------------- |
||
| 1058 | $i = 1; |
||
| 1059 | $divs = ''; |
||
| 1060 | foreach ($items as $content) { |
||
| 1061 | $isActive = (empty($selected) && 1 === $i) || (!empty($selected) && (int) $selected === $i); |
||
| 1062 | $panelClass = 'tab-panel'; |
||
| 1063 | if ($isActive) { |
||
| 1064 | $panelClass .= ' is-active'; |
||
| 1065 | } |
||
| 1066 | |||
| 1067 | $divs .= self::tag( |
||
| 1068 | 'div', |
||
| 1069 | $content, |
||
| 1070 | [ |
||
| 1071 | 'id' => $id.'-'.$i, |
||
| 1072 | 'x-show' => "openTab === $i", |
||
| 1073 | 'class' => $panelClass, |
||
| 1074 | ] |
||
| 1075 | ); |
||
| 1076 | $i++; |
||
| 1077 | } |
||
| 1078 | |||
| 1079 | // Wrapper for contents: white background, gray border, padding |
||
| 1080 | $contentWrapper = self::tag( |
||
| 1081 | 'div', |
||
| 1082 | $divs, |
||
| 1083 | [ |
||
| 1084 | 'class' => 'tab-content bg-white border border-gray-25 rounded-bottom px-3 py-3 mt-2', |
||
| 1085 | ] |
||
| 1086 | ); |
||
| 1087 | |||
| 1088 | // --------------------------------------------------------------------- |
||
| 1089 | // Outer wrapper |
||
| 1090 | // --------------------------------------------------------------------- |
||
| 1091 | $attributes['id'] = (string) $id; |
||
| 1092 | if (empty($attributes['class'])) { |
||
| 1093 | $attributes['class'] = ''; |
||
| 1094 | } |
||
| 1095 | // Shadow, rounded corners, small top margin |
||
| 1096 | $attributes['class'] .= ' tab_wrapper shadow-sm rounded mt-3'; |
||
| 1097 | |||
| 1098 | $initialTab = !empty($selected) ? (int) $selected : 1; |
||
| 1099 | $attributes['x-data'] = '{ openTab: '.$initialTab.' }'; |
||
| 1100 | |||
| 1101 | return self::tag( |
||
| 1102 | 'div', |
||
| 1103 | $ul.$contentWrapper, |
||
| 1104 | $attributes |
||
| 1105 | ); |
||
| 1106 | } |
||
| 1107 | |||
| 1108 | /** |
||
| 1109 | * @param $headers |
||
| 1110 | * @param null $selected |
||
| 1111 | * |
||
| 1112 | * @return string |
||
| 1113 | */ |
||
| 1114 | public static function tabsOnlyLink($headers, $selected = null, string $tabList = '') |
||
| 1115 | { |
||
| 1116 | $id = uniqid('tabs_'); |
||
| 1117 | $list = ''; |
||
| 1118 | |||
| 1119 | if ('integer' === gettype($selected)) { |
||
| 1120 | $selected -= 1; |
||
| 1121 | } |
||
| 1122 | |||
| 1123 | foreach ($headers as $key => $item) { |
||
| 1124 | $class = null; |
||
| 1125 | if ($key == $selected) { |
||
| 1126 | $class = 'active'; |
||
| 1127 | } |
||
| 1128 | $item = self::tag( |
||
| 1129 | 'a', |
||
| 1130 | $item['content'], |
||
| 1131 | [ |
||
| 1132 | 'id' => $id.'-'.$key, |
||
| 1133 | 'href' => $item['url'], |
||
| 1134 | 'class' => 'nav-link '.$class, |
||
| 1135 | ] |
||
| 1136 | ); |
||
| 1137 | $list .= '<li class="nav-item">'.$item.'</li>'; |
||
| 1138 | } |
||
| 1139 | |||
| 1140 | return self::div( |
||
| 1141 | self::tag( |
||
| 1142 | 'ul', |
||
| 1143 | $list, |
||
| 1144 | ['class' => 'nav nav-tabs'] |
||
| 1145 | ), |
||
| 1146 | ['class' => "ul-tablist $tabList"] |
||
| 1147 | ); |
||
| 1148 | } |
||
| 1149 | |||
| 1150 | /** |
||
| 1151 | * In order to display a grid using jqgrid you have to:. |
||
| 1152 | * |
||
| 1153 | * @example |
||
| 1154 | * After your Display::display_header function you have to add the nex javascript code: |
||
| 1155 | * <script> |
||
| 1156 | * echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]); |
||
| 1157 | * // for more information of this function check the grid_js() function |
||
| 1158 | * </script> |
||
| 1159 | * //Then you have to call the grid_html |
||
| 1160 | * echo Display::grid_html('my_grid_name'); |
||
| 1161 | * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work |
||
| 1162 | * |
||
| 1163 | * @param string the div id, this value must be the same with the first parameter of Display::grid_js() |
||
| 1164 | * |
||
| 1165 | * @return string html |
||
| 1166 | */ |
||
| 1167 | public static function grid_html($div_id) |
||
| 1168 | { |
||
| 1169 | $table = self::tag('table', '', ['id' => $div_id]); |
||
| 1170 | $table .= self::tag('div', '', ['id' => $div_id.'_pager']); |
||
| 1171 | |||
| 1172 | return $table; |
||
| 1173 | } |
||
| 1174 | |||
| 1175 | /** |
||
| 1176 | * This is a wrapper to use the jqgrid in Chamilo. |
||
| 1177 | * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options |
||
| 1178 | * This function need to be in the ready jquery function |
||
| 1179 | * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> } |
||
| 1180 | * In order to work this function needs the Display::grid_html function with the same div id. |
||
| 1181 | * |
||
| 1182 | * @param string $div_id div id |
||
| 1183 | * @param string $url url where the jqgrid will ask for data (if datatype = json) |
||
| 1184 | * @param array $column_names Visible columns (you should use get_lang). |
||
| 1185 | * An array in which we place the names of the columns. |
||
| 1186 | * This is the text that appears in the head of the grid (Header layer). |
||
| 1187 | * Example: colname {name:'date', index:'date', width:120, align:'right'}, |
||
| 1188 | * @param array $column_model the column model : Array which describes the parameters of the columns. |
||
| 1189 | * This is the most important part of the grid. |
||
| 1190 | * For a full description of all valid values see colModel API. See the url above. |
||
| 1191 | * @param array $extra_params extra parameters |
||
| 1192 | * @param array $data data that will be loaded |
||
| 1193 | * @param string $formatter A string that will be appended to the JSON returned |
||
| 1194 | * @param bool $fixed_width not implemented yet |
||
| 1195 | * |
||
| 1196 | * @return string the js code |
||
| 1197 | */ |
||
| 1198 | public static function grid_js( |
||
| 1199 | $div_id, |
||
| 1200 | $url, |
||
| 1201 | $column_names, |
||
| 1202 | $column_model, |
||
| 1203 | $extra_params, |
||
| 1204 | $data = [], |
||
| 1205 | $formatter = '', |
||
| 1206 | $fixed_width = false |
||
| 1207 | ) { |
||
| 1208 | $obj = new stdClass(); |
||
| 1209 | $obj->first = 'first'; |
||
| 1210 | |||
| 1211 | if (!empty($url)) { |
||
| 1212 | $obj->url = $url; |
||
| 1213 | } |
||
| 1214 | |||
| 1215 | // Needed it in order to render the links/html in the grid |
||
| 1216 | foreach ($column_model as &$columnModel) { |
||
| 1217 | if (!isset($columnModel['formatter'])) { |
||
| 1218 | $columnModel['formatter'] = ''; |
||
| 1219 | } |
||
| 1220 | } |
||
| 1221 | |||
| 1222 | //This line should only be used/modified in case of having characters |
||
| 1223 | // encoding problems - see #6159 |
||
| 1224 | //$column_names = array_map("utf8_encode", $column_names); |
||
| 1225 | $obj->colNames = $column_names; |
||
| 1226 | $obj->colModel = $column_model; |
||
| 1227 | $obj->pager = '#'.$div_id.'_pager'; |
||
| 1228 | $obj->datatype = 'json'; |
||
| 1229 | $obj->viewrecords = 'true'; |
||
| 1230 | $obj->guiStyle = 'bootstrap4'; |
||
| 1231 | $obj->iconSet = 'materialDesignIcons'; |
||
| 1232 | $all_value = 10000000; |
||
| 1233 | |||
| 1234 | // Sets how many records we want to view in the grid |
||
| 1235 | $obj->rowNum = 20; |
||
| 1236 | |||
| 1237 | // Default row quantity |
||
| 1238 | if (!isset($extra_params['rowList'])) { |
||
| 1239 | $defaultRowList = [20, 50, 100, 500, 1000, $all_value]; |
||
| 1240 | $rowList = api_get_setting('display.table_row_list', true); |
||
| 1241 | if (is_array($rowList) && isset($rowList['options']) && is_array($rowList['options'])) { |
||
| 1242 | $rowList = $rowList['options']; |
||
| 1243 | $rowList[] = $all_value; |
||
| 1244 | } else { |
||
| 1245 | $rowList = $defaultRowList; |
||
| 1246 | } |
||
| 1247 | $extra_params['rowList'] = $rowList; |
||
| 1248 | } |
||
| 1249 | |||
| 1250 | $defaultRow = (int) api_get_setting('display.table_default_row'); |
||
| 1251 | if ($defaultRow > 0) { |
||
| 1252 | $obj->rowNum = $defaultRow; |
||
| 1253 | } |
||
| 1254 | |||
| 1255 | $json = ''; |
||
| 1256 | if (!empty($extra_params['datatype'])) { |
||
| 1257 | $obj->datatype = $extra_params['datatype']; |
||
| 1258 | } |
||
| 1259 | |||
| 1260 | // Row even odd style. |
||
| 1261 | $obj->altRows = true; |
||
| 1262 | if (!empty($extra_params['altRows'])) { |
||
| 1263 | $obj->altRows = $extra_params['altRows']; |
||
| 1264 | } |
||
| 1265 | |||
| 1266 | if (!empty($extra_params['sortname'])) { |
||
| 1267 | $obj->sortname = $extra_params['sortname']; |
||
| 1268 | } |
||
| 1269 | |||
| 1270 | if (!empty($extra_params['sortorder'])) { |
||
| 1271 | $obj->sortorder = $extra_params['sortorder']; |
||
| 1272 | } |
||
| 1273 | |||
| 1274 | if (!empty($extra_params['rowList'])) { |
||
| 1275 | $obj->rowList = $extra_params['rowList']; |
||
| 1276 | } |
||
| 1277 | |||
| 1278 | if (!empty($extra_params['rowNum'])) { |
||
| 1279 | $obj->rowNum = $extra_params['rowNum']; |
||
| 1280 | } else { |
||
| 1281 | // Try to load max rows from Session |
||
| 1282 | $urlInfo = parse_url($url); |
||
| 1283 | if (isset($urlInfo['query'])) { |
||
| 1284 | parse_str($urlInfo['query'], $query); |
||
| 1285 | if (isset($query['a'])) { |
||
| 1286 | $action = $query['a']; |
||
| 1287 | // This value is set in model.ajax.php |
||
| 1288 | $savedRows = Session::read('max_rows_'.$action); |
||
| 1289 | if (!empty($savedRows)) { |
||
| 1290 | $obj->rowNum = $savedRows; |
||
| 1291 | } |
||
| 1292 | } |
||
| 1293 | } |
||
| 1294 | } |
||
| 1295 | |||
| 1296 | if (!empty($extra_params['viewrecords'])) { |
||
| 1297 | $obj->viewrecords = $extra_params['viewrecords']; |
||
| 1298 | } |
||
| 1299 | |||
| 1300 | $beforeSelectRow = null; |
||
| 1301 | if (isset($extra_params['beforeSelectRow'])) { |
||
| 1302 | $beforeSelectRow = 'beforeSelectRow: '.$extra_params['beforeSelectRow'].', '; |
||
| 1303 | unset($extra_params['beforeSelectRow']); |
||
| 1304 | } |
||
| 1305 | |||
| 1306 | $beforeProcessing = ''; |
||
| 1307 | if (isset($extra_params['beforeProcessing'])) { |
||
| 1308 | $beforeProcessing = 'beforeProcessing : function() { '.$extra_params['beforeProcessing'].' },'; |
||
| 1309 | unset($extra_params['beforeProcessing']); |
||
| 1310 | } |
||
| 1311 | |||
| 1312 | $beforeRequest = ''; |
||
| 1313 | if (isset($extra_params['beforeRequest'])) { |
||
| 1314 | $beforeRequest = 'beforeRequest : function() { '.$extra_params['beforeRequest'].' },'; |
||
| 1315 | unset($extra_params['beforeRequest']); |
||
| 1316 | } |
||
| 1317 | |||
| 1318 | $gridComplete = ''; |
||
| 1319 | if (isset($extra_params['gridComplete'])) { |
||
| 1320 | $gridComplete = 'gridComplete : function() { '.$extra_params['gridComplete'].' },'; |
||
| 1321 | unset($extra_params['gridComplete']); |
||
| 1322 | } |
||
| 1323 | |||
| 1324 | // Adding extra params |
||
| 1325 | if (!empty($extra_params)) { |
||
| 1326 | foreach ($extra_params as $key => $element) { |
||
| 1327 | // the groupHeaders key gets a special treatment |
||
| 1328 | if ('groupHeaders' != $key) { |
||
| 1329 | $obj->$key = $element; |
||
| 1330 | } |
||
| 1331 | } |
||
| 1332 | } |
||
| 1333 | |||
| 1334 | // Adding static data. |
||
| 1335 | if (!empty($data)) { |
||
| 1336 | $data_var = $div_id.'_data'; |
||
| 1337 | $json .= ' var '.$data_var.' = '.json_encode($data).';'; |
||
| 1338 | $obj->data = $data_var; |
||
| 1339 | $obj->datatype = 'local'; |
||
| 1340 | $json .= "\n"; |
||
| 1341 | } |
||
| 1342 | |||
| 1343 | $obj->end = 'end'; |
||
| 1344 | |||
| 1345 | $json_encode = json_encode($obj); |
||
| 1346 | |||
| 1347 | if (!empty($data)) { |
||
| 1348 | //Converts the "data":"js_variable" to "data":js_variable, |
||
| 1349 | // otherwise it will not work |
||
| 1350 | $json_encode = str_replace('"data":"'.$data_var.'"', '"data":'.$data_var.'', $json_encode); |
||
| 1351 | } |
||
| 1352 | |||
| 1353 | // Fixing true/false js values that doesn't need the "" |
||
| 1354 | $json_encode = str_replace(':"true"', ':true', $json_encode); |
||
| 1355 | // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text |
||
| 1356 | $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode); |
||
| 1357 | $json_encode = str_replace(':"false"', ':false', $json_encode); |
||
| 1358 | $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode); |
||
| 1359 | $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode); |
||
| 1360 | $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode); |
||
| 1361 | |||
| 1362 | if (('true' === api_get_setting('work.allow_compilatio_tool')) && |
||
| 1363 | (false !== strpos($_SERVER['REQUEST_URI'], 'work/work.php') || |
||
| 1364 | false != strpos($_SERVER['REQUEST_URI'], 'work/work_list_all.php') |
||
| 1365 | ) |
||
| 1366 | ) { |
||
| 1367 | $json_encode = str_replace('"function () { compilatioInit() }"', |
||
| 1368 | 'function () { compilatioInit() }', |
||
| 1369 | $json_encode |
||
| 1370 | ); |
||
| 1371 | } |
||
| 1372 | // Creating the jqgrid element. |
||
| 1373 | $json .= '$("#'.$div_id.'").jqGrid({'; |
||
| 1374 | $json .= "autowidth: true,"; |
||
| 1375 | //$json .= $beforeSelectRow; |
||
| 1376 | $json .= $gridComplete; |
||
| 1377 | $json .= $beforeProcessing; |
||
| 1378 | $json .= $beforeRequest; |
||
| 1379 | $json .= $json_encode; |
||
| 1380 | $json .= '});'; |
||
| 1381 | |||
| 1382 | // Grouping headers option |
||
| 1383 | if (isset($extra_params['groupHeaders'])) { |
||
| 1384 | $groups = ''; |
||
| 1385 | foreach ($extra_params['groupHeaders'] as $group) { |
||
| 1386 | //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" }, |
||
| 1387 | $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },'; |
||
| 1388 | } |
||
| 1389 | $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", { |
||
| 1390 | "useColSpanStyle" : false, |
||
| 1391 | "groupHeaders" : [ |
||
| 1392 | '.$groups.' |
||
| 1393 | ] |
||
| 1394 | });'; |
||
| 1395 | } |
||
| 1396 | |||
| 1397 | $all_text = addslashes(get_lang('All')); |
||
| 1398 | $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");'; |
||
| 1399 | $json .= "\n"; |
||
| 1400 | // Adding edit/delete icons. |
||
| 1401 | $json .= $formatter; |
||
| 1402 | |||
| 1403 | return $json; |
||
| 1404 | } |
||
| 1405 | |||
| 1406 | /** |
||
| 1407 | * @param array $headers |
||
| 1408 | * @param array $rows |
||
| 1409 | * @param array $attributes |
||
| 1410 | * |
||
| 1411 | * @return string |
||
| 1412 | */ |
||
| 1413 | public static function table($headers, $rows, $attributes = []) |
||
| 1414 | { |
||
| 1415 | if (empty($attributes)) { |
||
| 1416 | $attributes['class'] = 'data_table'; |
||
| 1417 | } |
||
| 1418 | $table = new HTML_Table($attributes); |
||
| 1419 | $row = 0; |
||
| 1420 | $column = 0; |
||
| 1421 | |||
| 1422 | // Course headers |
||
| 1423 | if (!empty($headers)) { |
||
| 1424 | foreach ($headers as $item) { |
||
| 1425 | $table->setHeaderContents($row, $column, $item); |
||
| 1426 | $column++; |
||
| 1427 | } |
||
| 1428 | $row = 1; |
||
| 1429 | $column = 0; |
||
| 1430 | } |
||
| 1431 | |||
| 1432 | if (!empty($rows)) { |
||
| 1433 | foreach ($rows as $content) { |
||
| 1434 | $table->setCellContents($row, $column, $content); |
||
| 1435 | $row++; |
||
| 1436 | } |
||
| 1437 | } |
||
| 1438 | |||
| 1439 | return $table->toHtml(); |
||
| 1440 | } |
||
| 1441 | |||
| 1442 | /** |
||
| 1443 | * Get the session box details as an array. |
||
| 1444 | * |
||
| 1445 | * @todo check session visibility. |
||
| 1446 | * |
||
| 1447 | * @param int $session_id |
||
| 1448 | * |
||
| 1449 | * @return array Empty array or session array |
||
| 1450 | * ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int] |
||
| 1451 | */ |
||
| 1452 | public static function getSessionTitleBox($session_id) |
||
| 1453 | { |
||
| 1454 | $session_info = api_get_session_info($session_id); |
||
| 1455 | $generalCoachesNames = implode( |
||
| 1456 | ' - ', |
||
| 1457 | SessionManager::getGeneralCoachesNamesForSession($session_id) |
||
| 1458 | ); |
||
| 1459 | |||
| 1460 | $session = []; |
||
| 1461 | $session['category_id'] = $session_info['session_category_id']; |
||
| 1462 | $session['title'] = $session_info['name']; |
||
| 1463 | $session['dates'] = ''; |
||
| 1464 | $session['coach'] = ''; |
||
| 1465 | if ('true' === api_get_setting('show_session_coach') && $generalCoachesNames) { |
||
| 1466 | $session['coach'] = get_lang('General coach').': '.$generalCoachesNames; |
||
| 1467 | } |
||
| 1468 | $active = false; |
||
| 1469 | if (('0000-00-00 00:00:00' === $session_info['access_end_date'] && |
||
| 1470 | '0000-00-00 00:00:00' === $session_info['access_start_date']) || |
||
| 1471 | (empty($session_info['access_end_date']) && empty($session_info['access_start_date'])) |
||
| 1472 | ) { |
||
| 1473 | if (isset($session_info['duration']) && !empty($session_info['duration'])) { |
||
| 1474 | $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id()); |
||
| 1475 | $session['duration'] = $daysLeft >= 0 |
||
| 1476 | ? sprintf(get_lang('This session has a maximum duration. Only %s days to go.'), $daysLeft) |
||
| 1477 | : get_lang('You are already registered but your allowed access time has expired.'); |
||
| 1478 | } |
||
| 1479 | $active = true; |
||
| 1480 | } else { |
||
| 1481 | $dates = SessionManager::parseSessionDates($session_info, true); |
||
| 1482 | $session['dates'] = $dates['access']; |
||
| 1483 | //$active = $date_start <= $now && $date_end >= $now; |
||
| 1484 | } |
||
| 1485 | $session['active'] = $active; |
||
| 1486 | $session['session_category_id'] = $session_info['session_category_id']; |
||
| 1487 | $session['visibility'] = $session_info['visibility']; |
||
| 1488 | $session['num_users'] = $session_info['nbr_users']; |
||
| 1489 | $session['num_courses'] = $session_info['nbr_courses']; |
||
| 1490 | $session['description'] = $session_info['description']; |
||
| 1491 | $session['show_description'] = $session_info['show_description']; |
||
| 1492 | //$session['image'] = SessionManager::getSessionImage($session_info['id']); |
||
| 1493 | $session['url'] = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$session_info['id']; |
||
| 1494 | |||
| 1495 | $entityManager = Database::getManager(); |
||
| 1496 | $fieldValuesRepo = $entityManager->getRepository(ExtraFieldValues::class); |
||
| 1497 | $extraFieldValues = $fieldValuesRepo->getVisibleValues( |
||
| 1498 | ExtraField::SESSION_FIELD_TYPE, |
||
| 1499 | $session_id |
||
| 1500 | ); |
||
| 1501 | |||
| 1502 | $session['extra_fields'] = []; |
||
| 1503 | /** @var ExtraFieldValues $value */ |
||
| 1504 | foreach ($extraFieldValues as $value) { |
||
| 1505 | if (empty($value)) { |
||
| 1506 | continue; |
||
| 1507 | } |
||
| 1508 | $session['extra_fields'][] = [ |
||
| 1509 | 'field' => [ |
||
| 1510 | 'variable' => $value->getField()->getVariable(), |
||
| 1511 | 'display_text' => $value->getField()->getDisplayText(), |
||
| 1512 | ], |
||
| 1513 | 'value' => $value->getFieldValue(), |
||
| 1514 | ]; |
||
| 1515 | } |
||
| 1516 | |||
| 1517 | return $session; |
||
| 1518 | } |
||
| 1519 | |||
| 1520 | /** |
||
| 1521 | * Return the five star HTML. |
||
| 1522 | * |
||
| 1523 | * @param string $id of the rating ul element |
||
| 1524 | * @param string $url that will be added (for jquery see hot_courses.tpl) |
||
| 1525 | * @param array $point_info point info array see function CourseManager::get_course_ranking() |
||
| 1526 | * @param bool $add_div_wrapper add a div wrapper |
||
| 1527 | * |
||
| 1528 | * @return string |
||
| 1529 | */ |
||
| 1530 | public static function return_rating_system( |
||
| 1531 | $id, |
||
| 1532 | $url, |
||
| 1533 | $point_info = [], |
||
| 1534 | $add_div_wrapper = true |
||
| 1535 | ) { |
||
| 1536 | $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null; |
||
| 1537 | $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0; |
||
| 1538 | |||
| 1539 | if (!empty($percentage)) { |
||
| 1540 | $percentage = $percentage * 125 / 100; |
||
| 1541 | } |
||
| 1542 | $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0; |
||
| 1543 | $star_label = sprintf(get_lang('%s stars out of 5'), $point_info['point_average_star']); |
||
| 1544 | |||
| 1545 | $html = '<section class="rating-widget">'; |
||
| 1546 | $html .= '<div class="rating-stars"><ul id="stars">'; |
||
| 1547 | $html .= '<li class="star" data-link="'.$url.'&star=1" title="Poor" data-value="1"><i class="fa fa-star fa-fw"></i></li> |
||
| 1548 | <li class="star" data-link="'.$url.'&star=2" title="Fair" data-value="2"><i class="fa fa-star fa-fw"></i></li> |
||
| 1549 | <li class="star" data-link="'.$url.'&star=3" title="Good" data-value="3"><i class="fa fa-star fa-fw"></i></li> |
||
| 1550 | <li class="star" data-link="'.$url.'&star=4" title="Excellent" data-value="4"><i class="fa fa-star fa-fw"></i></li> |
||
| 1551 | <li class="star" data-link="'.$url.'&star=5" title="WOW!!!" data-value="5"><i class="fa fa-star fa-fw"></i></li> |
||
| 1552 | '; |
||
| 1553 | $html .= '</ul></div>'; |
||
| 1554 | $html .= '</section>'; |
||
| 1555 | $labels = []; |
||
| 1556 | |||
| 1557 | $labels[] = 1 == $number_of_users_who_voted ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes'); |
||
| 1558 | $labels[] = 1 == $accesses ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits'); |
||
| 1559 | $labels[] = $point_info['user_vote'] ? get_lang('Your vote').' ['.$point_info['user_vote'].']' : get_lang('Your vote').' [?] '; |
||
| 1560 | |||
| 1561 | if (!$add_div_wrapper && api_is_anonymous()) { |
||
| 1562 | $labels[] = self::tag('span', get_lang('Login to vote'), ['class' => 'error']); |
||
| 1563 | } |
||
| 1564 | |||
| 1565 | $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']); |
||
| 1566 | $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]); |
||
| 1567 | |||
| 1568 | if ($add_div_wrapper) { |
||
| 1569 | $html = self::div($html, ['id' => 'rating_wrapper_'.$id]); |
||
| 1570 | } |
||
| 1571 | |||
| 1572 | return $html; |
||
| 1573 | } |
||
| 1574 | |||
| 1575 | /** |
||
| 1576 | * @param string $title |
||
| 1577 | * @param string $second_title |
||
| 1578 | * @param string $size |
||
| 1579 | * @param bool $filter |
||
| 1580 | * |
||
| 1581 | * @return string |
||
| 1582 | */ |
||
| 1583 | public static function page_header($title, $second_title = null, $size = 'h2', $filter = true) |
||
| 1584 | { |
||
| 1585 | if ($filter) { |
||
| 1586 | $title = Security::remove_XSS($title); |
||
| 1587 | } |
||
| 1588 | |||
| 1589 | if (!empty($second_title)) { |
||
| 1590 | if ($filter) { |
||
| 1591 | $second_title = Security::remove_XSS($second_title); |
||
| 1592 | } |
||
| 1593 | $title .= "<small> $second_title</small>"; |
||
| 1594 | } |
||
| 1595 | |||
| 1596 | return '<div class="page-header section-header mb-6"><'.$size.' class="section-header__title">'.$title.'</'.$size.'></div>'; |
||
| 1597 | } |
||
| 1598 | |||
| 1599 | public static function page_header_and_translate($title, $second_title = null) |
||
| 1600 | { |
||
| 1601 | $title = get_lang($title); |
||
| 1602 | |||
| 1603 | return self::page_header($title, $second_title); |
||
| 1604 | } |
||
| 1605 | |||
| 1606 | public static function page_subheader($title, $second_title = null, $size = 'h3', $attributes = []) |
||
| 1607 | { |
||
| 1608 | if (!empty($second_title)) { |
||
| 1609 | $second_title = Security::remove_XSS($second_title); |
||
| 1610 | $title .= "<small> $second_title<small>"; |
||
| 1611 | } |
||
| 1612 | $subTitle = self::tag($size, Security::remove_XSS($title), $attributes); |
||
| 1613 | |||
| 1614 | return $subTitle; |
||
| 1615 | } |
||
| 1616 | |||
| 1617 | public static function page_subheader2($title, $second_title = null) |
||
| 1618 | { |
||
| 1619 | return self::page_header($title, $second_title, 'h4'); |
||
| 1620 | } |
||
| 1621 | |||
| 1622 | public static function page_subheader3($title, $second_title = null) |
||
| 1623 | { |
||
| 1624 | return self::page_header($title, $second_title, 'h5'); |
||
| 1625 | } |
||
| 1626 | |||
| 1627 | public static function description(array $list): string |
||
| 1628 | { |
||
| 1629 | $html = ''; |
||
| 1630 | if (!empty($list)) { |
||
| 1631 | $html = '<dl class="dl-horizontal">'; |
||
| 1632 | foreach ($list as $item) { |
||
| 1633 | $html .= '<dt>'.$item['title'].'</dt>'; |
||
| 1634 | $html .= '<dd>'.$item['content'].'</dd>'; |
||
| 1635 | } |
||
| 1636 | $html .= '</dl>'; |
||
| 1637 | } |
||
| 1638 | |||
| 1639 | return $html; |
||
| 1640 | } |
||
| 1641 | |||
| 1642 | /** |
||
| 1643 | * @param int $percentage int value between 0 and 100 |
||
| 1644 | * @param bool $show_percentage |
||
| 1645 | * @param string $extra_info |
||
| 1646 | * @param string $class danger/success/infowarning |
||
| 1647 | * |
||
| 1648 | * @return string |
||
| 1649 | */ |
||
| 1650 | public static function bar_progress($percentage, $show_percentage = true, $extra_info = '', $class = '') |
||
| 1651 | { |
||
| 1652 | $percentage = (int) $percentage; |
||
| 1653 | $class = empty($class) ? '' : "progress-bar-$class"; |
||
| 1654 | |||
| 1655 | $div = '<div class="progress"> |
||
| 1656 | <div |
||
| 1657 | class="progress-bar progress-bar-striped '.$class.'" |
||
| 1658 | role="progressbar" |
||
| 1659 | aria-valuenow="'.$percentage.'" |
||
| 1660 | aria-valuemin="0" |
||
| 1661 | aria-valuemax="100" |
||
| 1662 | style="width: '.$percentage.'%;" |
||
| 1663 | >'; |
||
| 1664 | if ($show_percentage) { |
||
| 1665 | $div .= $percentage.'%'; |
||
| 1666 | } else { |
||
| 1667 | if (!empty($extra_info)) { |
||
| 1668 | $div .= $extra_info; |
||
| 1669 | } |
||
| 1670 | } |
||
| 1671 | $div .= '</div></div>'; |
||
| 1672 | |||
| 1673 | return $div; |
||
| 1674 | } |
||
| 1675 | |||
| 1676 | /** |
||
| 1677 | * @param array $badge_list |
||
| 1678 | * |
||
| 1679 | * @return string |
||
| 1680 | */ |
||
| 1681 | public static function badgeGroup($list) |
||
| 1690 | } |
||
| 1691 | |||
| 1692 | /** |
||
| 1693 | * Return an HTML span element with the badge class and an additional bg-$type class |
||
| 1694 | */ |
||
| 1695 | public static function label(string $content, string $type = 'default'): string |
||
| 1696 | { |
||
| 1697 | $html = ''; |
||
| 1698 | if (!empty($content)) { |
||
| 1699 | $class = match ($type) { |
||
| 1700 | 'success' => 'success', |
||
| 1701 | 'warning' => 'warning', |
||
| 1702 | 'important', 'danger', 'error' => 'error', |
||
| 1703 | 'info' => 'info', |
||
| 1704 | 'primary' => 'primary', |
||
| 1705 | default => 'secondary', |
||
| 1706 | }; |
||
| 1707 | |||
| 1708 | $html = '<span class="badge badge--'.$class.'">'; |
||
| 1709 | $html .= $content; |
||
| 1710 | $html .= '</span>'; |
||
| 1711 | } |
||
| 1712 | |||
| 1713 | return $html; |
||
| 1714 | } |
||
| 1715 | |||
| 1716 | public static function actions(array $items): string |
||
| 1717 | { |
||
| 1718 | if (empty($items)) { |
||
| 1719 | return ''; |
||
| 1720 | } |
||
| 1721 | |||
| 1722 | $links = ''; |
||
| 1723 | foreach ($items as $value) { |
||
| 1724 | $attributes = $value['url_attributes'] ?? []; |
||
| 1725 | $links .= self::url($value['content'], $value['url'], $attributes); |
||
| 1726 | } |
||
| 1727 | |||
| 1728 | return self::toolbarAction(uniqid('toolbar', false), [$links]); |
||
| 1729 | } |
||
| 1730 | |||
| 1731 | /** |
||
| 1732 | * Prints a tooltip. |
||
| 1733 | * |
||
| 1734 | * @param string $text |
||
| 1735 | * @param string $tip |
||
| 1736 | * |
||
| 1737 | * @return string |
||
| 1738 | */ |
||
| 1739 | public static function tip($text, $tip) |
||
| 1740 | { |
||
| 1741 | if (empty($tip)) { |
||
| 1742 | return $text; |
||
| 1743 | } |
||
| 1744 | |||
| 1745 | return self::span( |
||
| 1746 | $text, |
||
| 1747 | ['class' => 'boot-tooltip', 'title' => strip_tags($tip)] |
||
| 1748 | ); |
||
| 1749 | } |
||
| 1750 | |||
| 1751 | /** |
||
| 1752 | * @param array $buttons |
||
| 1753 | * |
||
| 1754 | * @return string |
||
| 1755 | */ |
||
| 1756 | public static function groupButton($buttons) |
||
| 1765 | } |
||
| 1766 | |||
| 1767 | /** |
||
| 1768 | * @todo use twig |
||
| 1769 | * |
||
| 1770 | * @param string $title |
||
| 1771 | * @param array $elements |
||
| 1772 | * @param bool $alignToRight |
||
| 1773 | * |
||
| 1774 | * @return string |
||
| 1775 | */ |
||
| 1776 | public static function groupButtonWithDropDown($title, $elements, $alignToRight = false) |
||
| 1777 | { |
||
| 1778 | $id = uniqid('dropdown', false); |
||
| 1779 | $html = ' |
||
| 1780 | <div class="dropdown inline-block relative"> |
||
| 1781 | <button |
||
| 1782 | id="'.$id.'" |
||
| 1783 | type="button" |
||
| 1784 | class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" |
||
| 1785 | aria-expanded="false" |
||
| 1786 | aria-haspopup="true" |
||
| 1787 | onclick="document.querySelector(\'#'.$id.'_menu\').classList.toggle(\'hidden\')" |
||
| 1788 | > |
||
| 1789 | '.$title.' |
||
| 1790 | <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> |
||
| 1791 | <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /> |
||
| 1792 | </svg> |
||
| 1793 | </button> |
||
| 1794 | <div |
||
| 1795 | id="'.$id.'_menu" |
||
| 1796 | class=" dropdown-menu hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" |
||
| 1797 | role="menu" |
||
| 1798 | aria-orientation="vertical" |
||
| 1799 | aria-labelledby="menu-button" |
||
| 1800 | tabindex="-1" |
||
| 1801 | > |
||
| 1802 | <div class="py-1" role="none">'; |
||
| 1803 | foreach ($elements as $item) { |
||
| 1804 | $html .= self::url( |
||
| 1805 | $item['title'], |
||
| 1806 | $item['href'], |
||
| 1807 | [ |
||
| 1808 | 'class' => 'text-gray-700 block px-4 py-2 text-sm', |
||
| 1809 | 'role' => 'menuitem', |
||
| 1810 | 'onclick' => $item['onclick'] ?? '', |
||
| 1811 | 'data-action' => $item['data-action'] ?? '', |
||
| 1812 | 'data-confirm' => $item['data-confirm'] ?? '', |
||
| 1813 | ] |
||
| 1814 | ); |
||
| 1815 | } |
||
| 1816 | $html .= ' |
||
| 1817 | </div> |
||
| 1818 | </div> |
||
| 1819 | </div> |
||
| 1820 | '; |
||
| 1821 | |||
| 1822 | return $html; |
||
| 1823 | } |
||
| 1824 | |||
| 1825 | /** |
||
| 1826 | * @param string $file |
||
| 1827 | * @param array $params |
||
| 1828 | * |
||
| 1829 | * @return string|null |
||
| 1830 | */ |
||
| 1831 | public static function getMediaPlayer($file, $params = []) |
||
| 1832 | { |
||
| 1833 | $fileInfo = pathinfo($file); |
||
| 1834 | |||
| 1835 | $autoplay = isset($params['autoplay']) && 'true' === $params['autoplay'] ? 'autoplay' : ''; |
||
| 1836 | $id = isset($params['id']) ? $params['id'] : $fileInfo['basename']; |
||
| 1837 | $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null; |
||
| 1838 | $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null; |
||
| 1839 | |||
| 1840 | switch ($fileInfo['extension']) { |
||
| 1841 | case 'mp3': |
||
| 1842 | case 'webm': |
||
| 1843 | $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >'; |
||
| 1844 | $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf"> |
||
| 1845 | <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" /> |
||
| 1846 | <param name="flashvars" value="controls=true&file='.$params['url'].'" /> |
||
| 1847 | </object>'; |
||
| 1848 | $html .= '</audio>'; |
||
| 1849 | |||
| 1850 | return $html; |
||
| 1851 | break; |
||
| 1852 | case 'wav': |
||
| 1853 | case 'ogg': |
||
| 1854 | $html = '<audio width="300px" controls id="'.$id.'" '.$autoplay.' src="'.$params['url'].'" >'; |
||
| 1855 | |||
| 1856 | return $html; |
||
| 1857 | break; |
||
| 1858 | } |
||
| 1859 | |||
| 1860 | return null; |
||
| 1861 | } |
||
| 1862 | |||
| 1863 | /** |
||
| 1864 | * @param int $nextValue |
||
| 1865 | * @param array $list |
||
| 1866 | * @param int $current |
||
| 1867 | * @param int $fixedValue |
||
| 1868 | * @param array $conditions |
||
| 1869 | * @param string $link |
||
| 1870 | * @param bool $isMedia |
||
| 1871 | * @param bool $addHeaders |
||
| 1872 | * @param array $linkAttributes |
||
| 1873 | * |
||
| 1874 | * @return string |
||
| 1875 | */ |
||
| 1876 | public static function progressPaginationBar( |
||
| 1877 | $nextValue, |
||
| 1878 | $list, |
||
| 1879 | $current, |
||
| 1880 | $fixedValue = null, |
||
| 1881 | $conditions = [], |
||
| 1882 | $link = null, |
||
| 1883 | $isMedia = false, |
||
| 1884 | $addHeaders = true, |
||
| 1885 | $linkAttributes = [] |
||
| 1886 | ) { |
||
| 1887 | if ($addHeaders) { |
||
| 1888 | $pagination_size = 'pagination-mini'; |
||
| 1889 | $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>'; |
||
| 1890 | } else { |
||
| 1891 | $html = null; |
||
| 1892 | } |
||
| 1893 | $affectAllItems = false; |
||
| 1894 | if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) { |
||
| 1895 | $affectAllItems = true; |
||
| 1896 | } |
||
| 1897 | $localCounter = 0; |
||
| 1898 | foreach ($list as $itemId) { |
||
| 1899 | $isCurrent = false; |
||
| 1900 | if ($affectAllItems) { |
||
| 1901 | $isCurrent = true; |
||
| 1902 | } else { |
||
| 1903 | if (!$isMedia) { |
||
| 1904 | $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false; |
||
| 1905 | } |
||
| 1906 | } |
||
| 1907 | $html .= self::parsePaginationItem( |
||
| 1908 | $itemId, |
||
| 1909 | $isCurrent, |
||
| 1910 | $conditions, |
||
| 1911 | $link, |
||
| 1912 | $nextValue, |
||
| 1913 | $isMedia, |
||
| 1914 | $localCounter, |
||
| 1915 | $fixedValue, |
||
| 1916 | $linkAttributes |
||
| 1917 | ); |
||
| 1918 | $localCounter++; |
||
| 1919 | } |
||
| 1920 | if ($addHeaders) { |
||
| 1921 | $html .= '</ul></div>'; |
||
| 1922 | } |
||
| 1923 | |||
| 1924 | return $html; |
||
| 1925 | } |
||
| 1926 | |||
| 1927 | /** |
||
| 1928 | * @param int $itemId |
||
| 1929 | * @param bool $isCurrent |
||
| 1930 | * @param array $conditions |
||
| 1931 | * @param string $link |
||
| 1932 | * @param int $nextValue |
||
| 1933 | * @param bool $isMedia |
||
| 1934 | * @param int $localCounter |
||
| 1935 | * @param int $fixedValue |
||
| 1936 | * @param array $linkAttributes |
||
| 1937 | * |
||
| 1938 | * @return string |
||
| 1939 | */ |
||
| 1940 | public static function parsePaginationItem( |
||
| 1941 | $itemId, |
||
| 1942 | $isCurrent, |
||
| 1943 | $conditions, |
||
| 1944 | $link, |
||
| 1945 | $nextValue = 0, |
||
| 1946 | $isMedia = false, |
||
| 1947 | $localCounter = null, |
||
| 1948 | $fixedValue = null, |
||
| 1949 | $linkAttributes = [] |
||
| 1950 | ) { |
||
| 1951 | $defaultClass = 'before'; |
||
| 1952 | $class = $defaultClass; |
||
| 1953 | foreach ($conditions as $condition) { |
||
| 1954 | $array = isset($condition['items']) ? $condition['items'] : []; |
||
| 1955 | $class_to_applied = $condition['class']; |
||
| 1956 | $type = isset($condition['type']) ? $condition['type'] : 'positive'; |
||
| 1957 | $mode = isset($condition['mode']) ? $condition['mode'] : 'add'; |
||
| 1958 | switch ($type) { |
||
| 1959 | case 'positive': |
||
| 1960 | if (in_array($itemId, $array)) { |
||
| 1961 | if ('overwrite' == $mode) { |
||
| 1962 | $class = " $defaultClass $class_to_applied"; |
||
| 1963 | } else { |
||
| 1964 | $class .= " $class_to_applied"; |
||
| 1965 | } |
||
| 1966 | } |
||
| 1967 | break; |
||
| 1968 | case 'negative': |
||
| 1969 | if (!in_array($itemId, $array)) { |
||
| 1970 | if ('overwrite' == $mode) { |
||
| 1971 | $class = " $defaultClass $class_to_applied"; |
||
| 1972 | } else { |
||
| 1973 | $class .= " $class_to_applied"; |
||
| 1974 | } |
||
| 1975 | } |
||
| 1976 | break; |
||
| 1977 | } |
||
| 1978 | } |
||
| 1979 | if ($isCurrent) { |
||
| 1980 | $class = 'before current'; |
||
| 1981 | } |
||
| 1982 | if ($isMedia && $isCurrent) { |
||
| 1983 | $class = 'before current'; |
||
| 1984 | } |
||
| 1985 | if (empty($link)) { |
||
| 1986 | $link_to_show = '#'; |
||
| 1987 | } else { |
||
| 1988 | $link_to_show = $link.($nextValue + $localCounter); |
||
| 1989 | } |
||
| 1990 | $label = $nextValue + $localCounter + 1; |
||
| 1991 | if ($isMedia) { |
||
| 1992 | $label = ($fixedValue + 1).' '.chr(97 + $localCounter); |
||
| 1993 | $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId; |
||
| 1994 | } |
||
| 1995 | $link = self::url($label.' ', $link_to_show, $linkAttributes); |
||
| 1996 | |||
| 1997 | return '<li class = "'.$class.'">'.$link.'</li>'; |
||
| 1998 | } |
||
| 1999 | |||
| 2000 | /** |
||
| 2001 | * @param int $current |
||
| 2002 | * @param int $total |
||
| 2003 | * |
||
| 2004 | * @return string |
||
| 2005 | */ |
||
| 2006 | public static function paginationIndicator($current, $total) |
||
| 2007 | { |
||
| 2008 | $html = null; |
||
| 2009 | if (!empty($current) && !empty($total)) { |
||
| 2010 | $label = sprintf(get_lang('%s of %s'), $current, $total); |
||
| 2011 | $html = self::url($label, '#', ['class' => 'btn disabled']); |
||
| 2012 | } |
||
| 2013 | |||
| 2014 | return $html; |
||
| 2015 | } |
||
| 2016 | |||
| 2017 | /** |
||
| 2018 | * @param $url |
||
| 2019 | * @param $currentPage |
||
| 2020 | * @param $pagesCount |
||
| 2021 | * @param $totalItems |
||
| 2022 | * |
||
| 2023 | * @return string |
||
| 2024 | */ |
||
| 2025 | public static function getPagination($url, $currentPage, $pagesCount, $totalItems) |
||
| 2026 | { |
||
| 2027 | $pagination = ''; |
||
| 2028 | if ($totalItems > 1 && $pagesCount > 1) { |
||
| 2029 | $pagination .= '<ul class="pagination">'; |
||
| 2030 | for ($i = 0; $i < $pagesCount; $i++) { |
||
| 2031 | $newPage = $i + 1; |
||
| 2032 | if ($currentPage == $newPage) { |
||
| 2033 | $pagination .= '<li class="active"><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>'; |
||
| 2034 | } else { |
||
| 2035 | $pagination .= '<li><a href="'.$url.'&page='.$newPage.'">'.$newPage.'</a></li>'; |
||
| 2036 | } |
||
| 2037 | } |
||
| 2038 | $pagination .= '</ul>'; |
||
| 2039 | } |
||
| 2040 | |||
| 2041 | return $pagination; |
||
| 2042 | } |
||
| 2043 | |||
| 2044 | /** |
||
| 2045 | * Adds a legacy message in the queue. |
||
| 2046 | * |
||
| 2047 | * @param string $message |
||
| 2048 | */ |
||
| 2049 | public static function addFlash($message) |
||
| 2050 | { |
||
| 2051 | // Detect type of message. |
||
| 2052 | $parts = preg_match('/alert-([a-z]*)/', $message, $matches); |
||
| 2053 | $type = 'primary'; |
||
| 2054 | if ($parts && isset($matches[1]) && $matches[1]) { |
||
| 2055 | $type = $matches[1]; |
||
| 2056 | } |
||
| 2057 | // Detect legacy content of message. |
||
| 2058 | $result = preg_match('/<div(.*?)\>(.*?)\<\/div>/s', $message, $matches); |
||
| 2059 | if ($result && isset($matches[2])) { |
||
| 2060 | Container::getSession()->getFlashBag()->add($type, $matches[2]); |
||
| 2061 | } |
||
| 2062 | } |
||
| 2063 | |||
| 2064 | /** |
||
| 2065 | * Get the profile edition link for a user. |
||
| 2066 | * |
||
| 2067 | * @param int $userId The user id |
||
| 2068 | * @param bool $asAdmin Optional. Whether get the URL for the platform admin |
||
| 2069 | * |
||
| 2070 | * @return string The link |
||
| 2071 | */ |
||
| 2072 | public static function getProfileEditionLink($userId, $asAdmin = false) |
||
| 2073 | { |
||
| 2074 | $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php'; |
||
| 2075 | if ($asAdmin) { |
||
| 2076 | $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId); |
||
| 2077 | } |
||
| 2078 | |||
| 2079 | return $editProfileUrl; |
||
| 2080 | } |
||
| 2081 | |||
| 2082 | /** |
||
| 2083 | * Get the vCard for a user. |
||
| 2084 | * |
||
| 2085 | * @param int $userId The user id |
||
| 2086 | * |
||
| 2087 | * @return string *.*vcf file |
||
| 2088 | */ |
||
| 2089 | public static function getVCardUserLink($userId) |
||
| 2090 | { |
||
| 2091 | return api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId); |
||
| 2092 | } |
||
| 2093 | |||
| 2094 | /** |
||
| 2095 | * @param string $content |
||
| 2096 | * @param string $title |
||
| 2097 | * @param string $footer |
||
| 2098 | * @param string $type primary|success|info|warning|danger |
||
| 2099 | * @param string $extra |
||
| 2100 | * @param string $id |
||
| 2101 | * @param string $customColor |
||
| 2102 | * @param string $rightAction |
||
| 2103 | * |
||
| 2104 | * @return string |
||
| 2105 | */ |
||
| 2106 | public static function panel( |
||
| 2107 | $content, |
||
| 2108 | $title = '', |
||
| 2109 | $footer = '', |
||
| 2110 | $type = 'default', |
||
| 2111 | $extra = '', |
||
| 2112 | $id = '', |
||
| 2113 | $customColor = '', |
||
| 2114 | $rightAction = '' |
||
| 2115 | ) { |
||
| 2116 | $headerStyle = ''; |
||
| 2117 | if (!empty($customColor)) { |
||
| 2118 | $headerStyle = 'style = "color: white; background-color: '.$customColor.'" '; |
||
| 2119 | } |
||
| 2120 | |||
| 2121 | $footer = !empty($footer) ? '<p class="card-text"><small class="text-muted">'.$footer.'</small></p>' : ''; |
||
| 2122 | $typeList = ['primary', 'success', 'info', 'warning', 'danger']; |
||
| 2123 | $style = !in_array($type, $typeList) ? 'default' : $type; |
||
| 2124 | |||
| 2125 | if (!empty($id)) { |
||
| 2126 | $id = " id='$id'"; |
||
| 2127 | } |
||
| 2128 | $cardBody = $title.' '.self::contentPanel($content).' '.$footer; |
||
| 2129 | |||
| 2130 | return " |
||
| 2131 | <div $id class=card> |
||
| 2132 | <div class='flex justify-between items-center py-2'> |
||
| 2133 | <div class='relative mt-1 flex'> |
||
| 2134 | $title |
||
| 2135 | </div> |
||
| 2136 | <div> |
||
| 2137 | $rightAction |
||
| 2138 | </div> |
||
| 2139 | </div> |
||
| 2140 | |||
| 2141 | $content |
||
| 2142 | $footer |
||
| 2143 | </div>" |
||
| 2144 | ; |
||
| 2145 | } |
||
| 2146 | |||
| 2147 | /** |
||
| 2148 | * @param string $content |
||
| 2149 | */ |
||
| 2150 | public static function contentPanel($content): string |
||
| 2151 | { |
||
| 2152 | if (empty($content)) { |
||
| 2153 | return ''; |
||
| 2154 | } |
||
| 2155 | |||
| 2156 | return '<div class="card-text">'.$content.'</div>'; |
||
| 2157 | } |
||
| 2158 | |||
| 2159 | /** |
||
| 2160 | * Get the button HTML with an Awesome Font icon. |
||
| 2161 | * |
||
| 2162 | * @param string $text The button content |
||
| 2163 | * @param string $url The url to button |
||
| 2164 | * @param string $icon The Awesome Font class for icon |
||
| 2165 | * @param string $type Optional. The button Bootstrap class. Default 'default' class |
||
| 2166 | * @param array $attributes The additional attributes |
||
| 2167 | * @param bool $includeText |
||
| 2168 | * |
||
| 2169 | * @return string The button HTML |
||
| 2170 | */ |
||
| 2171 | public static function toolbarButton( |
||
| 2172 | $text, |
||
| 2173 | $url, |
||
| 2174 | $icon = 'check', |
||
| 2175 | $type = null, |
||
| 2176 | array $attributes = [], |
||
| 2177 | $includeText = true |
||
| 2178 | ) { |
||
| 2179 | $buttonClass = "btn btn--secondary-outline"; |
||
| 2180 | if (!empty($type)) { |
||
| 2181 | $buttonClass = "btn btn--$type"; |
||
| 2182 | } |
||
| 2183 | //$icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']); |
||
| 2184 | $icon = self::getMdiIcon($icon); |
||
| 2185 | $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass; |
||
| 2186 | $attributes['title'] = $attributes['title'] ?? $text; |
||
| 2187 | |||
| 2188 | if (!$includeText) { |
||
| 2189 | $text = '<span class="sr-only">'.$text.'</span>'; |
||
| 2190 | } |
||
| 2191 | |||
| 2192 | return self::url("$icon $text", $url, $attributes); |
||
| 2193 | } |
||
| 2194 | |||
| 2195 | /** |
||
| 2196 | * Generate an HTML "p-toolbar" div element with the given id attribute. |
||
| 2197 | * @param string $id The HTML div's "id" attribute to set |
||
| 2198 | * @param array $contentList Array of left-center-right elements for the toolbar. If only 2 elements are defined, this becomes left-right (no center) |
||
| 2199 | * @return string HTML div for the toolbar |
||
| 2200 | */ |
||
| 2201 | public static function toolbarAction(string $id, array $contentList): string |
||
| 2202 | { |
||
| 2203 | $contentListPurged = array_filter($contentList); |
||
| 2204 | |||
| 2205 | if (empty($contentListPurged)) { |
||
| 2206 | return ''; |
||
| 2207 | } |
||
| 2208 | |||
| 2209 | $count = count($contentList); |
||
| 2210 | |||
| 2211 | $start = $contentList[0]; |
||
| 2212 | $center = ''; |
||
| 2213 | $end = ''; |
||
| 2214 | |||
| 2215 | if (2 === $count) { |
||
| 2216 | $end = $contentList[1]; |
||
| 2217 | } elseif (3 === $count) { |
||
| 2218 | $center = $contentList[1]; |
||
| 2219 | $end = $contentList[2]; |
||
| 2220 | } |
||
| 2221 | |||
| 2222 | return '<div id="'.$id.'" class="toolbar-action p-toolbar p-component flex items-center justify-between flex-wrap w-full" role="toolbar"> |
||
| 2223 | <div class="p-toolbar-group-start p-toolbar-group-left">'.$start.'</div> |
||
| 2224 | <div class="p-toolbar-group-center">'.$center.'</div> |
||
| 2225 | <div class="p-toolbar-group-end p-toolbar-group-right">'.$end.'</div> |
||
| 2226 | </div>'; |
||
| 2227 | } |
||
| 2228 | |||
| 2229 | /** |
||
| 2230 | * @param array $content |
||
| 2231 | * @param array $colsWidth Optional. Columns width |
||
| 2232 | * |
||
| 2233 | * @return string |
||
| 2234 | */ |
||
| 2235 | public static function toolbarGradeAction($content, $colsWidth = []) |
||
| 2236 | { |
||
| 2237 | $col = count($content); |
||
| 2238 | |||
| 2239 | if (!$colsWidth) { |
||
| 2240 | $width = 8 / $col; |
||
| 2241 | array_walk($content, function () use ($width, &$colsWidth) { |
||
| 2242 | $colsWidth[] = $width; |
||
| 2243 | }); |
||
| 2244 | } |
||
| 2245 | |||
| 2246 | $html = '<div id="grade" class="p-toolbar p-component flex items-center justify-between flex-wrap" role="toolbar">'; |
||
| 2247 | for ($i = 0; $i < $col; $i++) { |
||
| 2248 | $class = 'col-sm-'.$colsWidth[$i]; |
||
| 2249 | if ($col > 1) { |
||
| 2250 | if ($i > 0 && $i < count($content) - 1) { |
||
| 2251 | $class .= ' text-center'; |
||
| 2252 | } elseif ($i === count($content) - 1) { |
||
| 2253 | $class .= ' text-right'; |
||
| 2254 | } |
||
| 2255 | } |
||
| 2256 | $html .= '<div class="'.$class.'">'.$content[$i].'</div>'; |
||
| 2257 | } |
||
| 2258 | $html .= '</div>'; |
||
| 2259 | |||
| 2260 | return $html; |
||
| 2261 | } |
||
| 2262 | |||
| 2263 | /** |
||
| 2264 | * The auto-translated title version of getMdiIconSimple() |
||
| 2265 | * Shortcut method to getMdiIcon, to be used from Twig (see ChamiloExtension.php) |
||
| 2266 | * using acceptable default values |
||
| 2267 | * @param string $name The icon name or a string representing the icon in our *Icon Enums |
||
| 2268 | * @param int|null $size The icon size |
||
| 2269 | * @param string|null $additionalClass Additional CSS class to add to the icon |
||
| 2270 | * @param string|null $title A title for the icon |
||
| 2271 | * @return string |
||
| 2272 | * @throws InvalidArgumentException |
||
| 2273 | * @throws ReflectionException |
||
| 2274 | */ |
||
| 2275 | public static function getMdiIconTranslate( |
||
| 2276 | string $name, |
||
| 2277 | ?int $size = ICON_SIZE_SMALL, |
||
| 2278 | ?string $additionalClass = 'ch-tool-icon', |
||
| 2279 | ?string $title = null |
||
| 2280 | ): string |
||
| 2281 | { |
||
| 2282 | if (!empty($title)) { |
||
| 2283 | $title = get_lang($title); |
||
| 2284 | } |
||
| 2285 | |||
| 2286 | return self::getMdiIconSimple($name, $size, $additionalClass, $title); |
||
| 2287 | } |
||
| 2288 | /** |
||
| 2289 | * Shortcut method to getMdiIcon, to be used from Twig (see ChamiloExtension.php) |
||
| 2290 | * using acceptable default values |
||
| 2291 | * @param string $name The icon name or a string representing the icon in our *Icon Enums |
||
| 2292 | * @param int|null $size The icon size |
||
| 2293 | * @param string|null $additionalClass Additional CSS class to add to the icon |
||
| 2294 | * @param string|null $title A title for the icon |
||
| 2295 | * @return string |
||
| 2296 | * @throws InvalidArgumentException |
||
| 2297 | * @throws ReflectionException |
||
| 2298 | */ |
||
| 2299 | public static function getMdiIconSimple( |
||
| 2300 | string $name, |
||
| 2301 | ?int $size = ICON_SIZE_SMALL, |
||
| 2302 | ?string $additionalClass = 'ch-tool-icon', |
||
| 2303 | ?string $title = null |
||
| 2304 | ): string |
||
| 2305 | { |
||
| 2306 | // If the string contains '::', we assume it is a reference to one of the icon Enum classes in src/CoreBundle/Enums/ |
||
| 2307 | $matches = []; |
||
| 2308 | if (preg_match('/(\w*)::(\w*)/', $name, $matches)) { |
||
| 2309 | if (count($matches) != 3) { |
||
| 2310 | throw new InvalidArgumentException('Invalid enum case string format. Expected format is "EnumClass::CASE".'); |
||
| 2311 | } |
||
| 2312 | $enum = $matches[1]; |
||
| 2313 | $case = $matches[2]; |
||
| 2314 | if (!class_exists('Chamilo\CoreBundle\Enums\\'.$enum)) { |
||
| 2315 | throw new InvalidArgumentException("Class {$enum} does not exist."); |
||
| 2316 | } |
||
| 2317 | $reflection = new ReflectionEnum('Chamilo\CoreBundle\Enums\\'.$enum); |
||
| 2318 | // Check if the case exists in the Enum class |
||
| 2319 | if (!$reflection->hasCase($case)) { |
||
| 2320 | throw new InvalidArgumentException("Case {$case} does not exist in enum class {$enum}."); |
||
| 2321 | } |
||
| 2322 | // Get the Enum case |
||
| 2323 | /* @var ReflectionEnumUnitCase $enumUnitCaseObject */ |
||
| 2324 | $enumUnitCaseObject = $reflection->getCase($case); |
||
| 2325 | $enumValue = $enumUnitCaseObject->getValue(); |
||
| 2326 | $name = $enumValue->value; |
||
| 2327 | |||
| 2328 | } |
||
| 2329 | |||
| 2330 | return self::getMdiIcon($name, $additionalClass, null, $size, $title); |
||
| 2331 | } |
||
| 2332 | |||
| 2333 | /** |
||
| 2334 | * Get a full HTML <i> tag for an icon from the Material Design Icons set |
||
| 2335 | * @param string|ActionIcon|ToolIcon|ObjectIcon|StateIcon $name |
||
| 2336 | * @param string|null $additionalClass |
||
| 2337 | * @param string|null $style |
||
| 2338 | * @param int|null $pixelSize |
||
| 2339 | * @param string|null $title |
||
| 2340 | * @param array|null $additionalAttributes |
||
| 2341 | * @return string |
||
| 2342 | */ |
||
| 2343 | public static function getMdiIcon(string|ActionIcon|ToolIcon|ObjectIcon|StateIcon $name, string $additionalClass = null, string $style = null, int $pixelSize = null, string $title = null, array $additionalAttributes = null): string |
||
| 2344 | { |
||
| 2345 | $sizeString = ''; |
||
| 2346 | if (!empty($pixelSize)) { |
||
| 2347 | $sizeString = 'font-size: '.$pixelSize.'px; width: '.$pixelSize.'px; height: '.$pixelSize.'px; '; |
||
| 2348 | } |
||
| 2349 | if (empty($style)) { |
||
| 2350 | $style = ''; |
||
| 2351 | } |
||
| 2352 | |||
| 2353 | $additionalAttributes['class'] = 'mdi mdi-'; |
||
| 2354 | |||
| 2355 | if ($name instanceof ActionIcon |
||
| 2356 | || $name instanceof ToolIcon |
||
| 2357 | || $name instanceof ObjectIcon |
||
| 2358 | || $name instanceof StateIcon |
||
| 2359 | ) { |
||
| 2360 | $additionalAttributes['class'] .= $name->value; |
||
| 2361 | } else { |
||
| 2362 | $additionalAttributes['class'] .= $name; |
||
| 2363 | } |
||
| 2364 | |||
| 2365 | $additionalAttributes['class'] .= " $additionalClass"; |
||
| 2366 | $additionalAttributes['style'] = $sizeString.$style; |
||
| 2367 | $additionalAttributes['aria-hidden'] = 'true'; |
||
| 2368 | |||
| 2369 | if (!empty($title)) { |
||
| 2370 | $additionalAttributes['title'] = htmlentities($title); |
||
| 2371 | } |
||
| 2372 | |||
| 2373 | return self::tag( |
||
| 2374 | 'i', |
||
| 2375 | '', |
||
| 2376 | $additionalAttributes |
||
| 2377 | ); |
||
| 2378 | } |
||
| 2379 | |||
| 2380 | /** |
||
| 2381 | * Get a HTML code for a icon by Font Awesome. |
||
| 2382 | * |
||
| 2383 | * @param string $name The icon name. Example: "mail-reply" |
||
| 2384 | * @param int|string $size Optional. The size for the icon. (Example: lg, 2, 3, 4, 5) |
||
| 2385 | * @param bool $fixWidth Optional. Whether add the fw class |
||
| 2386 | * @param string $additionalClass Optional. Additional class |
||
| 2387 | * |
||
| 2388 | * @return string |
||
| 2389 | * @deprecated Use getMdiIcon() instead |
||
| 2390 | */ |
||
| 2391 | public static function returnFontAwesomeIcon( |
||
| 2392 | $name, |
||
| 2393 | $size = '', |
||
| 2394 | $fixWidth = false, |
||
| 2395 | $additionalClass = '' |
||
| 2396 | ) { |
||
| 2397 | $className = "mdi mdi-$name"; |
||
| 2398 | |||
| 2399 | if ($fixWidth) { |
||
| 2400 | $className .= ' fa-fw'; |
||
| 2401 | } |
||
| 2402 | |||
| 2403 | switch ($size) { |
||
| 2404 | case 'xs': |
||
| 2405 | case 'sm': |
||
| 2406 | case 'lg': |
||
| 2407 | $className .= " fa-{$size}"; |
||
| 2408 | break; |
||
| 2409 | case 2: |
||
| 2410 | case 3: |
||
| 2411 | case 4: |
||
| 2412 | case 5: |
||
| 2413 | $className .= " fa-{$size}x"; |
||
| 2414 | break; |
||
| 2415 | } |
||
| 2416 | |||
| 2417 | if (!empty($additionalClass)) { |
||
| 2418 | $className .= " $additionalClass"; |
||
| 2419 | } |
||
| 2420 | |||
| 2421 | $icon = self::tag('em', null, ['class' => $className]); |
||
| 2422 | |||
| 2423 | return "$icon "; |
||
| 2424 | } |
||
| 2425 | |||
| 2426 | public static function returnPrimeIcon( |
||
| 2427 | $name, |
||
| 2428 | $size = '', |
||
| 2429 | $fixWidth = false, |
||
| 2430 | $additionalClass = '' |
||
| 2431 | ) { |
||
| 2432 | $className = "pi pi-$name"; |
||
| 2433 | |||
| 2434 | if ($fixWidth) { |
||
| 2435 | $className .= ' pi-fw'; |
||
| 2436 | } |
||
| 2437 | |||
| 2438 | if ($size) { |
||
| 2439 | $className .= " pi-$size"; |
||
| 2440 | } |
||
| 2441 | |||
| 2442 | if (!empty($additionalClass)) { |
||
| 2443 | $className .= " $additionalClass"; |
||
| 2444 | } |
||
| 2445 | |||
| 2446 | $icon = self::tag('i', null, ['class' => $className]); |
||
| 2447 | |||
| 2448 | return "$icon "; |
||
| 2449 | } |
||
| 2450 | |||
| 2451 | /** |
||
| 2452 | * @param string $title |
||
| 2453 | * @param string $content |
||
| 2454 | * @param null $id |
||
| 2455 | * @param array $params |
||
| 2456 | * @param null $idAccordion |
||
| 2457 | * @param null $idCollapse |
||
| 2458 | * @param bool|true $open |
||
| 2459 | * @param bool|false $fullClickable |
||
| 2460 | * |
||
| 2461 | * @return string |
||
| 2462 | * |
||
| 2463 | * @todo rework function to easy use |
||
| 2464 | */ |
||
| 2465 | public static function panelCollapse( |
||
| 2466 | $title, |
||
| 2467 | $content, |
||
| 2468 | $id = null, |
||
| 2469 | $params = [], |
||
| 2470 | $idAccordion = null, |
||
| 2471 | $idCollapse = null, |
||
| 2472 | $open = true, |
||
| 2473 | $fullClickable = false |
||
| 2474 | ) { |
||
| 2475 | $javascript = ''; |
||
| 2476 | if (!empty($idAccordion)) { |
||
| 2477 | $javascript = ' |
||
| 2478 | <script> |
||
| 2479 | document.addEventListener("DOMContentLoaded", function() { |
||
| 2480 | const buttons = document.querySelectorAll("#card_'.$idAccordion.' a"); |
||
| 2481 | const menus = document.querySelectorAll("#collapse_'.$idAccordion.'"); |
||
| 2482 | buttons.forEach((button, index) => { |
||
| 2483 | button.addEventListener("click", function() { |
||
| 2484 | menus.forEach((menu, menuIndex) => { |
||
| 2485 | if (index === menuIndex) { |
||
| 2486 | button.setAttribute("aria-expanded", "true" === button.getAttribute("aria-expanded") ? "false" : "true") |
||
| 2487 | button.classList.toggle("mdi-chevron-down") |
||
| 2488 | button.classList.toggle("mdi-chevron-up") |
||
| 2489 | menu.classList.toggle("active"); |
||
| 2490 | } else { |
||
| 2491 | menu.classList.remove("active"); |
||
| 2492 | } |
||
| 2493 | }); |
||
| 2494 | }); |
||
| 2495 | }); |
||
| 2496 | }); |
||
| 2497 | </script>'; |
||
| 2498 | $html = ' |
||
| 2499 | <div class="display-panel-collapse mb-2"> |
||
| 2500 | <div class="display-panel-collapse__header" id="card_'.$idAccordion.'"> |
||
| 2501 | <a role="button" |
||
| 2502 | class="mdi mdi-chevron-down" |
||
| 2503 | data-toggle="collapse" |
||
| 2504 | data-target="#collapse_'.$idAccordion.'" |
||
| 2505 | aria-expanded="'.(($open) ? 'true' : 'false').'" |
||
| 2506 | aria-controls="collapse_'.$idAccordion.'" |
||
| 2507 | > |
||
| 2508 | '.$title.' |
||
| 2509 | </a> |
||
| 2510 | </div> |
||
| 2511 | <div |
||
| 2512 | id="collapse_'.$idAccordion.'" |
||
| 2513 | class="display-panel-collapse__collapsible '.(($open) ? 'active' : '').'" |
||
| 2514 | > |
||
| 2515 | <div id="collapse_contant_'.$idAccordion.'">'; |
||
| 2516 | |||
| 2517 | $html .= $content; |
||
| 2518 | $html .= '</div></div></div>'; |
||
| 2519 | |||
| 2520 | } else { |
||
| 2521 | if (!empty($id)) { |
||
| 2522 | $params['id'] = $id; |
||
| 2523 | } |
||
| 2524 | $params['class'] = 'v-card bg-white mx-2'; |
||
| 2525 | $html = ''; |
||
| 2526 | if (!empty($title)) { |
||
| 2527 | $html .= '<div class="v-card-header text-h5 my-2">'.$title.'</div>'.PHP_EOL; |
||
| 2528 | } |
||
| 2529 | $html .= '<div class="v-card-text">'.$content.'</div>'.PHP_EOL; |
||
| 2530 | $html = self::div($html, $params); |
||
| 2531 | } |
||
| 2532 | |||
| 2533 | return $javascript.$html; |
||
| 2534 | } |
||
| 2535 | |||
| 2536 | /** |
||
| 2537 | * Returns the string "1 day ago" with a link showing the exact date time. |
||
| 2538 | * |
||
| 2539 | * @param string|DateTime $dateTime in UTC or a DateTime in UTC |
||
| 2540 | * |
||
| 2541 | * @throws Exception |
||
| 2542 | * |
||
| 2543 | * @return string |
||
| 2544 | */ |
||
| 2545 | public static function dateToStringAgoAndLongDate(string|DateTime $dateTime): string |
||
| 2546 | { |
||
| 2547 | if (empty($dateTime) || '0000-00-00 00:00:00' === $dateTime) { |
||
| 2548 | return ''; |
||
| 2549 | } |
||
| 2550 | |||
| 2551 | if (is_string($dateTime)) { |
||
| 2552 | $dateTime = new \DateTime($dateTime, new \DateTimeZone('UTC')); |
||
| 2553 | } |
||
| 2554 | |||
| 2555 | return self::tip( |
||
| 2556 | date_to_str_ago($dateTime), |
||
| 2557 | api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG) |
||
| 2558 | ); |
||
| 2559 | } |
||
| 2560 | |||
| 2561 | /** |
||
| 2562 | * @param array $userInfo |
||
| 2563 | * @param string $status |
||
| 2564 | * @param string $toolbar |
||
| 2565 | * |
||
| 2566 | * @return string |
||
| 2567 | */ |
||
| 2568 | public static function getUserCard($userInfo, $status = '', $toolbar = '') |
||
| 2569 | { |
||
| 2570 | if (empty($userInfo)) { |
||
| 2571 | return ''; |
||
| 2572 | } |
||
| 2573 | |||
| 2574 | if (!empty($status)) { |
||
| 2575 | $status = '<div class="items-user-status">'.$status.'</div>'; |
||
| 2576 | } |
||
| 2577 | |||
| 2578 | if (!empty($toolbar)) { |
||
| 2579 | $toolbar = '<div class="btn-group pull-right">'.$toolbar.'</div>'; |
||
| 2580 | } |
||
| 2581 | |||
| 2582 | return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row"> |
||
| 2583 | <img src="'.$userInfo['avatar'].'" class="rounded" /> |
||
| 2584 | <h3 class="card-title">'.$userInfo['complete_name'].'</h3> |
||
| 2585 | <div class="card-body"> |
||
| 2586 | <div class="card-title"> |
||
| 2587 | '.$status.' |
||
| 2588 | '.$toolbar.' |
||
| 2589 | </div> |
||
| 2590 | </div> |
||
| 2591 | <hr /> |
||
| 2592 | </div>'; |
||
| 2593 | } |
||
| 2594 | |||
| 2595 | /** |
||
| 2596 | * @param string $fileName |
||
| 2597 | * @param string $fileUrl |
||
| 2598 | * |
||
| 2599 | * @return string |
||
| 2600 | */ |
||
| 2601 | public static function fileHtmlGuesser($fileName, $fileUrl) |
||
| 2602 | { |
||
| 2603 | $data = pathinfo($fileName); |
||
| 2604 | |||
| 2605 | //$content = self::url($data['basename'], $fileUrl); |
||
| 2606 | $content = ''; |
||
| 2607 | switch ($data['extension']) { |
||
| 2608 | case 'webm': |
||
| 2609 | case 'mp4': |
||
| 2610 | case 'ogg': |
||
| 2611 | $content = '<video style="width: 400px; height:100%;" src="'.$fileUrl.'"></video>'; |
||
| 2612 | // Allows video to play when loading during an ajax call |
||
| 2613 | $content .= "<script>jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer();</script>"; |
||
| 2614 | break; |
||
| 2615 | case 'jpg': |
||
| 2616 | case 'jpeg': |
||
| 2617 | case 'gif': |
||
| 2618 | case 'png': |
||
| 2619 | $content = '<img class="img-responsive" src="'.$fileUrl.'" />'; |
||
| 2620 | break; |
||
| 2621 | default: |
||
| 2622 | //$html = self::url($data['basename'], $fileUrl); |
||
| 2623 | break; |
||
| 2624 | } |
||
| 2625 | //$html = self::url($content, $fileUrl, ['ajax']); |
||
| 2626 | |||
| 2627 | return $content; |
||
| 2628 | } |
||
| 2629 | |||
| 2630 | /** |
||
| 2631 | * @param string $image |
||
| 2632 | * @param int $size |
||
| 2633 | * |
||
| 2634 | * @return string |
||
| 2635 | */ |
||
| 2636 | public static function get_icon_path($image, $size = ICON_SIZE_SMALL) |
||
| 2637 | { |
||
| 2638 | return self::return_icon($image, '', [], $size, false, true); |
||
| 2639 | } |
||
| 2640 | |||
| 2641 | /** |
||
| 2642 | * @param $id |
||
| 2643 | * |
||
| 2644 | * @return array|mixed |
||
| 2645 | */ |
||
| 2646 | public static function randomColor($id) |
||
| 2647 | { |
||
| 2648 | static $colors = []; |
||
| 2649 | |||
| 2650 | if (!empty($colors[$id])) { |
||
| 2651 | return $colors[$id]; |
||
| 2652 | } else { |
||
| 2653 | $color = substr(md5(time() * $id), 0, 6); |
||
| 2654 | $c1 = hexdec(substr($color, 0, 2)); |
||
| 2655 | $c2 = hexdec(substr($color, 2, 2)); |
||
| 2656 | $c3 = hexdec(substr($color, 4, 2)); |
||
| 2657 | $luminosity = $c1 + $c2 + $c3; |
||
| 2658 | |||
| 2659 | $type = '#000000'; |
||
| 2660 | if ($luminosity < (255 + 255 + 255) / 2) { |
||
| 2661 | $type = '#FFFFFF'; |
||
| 2662 | } |
||
| 2663 | |||
| 2664 | $result = [ |
||
| 2665 | 'color' => '#'.$color, |
||
| 2666 | 'luminosity' => $type, |
||
| 2667 | ]; |
||
| 2668 | $colors[$id] = $result; |
||
| 2669 | |||
| 2670 | return $result; // example: #fc443a |
||
| 2671 | } |
||
| 2672 | } |
||
| 2673 | |||
| 2674 | public static function noDataView(string $title, string $icon, string $buttonTitle, string $url): string |
||
| 2675 | { |
||
| 2676 | $content = '<div id="no-data-view">'; |
||
| 2677 | $content .= '<h3>'.$title.'</h3>'; |
||
| 2678 | $content .= $icon; |
||
| 2679 | $content .= '<div class="controls">'; |
||
| 2680 | $content .= self::url( |
||
| 2681 | '<em class="fa fa-plus"></em> '.$buttonTitle, |
||
| 2682 | $url, |
||
| 2683 | ['class' => 'btn btn--primary'] |
||
| 2684 | ); |
||
| 2685 | $content .= '</div>'; |
||
| 2686 | $content .= '</div>'; |
||
| 2687 | |||
| 2688 | return $content; |
||
| 2689 | } |
||
| 2690 | |||
| 2691 | public static function prose(string $contents): string |
||
| 2692 | { |
||
| 2693 | return " |
||
| 2694 | <div class='w-full my-8'> |
||
| 2695 | <div class='prose prose-blue max-w-none px-6 py-4 bg-white rounded-lg shadow'> |
||
| 2696 | $contents |
||
| 2697 | </div> |
||
| 2698 | </div> |
||
| 2699 | "; |
||
| 2700 | } |
||
| 2701 | |||
| 2702 | public static function getFrameReadyBlock( |
||
| 2703 | string $frameName, |
||
| 2704 | string $itemType = '', |
||
| 2705 | string $jsConditionalFunction = 'function () { return false; }' |
||
| 2706 | ): string { |
||
| 2707 | |||
| 2708 | if (in_array($itemType, ['link', 'sco', 'xapi', 'quiz', 'h5p', 'forum'])) { |
||
| 2709 | return false; |
||
| 2710 | } |
||
| 2711 | |||
| 2712 | $themeHelper = Container::$container->get(ThemeHelper::class); |
||
| 2713 | |||
| 2714 | $themeColorsUrl = $themeHelper->getThemeAssetUrl('colors.css'); |
||
| 2715 | |||
| 2716 | $colorThemeItem = $themeColorsUrl |
||
| 2717 | ? '{ type: "stylesheet", src: "'.$themeColorsUrl.'" },' |
||
| 2718 | : ''; |
||
| 2719 | |||
| 2720 | return '$.frameReady(function() {}, |
||
| 2721 | "'.$frameName.'", |
||
| 2722 | [ |
||
| 2723 | { type: "script", src: "/build/runtime.js" }, |
||
| 2724 | { type: "script", src: "/build/legacy_framereadyloader.js" }, |
||
| 2725 | { type: "stylesheet", src: "/build/legacy_framereadyloader.css" }, |
||
| 2726 | '.$colorThemeItem.' |
||
| 2727 | ], |
||
| 2728 | '.$jsConditionalFunction |
||
| 2729 | .');'; |
||
| 2730 | } |
||
| 2731 | |||
| 2732 | /** |
||
| 2733 | * Renders and consumes messages stored with Display::addFlash(). |
||
| 2734 | * Returns HTML ready to inject into the view (alert-*). |
||
| 2735 | * |
||
| 2736 | * @return html string with all Flash messages (or '' if none) |
||
| 2737 | */ |
||
| 2738 | public static function getFlash(): string |
||
| 2739 | { |
||
| 2740 | $html = ''; |
||
| 2741 | |||
| 2742 | try { |
||
| 2743 | $flashBag = Container::getSession()->getFlashBag(); |
||
| 2744 | $all = $flashBag->all(); |
||
| 2745 | |||
| 2746 | foreach ($all as $type => $messages) { |
||
| 2747 | switch ($type) { |
||
| 2748 | case 'success': |
||
| 2749 | $displayType = 'success'; |
||
| 2750 | break; |
||
| 2751 | case 'warning': |
||
| 2752 | $displayType = 'warning'; |
||
| 2753 | break; |
||
| 2754 | case 'danger': |
||
| 2755 | case 'error': |
||
| 2756 | $displayType = 'error'; |
||
| 2757 | break; |
||
| 2758 | case 'info': |
||
| 2759 | case 'primary': |
||
| 2760 | default: |
||
| 2761 | $displayType = 'info'; |
||
| 2762 | break; |
||
| 2763 | } |
||
| 2764 | |||
| 2765 | foreach ((array) $messages as $msg) { |
||
| 2766 | if (is_string($msg) && $msg !== '') { |
||
| 2767 | $html .= self::return_message($msg, $displayType, false); |
||
| 2768 | } |
||
| 2769 | } |
||
| 2770 | } |
||
| 2771 | } catch (\Throwable $e) { |
||
| 2772 | error_log('Display::getFlash error: '.$e->getMessage()); |
||
| 2773 | } |
||
| 2774 | |||
| 2775 | return $html; |
||
| 2776 | } |
||
| 2777 | |||
| 2778 | /** |
||
| 2779 | * Build the common MySpace / tracking menu (left part of the toolbar). |
||
| 2780 | * |
||
| 2781 | * $current can be: |
||
| 2782 | * - overview |
||
| 2783 | * - students |
||
| 2784 | * - teachers |
||
| 2785 | * - admin_view |
||
| 2786 | * - exams |
||
| 2787 | * - current_courses |
||
| 2788 | * - courses |
||
| 2789 | * - sessions |
||
| 2790 | * - company_reports |
||
| 2791 | * - company_reports_resumed |
||
| 2792 | */ |
||
| 2793 | public static function mySpaceMenu(?string $current = 'overview'): string |
||
| 2794 | { |
||
| 2795 | $base = api_get_path(WEB_CODE_PATH).'my_space/'; |
||
| 2796 | $items = []; |
||
| 2797 | |||
| 2798 | $isPlatformAdmin = api_is_platform_admin(); |
||
| 2799 | $isDrh = api_is_drh(); |
||
| 2800 | if ('yourstudents' === $current) { |
||
| 2801 | $current = 'students'; |
||
| 2802 | } |
||
| 2803 | |||
| 2804 | if ($isDrh) { |
||
| 2805 | // DRH menu. |
||
| 2806 | $items = [ |
||
| 2807 | 'students' => [ |
||
| 2808 | 'icon' => ObjectIcon::USER, |
||
| 2809 | 'title' => get_lang('Learners'), |
||
| 2810 | 'url' => $base.'student.php', |
||
| 2811 | ], |
||
| 2812 | 'teachers' => [ |
||
| 2813 | 'icon' => ObjectIcon::TEACHER, |
||
| 2814 | 'title' => get_lang('Teachers'), |
||
| 2815 | 'url' => $base.'teachers.php', |
||
| 2816 | ], |
||
| 2817 | 'courses' => [ |
||
| 2818 | 'icon' => ObjectIcon::COURSE, |
||
| 2819 | 'title' => get_lang('Courses'), |
||
| 2820 | 'url' => $base.'course.php', |
||
| 2821 | ], |
||
| 2822 | 'sessions' => [ |
||
| 2823 | 'icon' => ObjectIcon::SESSION, |
||
| 2824 | 'title' => get_lang('Course sessions'), |
||
| 2825 | 'url' => $base.'session.php', |
||
| 2826 | ], |
||
| 2827 | 'company_reports' => [ |
||
| 2828 | 'icon' => ObjectIcon::REPORT, |
||
| 2829 | 'title' => get_lang('Corporate report'), |
||
| 2830 | 'url' => $base.'company_reports.php', |
||
| 2831 | ], |
||
| 2832 | 'company_reports_resumed' => [ |
||
| 2833 | 'icon' => 'chart-box-outline', |
||
| 2834 | 'title' => get_lang('Corporate report, short version'), |
||
| 2835 | 'url' => $base.'company_reports_resumed.php', |
||
| 2836 | ], |
||
| 2837 | ]; |
||
| 2838 | } else { |
||
| 2839 | // Teacher / platform admin menu. |
||
| 2840 | $items = [ |
||
| 2841 | 'overview' => [ |
||
| 2842 | 'icon' => 'chart-bar', |
||
| 2843 | 'title' => get_lang('Global view'), |
||
| 2844 | 'url' => $base.'index.php', |
||
| 2845 | ], |
||
| 2846 | 'students' => [ |
||
| 2847 | 'icon' => 'account-star', |
||
| 2848 | 'title' => get_lang('Learners'), |
||
| 2849 | 'url' => $base.'student.php', |
||
| 2850 | ], |
||
| 2851 | 'teachers' => [ |
||
| 2852 | 'icon' => 'human-male-board', |
||
| 2853 | 'title' => get_lang('Teachers'), |
||
| 2854 | 'url' => $base.'teachers.php', |
||
| 2855 | ], |
||
| 2856 | ]; |
||
| 2857 | |||
| 2858 | if ($isPlatformAdmin) { |
||
| 2859 | $items['admin_view'] = [ |
||
| 2860 | 'icon' => 'star-outline', |
||
| 2861 | 'title' => get_lang('Admin view'), |
||
| 2862 | 'url' => $base.'admin_view.php', |
||
| 2863 | ]; |
||
| 2864 | $items['exams'] = [ |
||
| 2865 | 'icon' => 'order-bool-ascending-variant', |
||
| 2866 | 'title' => get_lang('Exam tracking'), |
||
| 2867 | 'url' => api_get_path(WEB_CODE_PATH).'tracking/exams.php', |
||
| 2868 | ]; |
||
| 2869 | $items['current_courses'] = [ |
||
| 2870 | 'icon' => 'book-open-page-variant', |
||
| 2871 | 'title' => get_lang('Current courses report'), |
||
| 2872 | 'url' => $base.'current_courses.php', |
||
| 2873 | ]; |
||
| 2874 | $items['certificate_report'] = [ |
||
| 2875 | 'icon' => 'certificate', |
||
| 2876 | 'title' => get_lang('See list of learner certificates'), |
||
| 2877 | 'url' => api_get_path(WEB_CODE_PATH).'gradebook/certificate_report.php', |
||
| 2878 | ]; |
||
| 2879 | } |
||
| 2880 | } |
||
| 2881 | |||
| 2882 | $html = ''; |
||
| 2883 | |||
| 2884 | foreach ($items as $name => $item) { |
||
| 2885 | $iconClass = $name === $current ? 'ch-tool-icon-disabled' : 'ch-tool-icon'; |
||
| 2886 | $url = $name === $current ? '' : $item['url']; |
||
| 2887 | |||
| 2888 | $html .= self::url( |
||
| 2889 | self::getMdiIcon( |
||
| 2890 | $item['icon'], |
||
| 2891 | $iconClass, |
||
| 2892 | null, |
||
| 2893 | 32, |
||
| 2894 | $item['title'] |
||
| 2895 | ), |
||
| 2896 | $url |
||
| 2897 | ); |
||
| 2898 | } |
||
| 2899 | |||
| 2900 | return $html; |
||
| 2901 | } |
||
| 2902 | |||
| 2903 | /** |
||
| 2904 | * Reusable collapsible wrapper for "advanced parameters" sections. |
||
| 2905 | */ |
||
| 2906 | public static function advancedPanelStart( |
||
| 2938 | '; |
||
| 2939 | } |
||
| 2940 | |||
| 2941 | public static function advancedPanelEnd(): string |
||
| 2942 | { |
||
| 2943 | return ' |
||
| 2944 | </div> |
||
| 2945 | </details> |
||
| 2946 | '; |
||
| 2947 | } |
||
| 2948 | |||
| 2949 | /** |
||
| 2950 | * Render a consistent "Subscribe users to this session" header + tabs layout |
||
| 2951 | * reused across legacy admin pages (add users, usergroups, etc). |
||
| 2952 | * |
||
| 2953 | * $activeTab: users|classes|teachers|students |
||
| 2954 | * $options: |
||
| 2955 | * - return_to: string (used to preserve the "Back" destination in the Classes tab) |
||
| 2956 | * - header_title: string (defaults to get_lang('Subscribe users to this session')) |
||
| 2957 | * - users_url/classes_url/teachers_url/students_url: override URLs if needed |
||
| 2958 | * - wrapper_class: string |
||
| 2959 | * - card_class: string |
||
| 2960 | * - tabs_bar_class: string |
||
| 2961 | * - content_class: string |
||
| 2962 | */ |
||
| 2963 | public static function sessionSubscriptionPage( |
||
| 2964 | int $sessionId, |
||
| 2965 | string $sessionTitle, |
||
| 2966 | string $backUrl, |
||
| 2967 | string $activeTab, |
||
| 2968 | string $contentHtml, |
||
| 2969 | array $options = [] |
||
| 2970 | ): string { |
||
| 2971 | $safeTitle = htmlspecialchars($sessionTitle, ENT_QUOTES, api_get_system_encoding()); |
||
| 2972 | |||
| 2973 | $headerTitle = $options['header_title'] ?? get_lang('Subscribe users to this session'); |
||
| 2974 | |||
| 2975 | $returnTo = (string) ($options['return_to'] ?? ''); |
||
| 2976 | |||
| 2977 | $usersUrl = $options['users_url'] |
||
| 2978 | ?? api_get_path(WEB_CODE_PATH).'session/add_users_to_session.php?id_session='.$sessionId.'&add=true'; |
||
| 2979 | |||
| 2980 | $classesUrl = $options['classes_url'] |
||
| 2981 | ?? api_get_path(WEB_CODE_PATH).'admin/usergroups.php?from_session='.$sessionId |
||
| 2982 | .(!empty($returnTo) ? '&return_to='.rawurlencode($returnTo) : ''); |
||
| 2983 | |||
| 2984 | $teachersUrl = $options['teachers_url'] |
||
| 2985 | ?? api_get_path(WEB_CODE_PATH).'session/add_teachers_to_session.php?id='.$sessionId; |
||
| 2986 | |||
| 3067 |
Let?s assume that you have a directory layout like this:
. |-- OtherDir | |-- Bar.php | `-- Foo.php `-- SomeDir `-- Foo.phpand let?s assume the following content of
Bar.php:If both files
OtherDir/Foo.phpandSomeDir/Foo.phpare loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.phpHowever, as
OtherDir/Foo.phpdoes not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: