diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 30284ef3dac..eb3da9c37d3 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -3061,6 +3061,121 @@ class paging_bar implements renderable, templatable { } } +/** + * Component representing initials bar. + * + * @copyright 2017 Ilya Tregubov + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.3 + * @package core + * @category output + */ +class initials_bar implements renderable, templatable { + + /** + * @var string Currently selected letter. + */ + public $current; + + /** + * @var string Class name to add to this initial bar. + */ + public $class; + + /** + * @var string The name to put in front of this initial bar. + */ + public $title; + + /** + * @var string URL parameter name for this initial. + */ + public $urlvar; + + /** + * @var string URL object. + */ + public $url; + + /** + * @var array An array of letters in the alphabet. + */ + public $alpha; + + /** + * Constructor initials_bar with only the required params. + * + * @param string $current the currently selected letter. + * @param string $class class name to add to this initial bar. + * @param string $title the name to put in front of this initial bar. + * @param string $urlvar URL parameter name for this initial. + * @param string $url URL object. + * @param array $alpha of letters in the alphabet. + */ + public function __construct($current, $class, $title, $urlvar, $url, $alpha = null) { + $this->current = $current; + $this->class = $class; + $this->title = $title; + $this->urlvar = $urlvar; + $this->url = $url; + $this->alpha = $alpha; + } + + /** + * Export for template. + * + * @param renderer_base $output The renderer. + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + $data = new stdClass(); + + if ($this->alpha == null) { + $this->alpha = explode(',', get_string('alphabet', 'langconfig')); + } + + if ($this->current == 'all') { + $this->current = ''; + } + + // We want to find a letter grouping size which suits the language so + // find the largest group size which is less than 15 chars. + // The choice of 15 chars is the largest number of chars that reasonably + // fits on the smallest supported screen size. By always using a max number + // of groups which is a factor of 2, we always get nice wrapping, and the + // last row is always the shortest. + $groupsize = count($this->alpha); + $groups = 1; + while ($groupsize > 15) { + $groups *= 2; + $groupsize = ceil(count($this->alpha) / $groups); + } + + $groupsizelimit = 0; + $groupnumber = 0; + foreach ($this->alpha as $letter) { + if ($groupsizelimit++ > 0 && $groupsizelimit % $groupsize == 1) { + $groupnumber++; + } + $groupletter = new stdClass(); + $groupletter->name = $letter; + $groupletter->url = $this->url->out(false, array($this->urlvar => $letter)); + if ($letter == $this->current) { + $groupletter->selected = $this->current; + } + $data->group[$groupnumber]->letter[] = $groupletter; + } + + $data->class = $this->class; + $data->title = $this->title; + $data->url = $this->url->out(false, array($this->urlvar => '')); + $data->current = $this->current; + $data->all = get_string('all'); + + return $data; + } +} + /** * This class represents how a block appears on a page. * diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 22eaf1e9812..c57bb73bec3 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -2925,6 +2925,32 @@ EOD; return html_writer::tag('div', $output, array('class' => 'paging')); } + /** + * Returns HTML to display initials bar to provide access to other pages (usually in a search) + * + * @param string $current the currently selected letter. + * @param string $class class name to add to this initial bar. + * @param string $title the name to put in front of this initial bar. + * @param string $urlvar URL parameter name for this initial. + * @param string $url URL object. + * @param array $alpha of letters in the alphabet. + * @return string the HTML to output. + */ + public function initials_bar($current, $class, $title, $urlvar, $url, $alpha = null) { + $ib = new initials_bar($current, $class, $title, $urlvar, $url, $alpha); + return $this->render($ib); + } + + /** + * Internal implementation of initials bar rendering. + * + * @param initials_bar $initialsbar + * @return string + */ + protected function render_initials_bar(initials_bar $initialsbar) { + return $this->render_from_template('core/initials_bar', $initialsbar->export_for_template($this)); + } + /** * Output the place a skip link goes to. * diff --git a/lib/tablelib.php b/lib/tablelib.php index 59c17a190c7..84d077b5011 100644 --- a/lib/tablelib.php +++ b/lib/tablelib.php @@ -907,8 +907,12 @@ class flexible_table { /** * This function is not part of the public api. * @return string initial of first name we are currently filtering by + * + * @deprecated since Moodle 3.3 */ function get_initial_first() { + debugging('Method get_initial_first() is no longer used and has been deprecated, ' . + 'to print initials bar call print_initials_bar()', DEBUG_DEVELOPER); if (!$this->use_initials) { return NULL; } @@ -919,8 +923,12 @@ class flexible_table { /** * This function is not part of the public api. * @return string initial of last name we are currently filtering by + * + * @deprecated since Moodle 3.3 */ function get_initial_last() { + debugging('Method get_initial_last() is no longer used and has been deprecated, ' . + 'to print initials bar call print_initials_bar()', DEBUG_DEVELOPER); if (!$this->use_initials) { return NULL; } @@ -935,44 +943,29 @@ class flexible_table { * @param string $class class name to add to this initial bar. * @param string $title the name to put in front of this initial bar. * @param string $urlvar URL parameter name for this initial. + * + * @deprecated since Moodle 3.3 */ protected function print_one_initials_bar($alpha, $current, $class, $title, $urlvar) { + + debugging('Method print_one_initials_bar() is no longer used and has been deprecated, ' . + 'to print initials bar call print_initials_bar()', DEBUG_DEVELOPER); + echo html_writer::start_tag('div', array('class' => 'initialbar ' . $class)) . - html_writer::tag('span', $title . ': ', array('class' => 'initialbarlabel')); + $title . ' : '; if ($current) { - echo html_writer::link($this->baseurl->out(false, array($urlvar => '')), - get_string('all'), array('class' => 'initialbarall')); + echo html_writer::link($this->baseurl->out(false, array($urlvar => '')), get_string('all')); } else { - echo html_writer::tag('strong', get_string('all'), array('class' => 'initialbarall')); + echo html_writer::tag('strong', get_string('all')); } - // We want to find a letter grouping size which suits the language so - // find the largest group size which is less than 15 chars. By always - // using a max number of groups which is a factor of 2, we always get - // nice wrapping, and the last row is always the shortest. - $groupsize = count($alpha); - $groups = 1; - while ($groupsize > 15) { - $groups *= 2; - $groupsize = ceil(count($alpha) / $groups); - } - - echo html_writer::start_tag('span', array('class' => 'initialbargroups')); - echo html_writer::start_tag('span', array('class' => 'initialbargroup')); - $c = 0; foreach ($alpha as $letter) { - if ($c++ > 0 && $c % $groupsize == 1) { - echo html_writer::end_tag('span') . ' '; - echo html_writer::start_tag('span', array('class' => 'initialbargroup')); - } if ($letter === $current) { echo html_writer::tag('strong', $letter); } else { echo html_writer::link($this->baseurl->out(false, array($urlvar => $letter)), $letter); } } - echo html_writer::end_tag('span'); - echo html_writer::end_tag('span'); echo html_writer::end_tag('div'); } @@ -981,29 +974,29 @@ class flexible_table { * This function is not part of the public api. */ function print_initials_bar() { + global $OUTPUT; + if ((!empty($this->prefs['i_last']) || !empty($this->prefs['i_first']) ||$this->use_initials) - && isset($this->columns['fullname'])) { + && isset($this->columns['fullname'])) { - $alpha = explode(',', get_string('alphabet', 'langconfig')); - - // Bar of first initials if (!empty($this->prefs['i_first'])) { $ifirst = $this->prefs['i_first']; } else { $ifirst = ''; } - $this->print_one_initials_bar($alpha, $ifirst, 'firstinitial', - get_string('firstname'), $this->request[TABLE_VAR_IFIRST]); - // Bar of last initials if (!empty($this->prefs['i_last'])) { $ilast = $this->prefs['i_last']; } else { $ilast = ''; } - $this->print_one_initials_bar($alpha, $ilast, 'lastinitial', - get_string('lastname'), $this->request[TABLE_VAR_ILAST]); + + $prefixfirst = $this->request[TABLE_VAR_IFIRST]; + $prefixlast = $this->request[TABLE_VAR_ILAST]; + echo $OUTPUT->initials_bar($ifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $this->baseurl); + echo $OUTPUT->initials_bar($ilast, 'lastinitial', get_string('lastname'), $prefixlast, $this->baseurl); } + } /** diff --git a/lib/templates/initials_bar.mustache b/lib/templates/initials_bar.mustache new file mode 100644 index 00000000000..dcb7001c2b3 --- /dev/null +++ b/lib/templates/initials_bar.mustache @@ -0,0 +1,100 @@ +{{! + 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/initials_bar + + Initials bar. + + Example context (json): + { + "title": "First name", + "class": "firstinitial", + "current": "A", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst", + "all": "All", + "group": [ + { + "letter": [ + { + "name": "A", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=A" + }, + { + "name": "B", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=B" + }, + { + "name": "C", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=C" + }, + { + "name": "D", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=D" + } + + ] + }, + { + "letter": [ + { + "name": "W", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=W", + "selected": "W" + }, + { + "name": "X", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=X" + }, + { + "name": "Y", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=Y" + }, + { + "name": "Z", + "url": "http://moodle.generic32/report/progress/index.php?course=2&sifirst=Z" + } + + ] + } + ] + } +}} +
+ {{title}} + {{#current}} + {{all}} + {{/current}} + {{^current}} +
{{all}}
+ {{/current}} + +
+ {{#group}} +
    + {{#letter}} + {{#selected}} +
  • {{name}}
  • + {{/selected}} + {{^selected}} +
  • {{name}}
  • + {{/selected}} + {{/letter}} +
+ {{/group}} +
+
+ diff --git a/lib/tests/behat/alpha_chooser.feature b/lib/tests/behat/alpha_chooser.feature new file mode 100644 index 00000000000..f42a500b741 --- /dev/null +++ b/lib/tests/behat/alpha_chooser.feature @@ -0,0 +1,380 @@ +@core +Feature: Initials bar + In order to filter users from user list + As an admin + I need to be able to use letter filters + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | teacher | Ateacher | Teacher | teacher@example.com | + | student1 | Astudent | Astudent | student1@example.com | + | student2 | Bstudent | Astudent | student2@example.com | + | student3 | Cstudent | Cstudent | student3@example.com | + | student4 | Cstudent | Cstudent | student4@example.com | + | student5 | Cstudent | Cstudent | student5@example.com | + | student6 | Cstudent | Cstudent | student6@example.com | + | student7 | Cstudent | Cstudent | student7@example.com | + | student8 | Cstudent | Cstudent | student8@example.com | + | student9 | Cstudent | Cstudent | student9@example.com | + | student10 | Cstudent | Cstudent | student10@example.com | + | student11 | Cstudent | Cstudent | student11@example.com | + | student12 | Cstudent | Cstudent | student12@example.com | + | student13 | Cstudent | Cstudent | student13@example.com | + | student14 | Cstudent | Cstudent | student14@example.com | + | student15 | Cstudent | Cstudent | student15@example.com | + | student16 | Cstudent | Cstudent | student16@example.com | + | student17 | Cstudent | Cstudent | student17@example.com | + | student18 | Cstudent | Cstudent | student18@example.com | + | student19 | Cstudent | Cstudent | student19@example.com | + | student20 | Cstudent | Cstudent | student20@example.com | + | student21 | Cstudent | Cstudent | student21@example.com | + | student22 | Cstudent | Cstudent | student22@example.com | + | student23 | Cstudent | Cstudent | student23@example.com | + | student24 | Cstudent | Cstudent | student24@example.com | + + And the following "courses" exist: + | fullname | shortname | category |enablecompletion | + | Course 1 | C1 | 0 | 1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + | student4 | C1 | student | + | student5 | C1 | student | + | student6 | C1 | student | + | student7 | C1 | student | + | student8 | C1 | student | + | student9 | C1 | student | + | student10 | C1 | student | + | student11 | C1 | student | + | student12 | C1 | student | + | student13 | C1 | student | + | student14 | C1 | student | + | student15 | C1 | student | + | student16 | C1 | student | + | student17 | C1 | student | + | student18 | C1 | student | + | student19 | C1 | student | + | student20 | C1 | student | + | student21 | C1 | student | + | student22 | C1 | student | + | student23 | C1 | student | + | student24 | C1 | student | + + @javascript + Scenario: Filter users on assignment submission page + Given the following "activities" exist: + | activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | + | assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 | + And I log in as "teacher" + And I follow "Course 1" + And I follow "TestAssignment" + When I navigate to "View all submissions" in current page administration + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + And I click on "A" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "B" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I am on homepage + And I follow "Course 1" + And I follow "TestAssignment" + When I navigate to "View all submissions" in current page administration + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + + @javascript + Scenario: Filter users on view gradebook page + Given the following "activities" exist: + | activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | + | assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 | + And I log in as "teacher" + And I follow "Course 1" + And I follow "TestAssignment" + When I navigate to "View all submissions" in current page administration + And I select "View gradebook" from the "jump" singleselect + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + And I click on "A" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "B" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I am on homepage + And I follow "Course 1" + And I follow "TestAssignment" + When I navigate to "View all submissions" in current page administration + And I select "View gradebook" from the "jump" singleselect + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + + @javascript + Scenario: Filter users on course participants page + Given the following "activities" exist: + | activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | + | assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 | + And I log in as "teacher" + And I follow "Course 1" + And I follow "Participants" + And I select "Brief" from the "mode" singleselect + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + And I click on "A" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "B" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I am on homepage + And I follow "Course 1" + And I follow "Participants" + And I select "Brief" from the "mode" singleselect + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + + @javascript + Scenario: Filter users on course participants page + Given the following "activities" exist: + | activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | + | assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 | + And I log in as "teacher" + And I follow "Course 1" + And I follow "Participants" + And I select "User details" from the "mode" singleselect + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + And I click on "A" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "B" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I am on homepage + And I follow "Course 1" + And I follow "Participants" + And I select "User details" from the "mode" singleselect + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + + @javascript + Scenario: Filter users on activity completion page + Given the following "activities" exist: + | activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | + | assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 | + And I log in as "admin" + And I am on site homepage + And I follow "Course 1" + And I follow "TestAssignment" + And I navigate to "Edit settings" in current page administration + And I expand all fieldsets + And I set the field "Completion tracking" to "1" + And I click on "Save and return to course" "button" + And I navigate to "Course completion" in current page administration + And I expand all fieldsets + And I click on "Assignment - TestAssignment" "checkbox" + And I click on "Save changes" "button" + And I log out + And I log in as "teacher" + And I follow "Course 1" + And I navigate to "More..." in current page administration + And I follow "Activity completion" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" + And I click on "A" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "B" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I am on homepage + And I follow "Course 1" + And I navigate to "More..." in current page administration + And I follow "Activity completion" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should not see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should not see "Cstudent Cstudent" + And I click on "All" "link" in the ".initialbar.lastinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element" + And ".initialbarall.letter.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element" + And ".letter.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element" + And ".letter.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element" + And I should see "Astudent Astudent" + And I should see "Bstudent Astudent" + And I should see "Cstudent Cstudent" diff --git a/report/completion/index.php b/report/completion/index.php index d4db15bf3e5..b4479b9e4d9 100644 --- a/report/completion/index.php +++ b/report/completion/index.php @@ -160,6 +160,25 @@ if ($csv) { groups_print_course_menu($course, $CFG->wwwroot.'/report/completion/?course='.$course->id); } +if ($sifirst !== 'all') { + set_user_preference('ifirst', $sifirst); +} +if ($silast !== 'all') { + set_user_preference('ilast', $silast); +} + +if (!empty($USER->preference['ifirst'])) { + $sifirst = $USER->preference['ifirst']; +} else { + $sifirst = 'all'; +} + +if (!empty($USER->preference['ilast'])) { + $silast = $USER->preference['ilast']; +} else { + $silast = 'all'; +} + // Generate where clause $where = array(); $where_params = array(); @@ -209,38 +228,13 @@ if (strlen($sort)) { } $link .= '&start='; -// Build the the page by Initial bar -$initials = array('first', 'last'); -$alphabet = explode(',', get_string('alphabet', 'langconfig')); - $pagingbar = ''; -foreach ($initials as $initial) { - $var = 'si'.$initial; - $othervar = $initial == 'first' ? 'silast' : 'sifirst'; - $othervar = $$othervar != 'all' ? "&{$othervar}={$$othervar}" : ''; - - $pagingbar .= '
'; - $pagingbar .= get_string($initial.'name').': '; - - if ($$var == 'all') { - $pagingbar .= ''.get_string('all').' '; - } - else { - $pagingbar .= "".get_string('all').' '; - } - - foreach ($alphabet as $letter) { - if ($$var === $letter) { - $pagingbar .= ''.$letter.' '; - } - else { - $pagingbar .= "$letter "; - } - } - - $pagingbar .= '
'; -} +// Initials bar. +$prefixfirst = 'sifirst'; +$prefixlast = 'silast'; +$pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $url); +$pagingbar .= $OUTPUT->initials_bar($silast, 'lastinitial', get_string('lastname'), $prefixlast, $url); // Do we need a paging bar? if ($total > COMPLETION_REPORT_PAGE) { diff --git a/report/progress/index.php b/report/progress/index.php index c97d4a68228..2895e1343f1 100644 --- a/report/progress/index.php +++ b/report/progress/index.php @@ -94,6 +94,25 @@ $reportsurl = $CFG->wwwroot.'/course/report.php?id='.$course->id; $completion = new completion_info($course); $activities = $completion->get_activities(); +if ($sifirst !== 'all') { + set_user_preference('ifirst', $sifirst); +} +if ($silast !== 'all') { + set_user_preference('ilast', $silast); +} + +if (!empty($USER->preference['ifirst'])) { + $sifirst = $USER->preference['ifirst']; +} else { + $sifirst = 'all'; +} + +if (!empty($USER->preference['ilast'])) { + $silast = $USER->preference['ilast']; +} else { + $silast = 'all'; +} + // Generate where clause $where = array(); $where_params = array(); @@ -179,38 +198,13 @@ if (strlen($sort)) { } $link .= '&start='; -// Build the the page by Initial bar -$initials = array('first', 'last'); -$alphabet = explode(',', get_string('alphabet', 'langconfig')); - $pagingbar = ''; -foreach ($initials as $initial) { - $var = 'si'.$initial; - $othervar = $initial == 'first' ? 'silast' : 'sifirst'; - $othervar = $$othervar != 'all' ? "&{$othervar}={$$othervar}" : ''; - - $pagingbar .= '
'; - $pagingbar .= get_string($initial.'name').': '; - - if ($$var == 'all') { - $pagingbar .= ''.get_string('all').' '; - } - else { - $pagingbar .= "".get_string('all').' '; - } - - foreach ($alphabet as $letter) { - if ($$var === $letter) { - $pagingbar .= ''.$letter.' '; - } - else { - $pagingbar .= "$letter "; - } - } - - $pagingbar .= '
'; -} +// Initials bar. +$prefixfirst = 'sifirst'; +$prefixlast = 'silast'; +$pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $url); +$pagingbar .= $OUTPUT->initials_bar($silast, 'lastinitial', get_string('lastname'), $prefixlast, $url); // Do we need a paging bar? if ($total > COMPLETION_REPORT_PAGE) { diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index 9b929ecb246..c7a3be970ad 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -1093,13 +1093,80 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { } .initialbar { - a, - strong { - padding-left: 3px; - padding-right: 3px; + + overflow: auto; + + .initialbarlabel { + display: inline-block; + width: 6em; + float: left; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .initialbarall { + float: left; + width: 4em; + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .initialbargroups { + float: left; + } + + .initialbargroup { + float: left; + display: inline-block; + white-space: nowrap; + margin: 0; + padding: 0; + + li { + float: left; + list-style: none; + } + } + + .letter { + display: inline-block; + height: 1.5em; + min-width: 1.5em; + text-align: center; + + color: $pagination-color; + border-width: $pagination-border-width; + border-color: $pagination-border-color; + border-style: solid; + background-color: $pagination-bg; + } + .letter:hover { + color: $pagination-hover-color; + border-color: $pagination-hover-border; + background-color: $pagination-hover-bg; + } + + .letter.active { + color: $pagination-active-color; + border-color: $pagination-active-border; + background-color: $pagination-active-bg; + } + +} + +@media (max-width: 400px) { + .initialbar { + .letter { + /* This is chosen so that 23 letter at 320px just fits */ + font-size: 11.5px; + } } } + /* Moodle Dialogue Settings (moodle-core-dialogue) */ .moodle-dialogue-base .moodle-dialogue-lightbox { background-color: $gray; diff --git a/theme/bootstrapbase/less/moodle/core.less b/theme/bootstrapbase/less/moodle/core.less index 9b4156c354a..a927e3c5ec2 100644 --- a/theme/bootstrapbase/less/moodle/core.less +++ b/theme/bootstrapbase/less/moodle/core.less @@ -1266,6 +1266,7 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { white-space: nowrap; text-align: center; } + .initialbar { overflow: auto; @@ -1279,6 +1280,15 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { white-space: nowrap; } + .initialbarall { + float: left; + width: 4em; + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .initialbargroups { float: left; } @@ -1287,30 +1297,35 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { float: left; display: inline-block; white-space: nowrap; - } + margin: 0; + padding: 0; - a, - strong { - display: inline-block; - min-width: 1.4em; - text-align: center; - - &.initialbarall { + li { float: left; - width: 4em; - margin-bottom: 2px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + list-style: none; } } - strong { - background: @linkColor; - color: @bodyBackground; + .letter { + display: inline-block; + height: 1.35em; + min-width: 1.35em; + text-align: center; + + color: @linkColor; + background: @paginationBackground; + border-width: 1px; + border-color: @paginationBorder; + border-style: solid; + } + .letter:hover, + .letter.active { + color: white; + background-color: @linkColor; } } + /* Moodle Dialogue Settings (moodle-core-dialogue) */ .moodle-dialogue-base .moodle-dialogue-lightbox { background-color: #aaa; diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index b4a44b0185b..719e704b875 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -3610,10 +3610,54 @@ body#page-lib-editor-tinymce-plugins-moodlemedia-preview { white-space: nowrap; text-align: center; } -.initialbar a, -.initialbar strong { - padding-left: 3px; - padding-right: 3px; +.initialbar { + overflow: auto; +} +.initialbar .initialbarlabel { + display: inline-block; + width: 6em; + float: left; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.initialbar .initialbarall { + float: left; + width: 4em; + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.initialbar .initialbargroups { + float: left; +} +.initialbar .initialbargroup { + float: left; + display: inline-block; + white-space: nowrap; + margin: 0; + padding: 0; +} +.initialbar .initialbargroup li { + float: left; + list-style: none; +} +.initialbar .letter { + display: inline-block; + height: 1.35em; + min-width: 1.35em; + text-align: center; + color: #0070a8; + background: #fff; + border-width: 1px; + border-color: #ddd; + border-style: solid; +} +.initialbar .letter:hover, +.initialbar .letter.active { + color: white; + background-color: #0070a8; } /* Moodle Dialogue Settings (moodle-core-dialogue) */ .moodle-dialogue-base .moodle-dialogue-lightbox { @@ -10290,7 +10334,6 @@ body.path-question-type .mform fieldset.hidden { } } /*! - * Bootstrap v2.3.2 * * Copyright 2013 Twitter, Inc diff --git a/user/index.php b/user/index.php index 168ea2d3ebb..3a388a16902 100644 --- a/user/index.php +++ b/user/index.php @@ -567,44 +567,8 @@ if ($mode === MODE_USERDETAILS) { // Print simple listing. } else { if ($totalcount > $perpage) { - $firstinitial = $table->get_initial_first(); - $lastinitial = $table->get_initial_last(); - $strall = get_string('all'); - $alpha = explode(',', get_string('alphabet', 'langconfig')); - - // Bar of first initials. - - echo '
'.get_string('firstname').' : '; - if (!empty($firstinitial)) { - echo ''.$strall.''; - } else { - echo ''.$strall.''; - } - foreach ($alpha as $letter) { - if ($letter == $firstinitial) { - echo ' '.$letter.''; - } else { - echo ' '.$letter.''; - } - } - echo '
'; - - // Bar of last initials. - - echo '
'.get_string('lastname').' : '; - if (!empty($lastinitial)) { - echo ''.$strall.''; - } else { - echo ''.$strall.''; - } - foreach ($alpha as $letter) { - if ($letter == $lastinitial) { - echo ' '.$letter.''; - } else { - echo ' '.$letter.''; - } - } - echo '
'; + // Initials bar. + $table->print_initials_bar(); $pagingbar = new paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl); $pagingbar->pagevar = 'spage'; diff --git a/user/renderer.php b/user/renderer.php index c12f579d266..2f384fc42c0 100644 --- a/user/renderer.php +++ b/user/renderer.php @@ -106,8 +106,12 @@ class core_user_renderer extends plugin_renderer_base { public function user_search($url, $firstinitial, $lastinitial, $usercount, $totalcount, $heading = null) { global $OUTPUT; - $strall = get_string('all'); - $alpha = explode(',', get_string('alphabet', 'langconfig')); + if ($firstinitial !== 'all') { + set_user_preference('ifirst', $firstinitial); + } + if ($lastinitial !== 'all') { + set_user_preference('ilast', $lastinitial); + } if (!isset($heading)) { $heading = get_string('allparticipants'); @@ -119,43 +123,11 @@ class core_user_renderer extends plugin_renderer_base { // Search utility heading. $content .= $OUTPUT->heading($heading.get_string('labelsep', 'langconfig').$usercount.'/'.$totalcount, 3); - // Bar of first initials. - $content .= html_writer::start_tag('div', array('class' => 'initialbar firstinitial')); - $content .= html_writer::label(get_string('firstname').' : ', null); - - if (!empty($firstinitial)) { - $content .= html_writer::link($url.'&sifirst=', $strall); - } else { - $content .= html_writer::tag('strong', $strall); - } - - foreach ($alpha as $letter) { - if ($letter == $firstinitial) { - $content .= html_writer::tag('strong', $letter); - } else { - $content .= html_writer::link($url.'&sifirst='.$letter, $letter); - } - } - $content .= html_writer::end_tag('div'); - - // Bar of last initials. - $content .= html_writer::start_tag('div', array('class' => 'initialbar lastinitial')); - $content .= html_writer::label(get_string('lastname').' : ', null); - - if (!empty($lastinitial)) { - $content .= html_writer::link($url.'&silast=', $strall); - } else { - $content .= html_writer::tag('strong', $strall); - } - - foreach ($alpha as $letter) { - if ($letter == $lastinitial) { - $content .= html_writer::tag('strong', $letter); - } else { - $content .= html_writer::link($url.'&silast='.$letter, $letter); - } - } - $content .= html_writer::end_tag('div'); + // Initials bar. + $prefixfirst = 'sifirst'; + $prefixlast = 'silast'; + $content .= $OUTPUT->initials_bar($firstinitial, 'firstinitial', get_string('firstname'), $prefixfirst, $url); + $content .= $OUTPUT->initials_bar($lastinitial, 'lastinitial', get_string('lastname'), $prefixlast, $url); $content .= html_writer::end_tag('div'); $content .= html_writer::tag('div', ' ');