diff --git a/availability/condition/completion/tests/behat/conditional_bug.feature b/availability/condition/completion/tests/behat/conditional_bug.feature index db2511605ee..1bc44584e78 100644 --- a/availability/condition/completion/tests/behat/conditional_bug.feature +++ b/availability/condition/completion/tests/behat/conditional_bug.feature @@ -44,6 +44,7 @@ Feature: Confirm that conditions on completion no longer cause a bug And I click on "Activity completion" "button" in the "Add restriction..." "dialogue" And I set the field with xpath "//div[contains(concat(' ', normalize-space(@class), ' '), ' availability-item ')][preceding-sibling::div]//select[@name='cm']" to "Page2" And I press "Save and return to course" + And I click on "Show more" "button" in the "#section-1 .availabilityinfo" "css_element" Then I should see "Not available unless:" in the ".activity.glossary" "css_element" And I should see "The activity Page1 is marked complete" in the ".activity.glossary" "css_element" And I should see "The activity Page2 is marked complete" in the ".activity.glossary" "css_element" diff --git a/availability/tests/behat/display_availability.feature b/availability/tests/behat/display_availability.feature index 5998d033316..b2a5d3ed045 100644 --- a/availability/tests/behat/display_availability.feature +++ b/availability/tests/behat/display_availability.feature @@ -73,13 +73,17 @@ Feature: display_availability And I should see "2013" in the "#section-1 .availabilityinfo" "css_element" And I should see "2013" in the "#section-1 .availabilityinfo" "css_element" And "li" "css_element" should not exist in the "#section-1 .availabilityinfo" "css_element" + And "Show more" "button" should not exist in the "#section-1 .availabilityinfo" "css_element" # Page 2 should show in list format. And "li" "css_element" should exist in the "#section-2 .availabilityinfo" "css_element" And I should see "Not available unless:" in the "#section-2 .availabilityinfo" "css_element" And I should see "It is before" in the "#section-2 .availabilityinfo" "css_element" And I should see "hidden otherwise" in the "#section-2 .availabilityinfo" "css_element" + And I click on "Show more" "button" in the "Page 2" "activity" And I should see "Email address" in the "#section-2 .availabilityinfo" "css_element" + And I click on "Show less" "button" in the "#section-2 .availabilityinfo" "css_element" + And I should not see "Email address" in the "#section-2 .availabilityinfo" "css_element" # Page 3 should not have available info. And "#section-3 .availabilityinfo" "css_element" should not exist @@ -114,6 +118,11 @@ Feature: display_availability And I click on "Date" "button" in the "Add restriction..." "dialogue" And I set the field "direction" to "until" And I set the field "x[year]" to "2013" + And I press "Add restriction..." + And I click on "User profile" "button" in the "Add restriction..." "dialogue" + And I set the field "User profile field" to "Email address" + And I set the field "Value to compare against" to "email@example.com" + And I set the field "Method of comparison" to "is equal to" And I press "Save changes" # Section 2 is the same but hidden from students @@ -130,7 +139,7 @@ Feature: display_availability And I am on "Course 1" course homepage # Check display - Then I should see "Available until" in the "#section-1 .availabilityinfo" "css_element" + Then I should see "Not available unless" in the "#section-1 .availabilityinfo" "css_element" And I should see "Available until" in the "#section-2 .availabilityinfo" "css_element" And I should see "hidden otherwise" in the "#section-2 .availabilityinfo" "css_element" @@ -144,7 +153,11 @@ Feature: display_availability # Section 1 should be visible and show info. And I should see "Topic 1" in the "region-main" "region" - And I should see "Available until" in the "#section-1 .availabilityinfo" "css_element" + And I should see "Not available unless" in the "#section-1 .availabilityinfo" "css_element" + And I click on "Show more" "button" in the "#section-1 .availabilityinfo" "css_element" + And I should see "Email address" in the "#section-1 .availabilityinfo" "css_element" + And I click on "Show less" "button" in the "#section-1 .availabilityinfo" "css_element" + And I should not see "Email address" in the "#section-1 .availabilityinfo" "css_element" # Section 2 should not be available at all And I should not see "Topic 2" in the "region-main" "region" diff --git a/course/format/classes/output/local/content/cm/availability.php b/course/format/classes/output/local/content/cm/availability.php index dbe249f6e01..9776c9eccfc 100644 --- a/course/format/classes/output/local/content/cm/availability.php +++ b/course/format/classes/output/local/content/cm/availability.php @@ -108,11 +108,7 @@ class availability extends section_avalability { } $info = []; - $formattedinfo = \core_availability\info::format_info( - $this->mod->availableinfo, - $this->mod->get_course() - ); - $info[] = $this->availability_info($formattedinfo, 'isrestricted'); + $info[] = $this->get_availability_data($output, $this->mod->availableinfo, 'isrestricted'); return $info; } @@ -151,11 +147,7 @@ class availability extends section_avalability { if (!$mod->visible) { $hidinfoclass .= ' hide'; } - $formattedinfo = info::format_info( - $fullinfo, - $mod->get_course() - ); - $info[] = $this->availability_info($formattedinfo, $hidinfoclass); + $info[] = $this->get_availability_data($output, $fullinfo, $hidinfoclass); return $info; } diff --git a/course/format/classes/output/local/content/section/availability.php b/course/format/classes/output/local/content/section/availability.php index a183aa3eed2..2d24ff1728c 100644 --- a/course/format/classes/output/local/content/section/availability.php +++ b/course/format/classes/output/local/content/section/availability.php @@ -25,6 +25,7 @@ namespace core_courseformat\output\local\content\section; use context_course; +use core_availability_multiple_messages; use core\output\named_templatable; use core_availability\info; use core_availability\info_section; @@ -57,6 +58,9 @@ class availability implements named_templatable, renderable { /** @var stdClass|null the instance export data */ protected $data = null; + /** @var int Availability excerpt text max size treshold */ + protected const AVAILABILITY_EXCERPT_MAXSIZE = 100; + /** * Constructor. * @@ -124,7 +128,7 @@ class availability implements named_templatable, renderable { * are going to be unavailable etc). This logic is the same as for * activities. * - * @param renderer_base $output typically, the renderer that's calling this function + * @param \renderer_base $output typically, the renderer that's calling this function * @return stdclass data context for a mustache template */ protected function get_info(\renderer_base $output): array { @@ -142,30 +146,115 @@ class availability implements named_templatable, renderable { if ($section->availableinfo) { // Note: We only get to this function if availableinfo is non-empty, // so there is definitely something to print. - $formattedinfo = info::format_info($section->availableinfo, $section->course); - $info[] = $this->availability_info($formattedinfo, 'isrestricted'); + $info[] = $this->get_availability_data($output, $section->availableinfo, 'isrestricted'); } } else if ($canviewhidden && !empty($CFG->enableavailability)) { // Check if there is an availability restriction. $ci = new info_section($section); $fullinfo = $ci->get_full_information(); if ($fullinfo) { - $formattedinfo = info::format_info($fullinfo, $section->course); - $info[] = $this->availability_info($formattedinfo, 'isrestricted isfullinfo'); + $info[] = $this->get_availability_data($output, $fullinfo, 'isrestricted isfullinfo'); } } return $info; } + /** + * Get the basic availability information data. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @param string|core_availability_multiple_messages $availabilityinfo the avalability info + * @param string $additionalclasses additional css classes + * @return stdClass the availability information data + */ + protected function get_availability_data($output, $availabilityinfo, $additionalclasses = ''): stdClass { + // At this point, availabilityinfo is either a string or a renderable. We need to handle both cases in a different way. + if (is_string($availabilityinfo)) { + $data = $this->availability_info_from_string($output, $availabilityinfo); + } else { + $data = $this->availability_info_from_output($output, $availabilityinfo); + } + + $data->classes = $additionalclasses; + + $additionalclasses = array_filter(explode(' ', $additionalclasses)); + if (in_array('ishidden', $additionalclasses)) { + $data->ishidden = 1; + } else if (in_array('isstealth', $additionalclasses)) { + $data->isstealth = 1; + } else if (in_array('isrestricted', $additionalclasses)) { + $data->isrestricted = 1; + if (in_array('isfullinfo', $additionalclasses)) { + $data->isfullinfo = 1; + } + } + + return $data; + } + + /** + * Generate the basic availability information data from a string. + * Just shorten availability text to generate the excerpt text. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @param string $availabilityinfo the avalability info + * @return stdClass the availability information data + */ + protected function availability_info_from_string(\renderer_base $output, string $availabilityinfo): stdClass { + $course = $this->format->get_course(); + + $text = info::format_info($availabilityinfo, $course); + $data = ['text' => $text]; + + if (strlen(html_to_text($text)) > self::AVAILABILITY_EXCERPT_MAXSIZE) { + $data['excerpt'] = shorten_text($text, self::AVAILABILITY_EXCERPT_MAXSIZE); + } + + return (object) $data; + } + + /** + * Generate the basic availability information data from a renderable. + * Use the header and the first item to generate the excerpt text. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @param core_availability_multiple_messages $availabilityinfo the avalability info + * @return stdClass the availability information data + */ + protected function availability_info_from_output( + \renderer_base $output, + core_availability_multiple_messages $availabilityinfo + ): stdClass { + $course = $this->format->get_course(); + + $renderable = new \core_availability\output\availability_info($availabilityinfo); + // We need to export_for_template() instead of directly render, to reuse the info for both 'text' and 'excerpt'. + $info = $renderable->export_for_template($output); + + $text = $output->render_from_template('core_availability/availability_info', $info); + $data = ['text' => info::format_info($text, $course)]; + + if (!empty($info->items)) { + $excerpttext = $info->header . ' ' . $info->items[0]->header; + $data['excerpt'] = info::format_info($excerpttext, $course); + } + + return (object) $data; + } + /** * Generate the basic availability information data. * + * @deprecated since Moodle 4.3 MDL-78204. Please use {@see self::get_availability_data} instead. + * @todo MDL-78489 This will be deleted in Moodle 4.7. * @param string $text the formatted avalability text * @param string $additionalclasses additional css classes * @return stdClass the availability information data */ protected function availability_info($text, $additionalclasses = ''): stdClass { + debugging('Use of ' . __FUNCTION__ . '() have been deprecated, ' . + 'please use core_courseformat\output\local\content\section\availability::get_availability_data()', DEBUG_DEVELOPER); $data = (object)[ 'text' => $text, diff --git a/course/format/templates/local/content/availability.mustache b/course/format/templates/local/content/availability.mustache new file mode 100644 index 00000000000..1e899660226 --- /dev/null +++ b/course/format/templates/local/content/availability.mustache @@ -0,0 +1,43 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template core_courseformat/local/content/availability + + Displays the availability contents with excerpt version if needed. + + Example context (json): + { + "text": "Not available unless: ", + "excerpt": "Not available unless: It is on or after 8 June 2012" + } +}} +{{^excerpt}} + {{#pix}}t/unlock, core{{/pix}} {{{text}}} +{{/excerpt}} +{{#excerpt}} + {{< core/showmore }} + {{$collapsedcontent}} + {{#pix}}t/unlock, core{{/pix}} {{{excerpt}}} ... + {{/collapsedcontent}} + {{$expandedcontent}} + {{#pix}}t/unlock, core{{/pix}} {{{text}}} + {{/expandedcontent}} + {{$buttonextraclasses}}font-weight-bold{{/buttonextraclasses}} + {{$collapsedextraclasses}}text-truncate pr-2{{/collapsedextraclasses}} + {{$expandedextraclasses}}py-2{{/expandedextraclasses}} + {{/core/showmore }} +{{/excerpt}} diff --git a/course/format/templates/local/content/cm/availability.mustache b/course/format/templates/local/content/cm/availability.mustache index e59ece9b272..e473f3a0b3e 100644 --- a/course/format/templates/local/content/cm/availability.mustache +++ b/course/format/templates/local/content/cm/availability.mustache @@ -41,7 +41,7 @@ {{{text}}} {{/isrestricted}} {{#isrestricted}} -
{{#pix}}t/unlock, core{{/pix}} {{{text}}}
+ {{> core_courseformat/local/content/availability }} {{/isrestricted}} {{/info}} diff --git a/course/format/templates/local/content/section/availability.mustache b/course/format/templates/local/content/section/availability.mustache index 7c6448011bb..6b7008fe619 100644 --- a/course/format/templates/local/content/section/availability.mustache +++ b/course/format/templates/local/content/section/availability.mustache @@ -41,7 +41,7 @@ {{{text}}} {{/isrestricted}} {{#isrestricted}} -
{{#pix}}t/unlock, core{{/pix}} {{{text}}}
+ {{> core_courseformat/local/content/availability }} {{/isrestricted}} {{/info}} diff --git a/course/format/upgrade.txt b/course/format/upgrade.txt index 7350a841100..c17b2b4702d 100644 --- a/course/format/upgrade.txt +++ b/course/format/upgrade.txt @@ -12,6 +12,8 @@ Some considerations about the activitybadge feature: - An optional URL to redirect the user when the badge is clicked. - An optional ID to add the element in case the module wants to add some JS to the badge events. - Optionally, any other extra HTML attributes to the badge element (for example, data attributes). +* Protected function `core_courseformat\output\local\content\section\availability::availability_info()` has been deprecated, +`core_courseformat\output\local\content\section\availability::get_availability_data()` should be used instead. === 4.2 === * New core_courseformat\base::get_context() to get the course context directly from the format instance.