See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Tour helper. 19 * 20 * @package tool_usertours 21 * @copyright 2016 Andrew Nicols <andrew@nicols.co.uk> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace tool_usertours; 26 27 use core\output\inplace_editable; 28 use tool_usertours\local\clientside_filter\clientside_filter; 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 /** 33 * Tour helper. 34 * 35 * @copyright 2016 Andrew Nicols <andrew@nicols.co.uk> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class helper { 39 40 /** 41 * @var MOVE_UP 42 */ 43 const MOVE_UP = -1; 44 45 /** 46 * @var MOVE_DOWN 47 */ 48 const MOVE_DOWN = 1; 49 50 /** 51 * @var boolean Has it been bootstrapped? 52 */ 53 private static $bootstrapped = false; 54 55 /** 56 * @var string Regex to check any matching lang string. 57 */ 58 protected const LANG_STRING_REGEX = '|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|'; 59 60 /** 61 * Get the link to edit the step. 62 * 63 * If no stepid is specified, then a link to create a new step is provided. The $targettype must be specified in this case. 64 * 65 * @param int $tourid The tour that the step belongs to. 66 * @param int $stepid The step ID. 67 * @param int $targettype The type of step. 68 * 69 * @return moodle_url 70 */ 71 public static function get_edit_step_link($tourid, $stepid = null, $targettype = null) { 72 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 73 74 if ($stepid) { 75 $link->param('action', manager::ACTION_EDITSTEP); 76 $link->param('id', $stepid); 77 } else { 78 $link->param('action', manager::ACTION_NEWSTEP); 79 $link->param('tourid', $tourid); 80 } 81 82 return $link; 83 } 84 85 /** 86 * Get the link to move the tour. 87 * 88 * @param int $tourid The tour ID. 89 * @param int $direction The direction to move in 90 * 91 * @return moodle_url 92 */ 93 public static function get_move_tour_link($tourid, $direction = self::MOVE_DOWN) { 94 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 95 96 $link->param('action', manager::ACTION_MOVETOUR); 97 $link->param('id', $tourid); 98 $link->param('direction', $direction); 99 $link->param('sesskey', sesskey()); 100 101 return $link; 102 } 103 104 /** 105 * Get the link to move the step. 106 * 107 * @param int $stepid The step ID. 108 * @param int $direction The direction to move in 109 * 110 * @return moodle_url 111 */ 112 public static function get_move_step_link($stepid, $direction = self::MOVE_DOWN) { 113 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 114 115 $link->param('action', manager::ACTION_MOVESTEP); 116 $link->param('id', $stepid); 117 $link->param('direction', $direction); 118 $link->param('sesskey', sesskey()); 119 120 return $link; 121 } 122 123 /** 124 * Get the link ot create a new step. 125 * 126 * @param int $tourid The ID of the tour to attach this step to. 127 * @param int $targettype The type of target. 128 * 129 * @return moodle_url The required URL. 130 */ 131 public static function get_new_step_link($tourid, $targettype = null) { 132 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 133 $link->param('action', manager::ACTION_NEWSTEP); 134 $link->param('tourid', $tourid); 135 $link->param('targettype', $targettype); 136 137 return $link; 138 } 139 140 /** 141 * Get the link used to view the tour. 142 * 143 * @param int $tourid The ID of the tour to display. 144 * @return moodle_url The URL. 145 */ 146 public static function get_view_tour_link($tourid) { 147 return new \moodle_url('/admin/tool/usertours/configure.php', [ 148 'id' => $tourid, 149 'action' => manager::ACTION_VIEWTOUR, 150 ]); 151 } 152 153 /** 154 * Get the link used to reset the tour state for all users. 155 * 156 * @param int $tourid The ID of the tour to display. 157 * @return moodle_url The URL. 158 */ 159 public static function get_reset_tour_for_all_link($tourid) { 160 return new \moodle_url('/admin/tool/usertours/configure.php', [ 161 'id' => $tourid, 162 'action' => manager::ACTION_RESETFORALL, 163 'sesskey' => sesskey(), 164 ]); 165 } 166 167 /** 168 * Get the link used to edit the tour. 169 * 170 * @param int $tourid The ID of the tour to edit. 171 * @return moodle_url The URL. 172 */ 173 public static function get_edit_tour_link($tourid = null) { 174 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 175 176 if ($tourid) { 177 $link->param('action', manager::ACTION_EDITTOUR); 178 $link->param('id', $tourid); 179 } else { 180 $link->param('action', manager::ACTION_NEWTOUR); 181 } 182 183 return $link; 184 } 185 186 /** 187 * Get the link used to import the tour. 188 * 189 * @return moodle_url The URL. 190 */ 191 public static function get_import_tour_link() { 192 $link = new \moodle_url('/admin/tool/usertours/configure.php', [ 193 'action' => manager::ACTION_IMPORTTOUR, 194 ]); 195 196 return $link; 197 } 198 199 /** 200 * Get the link used to export the tour. 201 * 202 * @param int $tourid The ID of the tour to export. 203 * @return moodle_url The URL. 204 */ 205 public static function get_export_tour_link($tourid) { 206 $link = new \moodle_url('/admin/tool/usertours/configure.php', [ 207 'action' => manager::ACTION_EXPORTTOUR, 208 'id' => $tourid, 209 ]); 210 211 return $link; 212 } 213 214 /** 215 * Get the link used to duplicate the tour. 216 * 217 * @param int $tourid The ID of the tour to duplicate. 218 * @return moodle_url The URL. 219 */ 220 public static function get_duplicate_tour_link($tourid) { 221 $link = new \moodle_url('/admin/tool/usertours/configure.php', [ 222 'action' => manager::ACTION_DUPLICATETOUR, 223 'id' => $tourid, 224 ]); 225 226 return $link; 227 } 228 229 /** 230 * Get the link used to delete the tour. 231 * 232 * @param int $tourid The ID of the tour to delete. 233 * @return moodle_url The URL. 234 */ 235 public static function get_delete_tour_link($tourid) { 236 return new \moodle_url('/admin/tool/usertours/configure.php', [ 237 'id' => $tourid, 238 'action' => manager::ACTION_DELETETOUR, 239 'sesskey' => sesskey(), 240 ]); 241 } 242 243 /** 244 * Get the link for listing tours. 245 * 246 * @return moodle_url The URL. 247 */ 248 public static function get_list_tour_link() { 249 $link = new \moodle_url('/admin/tool/usertours/configure.php'); 250 $link->param('action', manager::ACTION_LISTTOURS); 251 252 return $link; 253 } 254 255 /** 256 * Get a filler icon for display in the actions column of a table. 257 * 258 * @param string $url The URL for the icon. 259 * @param string $icon The icon identifier. 260 * @param string $alt The alt text for the icon. 261 * @param string $iconcomponent The icon component. 262 * @param array $options Display options. 263 * @return string 264 */ 265 public static function format_icon_link($url, $icon, $alt, $iconcomponent = 'moodle', $options = array()) { 266 global $OUTPUT; 267 268 return $OUTPUT->action_icon( 269 $url, 270 new \pix_icon($icon, $alt, $iconcomponent, [ 271 'title' => $alt, 272 ]), 273 null, 274 $options 275 ); 276 277 } 278 279 /** 280 * Get a filler icon for display in the actions column of a table. 281 * 282 * @param array $options Display options. 283 * @return string 284 */ 285 public static function get_filler_icon($options = array()) { 286 global $OUTPUT; 287 288 return \html_writer::span( 289 $OUTPUT->pix_icon('t/filler', '', 'tool_usertours', $options), 290 'action-icon' 291 ); 292 } 293 294 /** 295 * Get the link for deleting steps. 296 * 297 * @param int $stepid The ID of the step to display. 298 * @return moodle_url The URL. 299 */ 300 public static function get_delete_step_link($stepid) { 301 return new \moodle_url('/admin/tool/usertours/configure.php', [ 302 'action' => manager::ACTION_DELETESTEP, 303 'id' => $stepid, 304 'sesskey' => sesskey(), 305 ]); 306 } 307 308 /** 309 * Render the inplace editable used to edit the tour name. 310 * 311 * @param tour $tour The tour to edit. 312 * @return inplace_editable 313 */ 314 public static function render_tourname_inplace_editable(tour $tour): inplace_editable { 315 $name = format_text(static::get_string_from_input($tour->get_name()), FORMAT_HTML); 316 return new inplace_editable( 317 'tool_usertours', 318 'tourname', 319 $tour->get_id(), 320 true, 321 \html_writer::link( 322 $tour->get_view_link(), 323 $name 324 ), 325 $tour->get_name() 326 ); 327 } 328 329 /** 330 * Render the inplace editable used to edit the tour description. 331 * 332 * @param tour $tour The tour to edit. 333 * @return inplace_editable 334 */ 335 public static function render_tourdescription_inplace_editable(tour $tour): inplace_editable { 336 $description = format_text(static::get_string_from_input($tour->get_description()), FORMAT_HTML); 337 return new inplace_editable( 338 'tool_usertours', 339 'tourdescription', 340 $tour->get_id(), 341 true, 342 $description, 343 $tour->get_description() 344 ); 345 } 346 347 /** 348 * Render the inplace editable used to edit the tour enable state. 349 * 350 * @param tour $tour The tour to edit. 351 * @return inplace_editable 352 */ 353 public static function render_tourenabled_inplace_editable(tour $tour): inplace_editable { 354 global $OUTPUT; 355 356 if ($tour->is_enabled()) { 357 $icon = 't/hide'; 358 $alt = get_string('disable'); 359 $value = 1; 360 } else { 361 $icon = 't/show'; 362 $alt = get_string('enable'); 363 $value = 0; 364 } 365 366 $editable = new inplace_editable( 367 'tool_usertours', 368 'tourenabled', 369 $tour->get_id(), 370 true, 371 $OUTPUT->pix_icon($icon, $alt, 'moodle', [ 372 'title' => $alt, 373 ]), 374 $value 375 ); 376 377 $editable->set_type_toggle(); 378 return $editable; 379 } 380 381 /** 382 * Render the inplace editable used to edit the step name. 383 * 384 * @param step $step The step to edit. 385 * @return inplace_editable 386 */ 387 public static function render_stepname_inplace_editable(step $step): inplace_editable { 388 $title = format_text(static::get_string_from_input($step->get_title()), FORMAT_HTML); 389 390 return new inplace_editable( 391 'tool_usertours', 392 'stepname', 393 $step->get_id(), 394 true, 395 \html_writer::link( 396 $step->get_edit_link(), 397 $title 398 ), 399 $step->get_title() 400 ); 401 } 402 403 /** 404 * Get all of the tours. 405 * 406 * @return stdClass[] 407 */ 408 public static function get_tours() { 409 global $DB; 410 411 $tours = $DB->get_records('tool_usertours_tours', array(), 'sortorder ASC'); 412 $return = []; 413 foreach ($tours as $tour) { 414 $return[$tour->id] = tour::load_from_record($tour); 415 } 416 return $return; 417 } 418 419 /** 420 * Get the specified tour. 421 * 422 * @param int $tourid The tour that the step belongs to. 423 * @return tour 424 */ 425 public static function get_tour($tourid) { 426 return tour::instance($tourid); 427 } 428 429 /** 430 * Fetch the tour with the specified sortorder. 431 * 432 * @param int $sortorder The sortorder of the tour. 433 * @return tour 434 */ 435 public static function get_tour_from_sortorder($sortorder) { 436 global $DB; 437 438 $tour = $DB->get_record('tool_usertours_tours', array('sortorder' => $sortorder)); 439 return tour::load_from_record($tour); 440 } 441 442 /** 443 * Return the count of all tours. 444 * 445 * @return int 446 */ 447 public static function count_tours() { 448 global $DB; 449 450 return $DB->count_records('tool_usertours_tours'); 451 } 452 453 /** 454 * Reset the sortorder for all tours. 455 */ 456 public static function reset_tour_sortorder() { 457 global $DB; 458 $tours = $DB->get_records('tool_usertours_tours', null, 'sortorder ASC, pathmatch DESC', 'id, sortorder'); 459 460 $index = 0; 461 foreach ($tours as $tour) { 462 if ($tour->sortorder != $index) { 463 $DB->set_field('tool_usertours_tours', 'sortorder', $index, array('id' => $tour->id)); 464 } 465 $index++; 466 } 467 468 // Notify the cache that a tour has changed. 469 // Tours are only stored in the cache if there are steps. 470 // If there step count has changed for some reason, this will change the potential cache results. 471 cache::notify_tour_change(); 472 } 473 474 475 /** 476 * Get all of the steps in the tour. 477 * 478 * @param int $tourid The tour that the step belongs to. 479 * @return step[] 480 */ 481 public static function get_steps($tourid) { 482 $steps = cache::get_stepdata($tourid); 483 484 $return = []; 485 foreach ($steps as $step) { 486 $return[$step->id] = step::load_from_record($step); 487 } 488 return $return; 489 } 490 491 /** 492 * Fetch the specified step. 493 * 494 * @param int $stepid The id of the step to fetch. 495 * @return step 496 */ 497 public static function get_step($stepid) { 498 return step::instance($stepid); 499 } 500 501 /** 502 * Fetch the step with the specified sortorder. 503 * 504 * @param int $tourid The tour that the step belongs to. 505 * @param int $sortorder The sortorder of the step. 506 * @return step 507 */ 508 public static function get_step_from_sortorder($tourid, $sortorder) { 509 global $DB; 510 511 $step = $DB->get_record('tool_usertours_steps', array('tourid' => $tourid, 'sortorder' => $sortorder)); 512 return step::load_from_record($step); 513 } 514 515 /** 516 * Handle addition of the tour into the current page. 517 */ 518 public static function bootstrap() { 519 global $PAGE; 520 521 if (!isloggedin() || isguestuser()) { 522 return; 523 } 524 525 if (in_array($PAGE->pagelayout, ['maintenance', 'print', 'redirect'])) { 526 // Do not try to show user tours inside iframe, in maintenance mode, 527 // when printing, or during redirects. 528 return; 529 } 530 531 if (self::$bootstrapped) { 532 return; 533 } 534 self::$bootstrapped = true; 535 536 $tours = manager::get_current_tours(); 537 538 if ($tours) { 539 $filters = static::get_all_clientside_filters(); 540 541 $tourdetails = array_map(function($tour) use ($filters) { 542 return [ 543 'tourId' => $tour->get_id(), 544 'startTour' => $tour->should_show_for_user(), 545 'filtervalues' => $tour->get_client_filter_values($filters), 546 ]; 547 }, $tours); 548 549 $filternames = []; 550 foreach ($filters as $filter) { 551 $filternames[] = $filter::get_filter_name(); 552 } 553 554 $PAGE->requires->js_call_amd('tool_usertours/usertours', 'init', [ 555 $tourdetails, 556 $filternames, 557 ]); 558 } 559 } 560 561 /** 562 * Get a list of all possible filters. 563 * 564 * @return array 565 */ 566 public static function get_all_filters() { 567 $filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter'); 568 $filters = array_keys($filters); 569 570 $filters = array_filter($filters, function($filterclass) { 571 $rc = new \ReflectionClass($filterclass); 572 return $rc->isInstantiable(); 573 }); 574 575 $filters = array_merge($filters, static::get_all_clientside_filters()); 576 577 return $filters; 578 } 579 580 /** 581 * Get a list of all clientside filters. 582 * 583 * @return array 584 */ 585 public static function get_all_clientside_filters() { 586 $filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\clientside_filter'); 587 $filters = array_keys($filters); 588 589 $filters = array_filter($filters, function($filterclass) { 590 $rc = new \ReflectionClass($filterclass); 591 return $rc->isInstantiable(); 592 }); 593 594 return $filters; 595 } 596 597 /** 598 * Attempt to fetch any matching langstring if the content is in the 599 * format identifier,component. 600 * 601 * @param string $content Step's content or Tour's name or Tour's description 602 * @return string Processed content, any langstring will be converted to translated text 603 */ 604 public static function get_string_from_input(string $content): string { 605 $content = trim($content); 606 607 if (preg_match(static::LANG_STRING_REGEX, $content, $matches)) { 608 if ($matches[2] === 'moodle') { 609 $matches[2] = 'core'; 610 } 611 612 if (get_string_manager()->string_exists($matches[1], $matches[2])) { 613 $content = get_string($matches[1], $matches[2]); 614 } 615 } 616 617 return $content; 618 } 619 620 /** 621 * Check if the given string contains any matching langstring. 622 * 623 * @param string $string 624 * @return bool 625 */ 626 public static function is_language_string_from_input(string $string): bool { 627 return preg_match(static::LANG_STRING_REGEX, $string) == true; 628 } 629 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body