diff --git a/enrol/manual/amd/build/form-potential-user-selector.min.js b/enrol/manual/amd/build/form-potential-user-selector.min.js index d697a8b40364f..2ced5d6b6151c 100644 --- a/enrol/manual/amd/build/form-potential-user-selector.min.js +++ b/enrol/manual/amd/build/form-potential-user-selector.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/templates"],function(a,b,c){return{processResults:function(b,c){var d=[];return a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d},transport:function(d,e,f,g){var h,i=a(d).attr("courseid");"undefined"==typeof i&&(i="1");var j=a(d).attr("enrolid");"undefined"==typeof j&&(j=""),h=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:i,enrolid:j,search:e,searchanywhere:!0,page:0,perpage:30}}]),h[0].then(function(b){var d=[],e=0;return a.each(b,function(b,e){var f=e,g=[];a.each(["idnumber","email","phone1","phone2","department","institution"],function(a,b){"undefined"!=typeof e[b]&&""!==e[b]&&(f.hasidentity=!0,g.push(e[b]))}),f.identity=g.join(", "),d.push(c.render("enrol_manual/form-user-selector-suggestion",f))}),a.when.apply(a.when,d).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[e],e++}),f(b)})}).fail(g)}}}); \ No newline at end of file +define(["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){var e=100;return{processResults:function(b,c){var d=[];return a.isArray(c)?(a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d):c},transport:function(f,g,h,i){var j,k=a(f).attr("courseid");"undefined"==typeof k&&(k="1");var l=a(f).attr("enrolid");"undefined"==typeof l&&(l=""),j=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:k,enrolid:l,search:g,searchanywhere:!0,page:0,perpage:e+1}}]),j[0].then(function(b){var f=[],g=0;return b.length<=e?(a.each(b,function(b,d){var e=d,g=[];a.each(["idnumber","email","phone1","phone2","department","institution"],function(a,b){"undefined"!=typeof d[b]&&""!==d[b]&&(e.hasidentity=!0,g.push(d[b]))}),e.identity=g.join(", "),f.push(c.render("enrol_manual/form-user-selector-suggestion",e))}),a.when.apply(a.when,f).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[g],g++}),h(b)})):d.get_string("toomanyuserstoshow","core",">"+e).then(function(a){h(a)})}).fail(i)}}}); \ No newline at end of file diff --git a/enrol/manual/amd/src/form-potential-user-selector.js b/enrol/manual/amd/src/form-potential-user-selector.js index 49bdcbfc30e7f..066f59da0b2c6 100644 --- a/enrol/manual/amd/src/form-potential-user-selector.js +++ b/enrol/manual/amd/src/form-potential-user-selector.js @@ -23,19 +23,27 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) { +define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax, Templates, Str) { + + /** @var {Number} Maximum number of users to show. */ + var MAXUSERS = 100; return /** @alias module:enrol_manual/form-potential-user-selector */ { processResults: function(selector, results) { var users = []; - $.each(results, function(index, user) { - users.push({ - value: user.id, - label: user._label + if ($.isArray(results)) { + $.each(results, function(index, user) { + users.push({ + value: user.id, + label: user._label + }); }); - }); - return users; + return users; + + } else { + return results; + } }, transport: function(selector, query, success, failure) { @@ -57,7 +65,7 @@ define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) { search: query, searchanywhere: true, page: 0, - perpage: 30 + perpage: MAXUSERS + 1 } }]); @@ -65,30 +73,38 @@ define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) { var promises = [], i = 0; - // Render the label. - $.each(results, function(index, user) { - var ctx = user, - identity = []; - $.each(['idnumber', 'email', 'phone1', 'phone2', 'department', 'institution'], function(i, k) { - if (typeof user[k] !== 'undefined' && user[k] !== '') { - ctx.hasidentity = true; - identity.push(user[k]); - } + if (results.length <= MAXUSERS) { + // Render the label. + $.each(results, function(index, user) { + var ctx = user, + identity = []; + $.each(['idnumber', 'email', 'phone1', 'phone2', 'department', 'institution'], function(i, k) { + if (typeof user[k] !== 'undefined' && user[k] !== '') { + ctx.hasidentity = true; + identity.push(user[k]); + } + }); + ctx.identity = identity.join(', '); + promises.push(Templates.render('enrol_manual/form-user-selector-suggestion', ctx)); }); - ctx.identity = identity.join(', '); - promises.push(Templates.render('enrol_manual/form-user-selector-suggestion', ctx)); - }); - // Apply the label to the results. - return $.when.apply($.when, promises).then(function() { - var args = arguments; - $.each(results, function(index, user) { - user._label = args[i]; - i++; + // Apply the label to the results. + return $.when.apply($.when, promises).then(function() { + var args = arguments; + $.each(results, function(index, user) { + user._label = args[i]; + i++; + }); + success(results); + return; }); - success(results); - return; - }); + + } else { + return Str.get_string('toomanyuserstoshow', 'core', '>' + MAXUSERS).then(function(toomanyuserstoshow) { + success(toomanyuserstoshow); + return; + }); + } }).fail(failure); } diff --git a/enrol/manual/tests/behat/quickenrolment.feature b/enrol/manual/tests/behat/quickenrolment.feature new file mode 100644 index 0000000000000..c5e3549a5770f --- /dev/null +++ b/enrol/manual/tests/behat/quickenrolment.feature @@ -0,0 +1,155 @@ +@enrol @enrol_manual +Feature: Teacher can search and enrol users one by one into the course + In order to quickly enrol particular students into my course + As a teacher + I can search for the students and enrol them into the course + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | teacher001 | Teacher | 001 | teacher001@example.com | + | student001 | Student | 001 | student001@example.com | + | student002 | Student | 002 | student002@example.com | + | student003 | Student | 003 | student003@example.com | + | student004 | Student | 004 | student004@example.com | + | student005 | Student | 005 | student005@example.com | + | student006 | Student | 006 | student006@example.com | + | student007 | Student | 007 | student007@example.com | + | student008 | Student | 008 | student008@example.com | + | student009 | Student | 009 | student009@example.com | + | student010 | Student | 010 | student010@example.com | + | student011 | Student | 011 | student011@example.com | + | student012 | Student | 012 | student012@example.com | + | student013 | Student | 013 | student013@example.com | + | student014 | Student | 014 | student014@example.com | + | student015 | Student | 015 | student015@example.com | + | student016 | Student | 016 | student016@example.com | + | student017 | Student | 017 | student017@example.com | + | student018 | Student | 018 | student018@example.com | + | student019 | Student | 019 | student019@example.com | + | student020 | Student | 020 | student020@example.com | + | student021 | Student | 021 | student021@example.com | + | student022 | Student | 022 | student022@example.com | + | student023 | Student | 023 | student023@example.com | + | student024 | Student | 024 | student024@example.com | + | student025 | Student | 025 | student025@example.com | + | student026 | Student | 026 | student026@example.com | + | student027 | Student | 027 | student027@example.com | + | student028 | Student | 028 | student028@example.com | + | student029 | Student | 029 | student029@example.com | + | student030 | Student | 030 | student030@example.com | + | student031 | Student | 031 | student031@example.com | + | student032 | Student | 032 | student032@example.com | + | student033 | Student | 033 | student033@example.com | + | student034 | Student | 034 | student034@example.com | + | student035 | Student | 035 | student035@example.com | + | student036 | Student | 036 | student036@example.com | + | student037 | Student | 037 | student037@example.com | + | student038 | Student | 038 | student038@example.com | + | student039 | Student | 039 | student039@example.com | + | student040 | Student | 040 | student040@example.com | + | student041 | Student | 041 | student041@example.com | + | student042 | Student | 042 | student042@example.com | + | student043 | Student | 043 | student043@example.com | + | student044 | Student | 044 | student044@example.com | + | student045 | Student | 045 | student045@example.com | + | student046 | Student | 046 | student046@example.com | + | student047 | Student | 047 | student047@example.com | + | student048 | Student | 048 | student048@example.com | + | student049 | Student | 049 | student049@example.com | + | student050 | Student | 050 | student050@example.com | + | student051 | Student | 051 | student051@example.com | + | student052 | Student | 052 | student052@example.com | + | student053 | Student | 053 | student053@example.com | + | student054 | Student | 054 | student054@example.com | + | student055 | Student | 055 | student055@example.com | + | student056 | Student | 056 | student056@example.com | + | student057 | Student | 057 | student057@example.com | + | student058 | Student | 058 | student058@example.com | + | student059 | Student | 059 | student059@example.com | + | student060 | Student | 060 | student060@example.com | + | student061 | Student | 061 | student061@example.com | + | student062 | Student | 062 | student062@example.com | + | student063 | Student | 063 | student063@example.com | + | student064 | Student | 064 | student064@example.com | + | student065 | Student | 065 | student065@example.com | + | student066 | Student | 066 | student066@example.com | + | student067 | Student | 067 | student067@example.com | + | student068 | Student | 068 | student068@example.com | + | student069 | Student | 069 | student069@example.com | + | student070 | Student | 070 | student070@example.com | + | student071 | Student | 071 | student071@example.com | + | student072 | Student | 072 | student072@example.com | + | student073 | Student | 073 | student073@example.com | + | student074 | Student | 074 | student074@example.com | + | student075 | Student | 075 | student075@example.com | + | student076 | Student | 076 | student076@example.com | + | student077 | Student | 077 | student077@example.com | + | student078 | Student | 078 | student078@example.com | + | student079 | Student | 079 | student079@example.com | + | student080 | Student | 080 | student080@example.com | + | student081 | Student | 081 | student081@example.com | + | student082 | Student | 082 | student082@example.com | + | student083 | Student | 083 | student083@example.com | + | student084 | Student | 084 | student084@example.com | + | student085 | Student | 085 | student085@example.com | + | student086 | Student | 086 | student086@example.com | + | student087 | Student | 087 | student087@example.com | + | student088 | Student | 088 | student088@example.com | + | student089 | Student | 089 | student089@example.com | + | student090 | Student | 090 | student090@example.com | + | student091 | Student | 091 | student091@example.com | + | student092 | Student | 092 | student092@example.com | + | student093 | Student | 093 | student093@example.com | + | student094 | Student | 094 | student094@example.com | + | student095 | Student | 095 | student095@example.com | + | student096 | Student | 096 | student096@example.com | + | student097 | Student | 097 | student097@example.com | + | student098 | Student | 098 | student098@example.com | + | student099 | Student | 099 | student099@example.com | + And the following "courses" exist: + | fullname | shortname | + | Course 001 | C001 | + And the following "course enrolments" exist: + | user | course | role | + | teacher001 | C001 | editingteacher | + And I log in as "teacher001" + And I am on "Course 001" course homepage + + @javascript + Scenario: Teacher can search and enrol one particular student + Given I navigate to course participants + And I press "Enrol users" + When I set the field "Select users" to "student001" + And I should see "Student 001" + And I click on "Enrol users" "button" in the "Enrol users" "dialogue" + Then I should see "Active" in the "Student 001" "table_row" + + @javascript + Scenario: Searching for a non-existing user + Given I navigate to course participants + And I press "Enrol users" + And I set the field "Select users" to "qwertyuiop" + And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row" + Then I should see "No suggestions" + + @javascript + Scenario: If there are less than 100 matching users, all are displayed for selection + Given I navigate to course participants + And I press "Enrol users" + When I set the field "Select users" to "example.com" + And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row" + And I click on "Student 099" item in the autocomplete list + Then I should see "Student 099" + + @javascript + Scenario: If there are more than 100 matching users, inform there are too many. + Given the following "users" exist: + | username | firstname | lastname | email | + | student100 | Student | 100 | student100@example.com | + | student101 | Student | 101 | student101@example.com | + And I navigate to course participants + And I press "Enrol users" + When I set the field "Select users" to "example.com" + And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row" + Then I should see "Too many users (>100) to show" diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js index 954829bfdd07a..c59dc5d71e26e 100644 --- a/lib/amd/build/form-autocomplete.min.js +++ b/lib/amd/build/form-autocomplete.min.js @@ -1 +1 @@ -define(["jquery","core/log","core/str","core/templates","core/notification"],function(a,b,c,d,e){var f={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38},g=a.now(),h=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;for(b%=e;b<0;)b+=e;var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",!1).attr("id",""),f.attr("data-active-selection",!0).attr("id",g),d.attr("aria-activedescendant",g)},i=function(b,c,f){var g=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),k=!1;j&&(k=a(document.getElementById(j)).attr("data-value")),f.children("option").each(function(b,c){if(a(c).prop("selected")){var d;d=a(c).data("html")?a(c).data("html"):a(c).html(),g.push({label:d,value:a(c).attr("value")})}});var l=a.extend({items:g},b,c);d.render("core/form_autocomplete_selection",l).done(function(b){i.empty().append(a(b).html()),k!==!1&&i.children("[aria-selected=true]").each(function(b,d){a(d).attr("data-value")===k&&h(b,c)})}).fail(e.exception)},j=function(a){"undefined"!=typeof M.core_formchangechecker&&M.core_formchangechecker.set_form_changed(),a.change()},k=function(b,c,d,e){var f=a(d).attr("data-value");b.multiple&&e.children("option").each(function(b,c){a(c).attr("value")==f&&(a(c).prop("selected",!1),a(c).attr("data-iscustom")&&a(c).remove())}),i(b,c,e),j(e)},l=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children("[aria-hidden=false]").length;for(b%=f;b<0;)b+=f;var g=a(e.children("[aria-hidden=false]").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id",""),g.attr("aria-selected",!0).attr("id",i),d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;e.animate({scrollTop:j},100)},m=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children("[aria-hidden=false]").index(d);l(e+1,b)},n=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]");if(!d)return void h(0,b);var e=c.children("[aria-selected=true]").index(d);h(e-1,b)},o=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]");if(!d)return void h(0,b);var e=c.children("[aria-selected=true]").index(d);h(e+1,b)},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children("[aria-hidden=false]").index(d);l(e-1,b)},q=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));c.attr("aria-expanded",!1).attr("aria-activedescendant",b.selectionId),d.hide().attr("aria-hidden",!0)},r=function(b,f,g,h){var i=a(document.getElementById(f.inputId)),j=a(document.getElementById(f.suggestionsId)),k=!1,m=[];h.children("option").each(function(b,c){a(c).prop("selected")!==!0&&(m[m.length]={label:c.innerHTML,value:a(c).attr("value")})});var n=f.caseSensitive?g:g.toLocaleLowerCase(),o=a.extend({options:m},b,f);d.render("core/form_autocomplete_suggestions",o).done(function(d){j.replaceWith(d),j=a(document.getElementById(f.suggestionsId)),j.show().attr("aria-hidden",!1),j.children().each(function(c,d){d=a(d),b.caseSensitive&&d.text().indexOf(n)>-1||!b.caseSensitive&&d.text().toLocaleLowerCase().indexOf(n)>-1?(d.show().attr("aria-hidden",!1),k=!0):d.hide().attr("aria-hidden",!0)}),i.attr("aria-expanded",!0),k?b.tags||l(0,f):c.get_string("nosuggestions","form").done(function(a){j.html(a)})}).fail(e.exception)},s=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){if(e=e.trim(),""!==e&&(b.multiple||d.children("option").prop("selected",!1),d.children("option").each(function(b,c){a(c).attr("value")==e&&(h=!0,a(c).prop("selected",!0))}),!h)){var f=a("