MDL-23532 enrol - removed general handling of user enrolment editing/unenrolment...
[moodle.git] / enrol / manual / yui / quickenrolment / quickenrolment.js
CommitLineData
b69ca6be 1YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
a70eb30f
SH
2
3 var UEP = {
4 NAME : 'Enrolment Manager',
5 /** Properties **/
6 BASE : 'base',
7 SEARCH : 'search',
8 PARAMS : 'params',
9 URL : 'url',
10 AJAXURL : 'ajaxurl',
11 MULTIPLE : 'multiple',
12 PAGE : 'page',
13 COURSEID : 'courseid',
14 USERS : 'users',
15 USERCOUNT : 'userCount',
16 REQUIREREFRESH : 'requiresRefresh',
17 LASTSEARCH : 'lastPreSearchValue',
18 INSTANCES : 'instances',
19 OPTIONSTARTDATE : 'optionsStartDate',
20 DEFAULTROLE : 'defaultRole',
21 DEFAULTSTARTDATE : 'defaultStartDate',
22 DEFAULTDURATION : 'defaultDuration',
13ba9036
AD
23 ASSIGNABLEROLES : 'assignableRoles',
24 DISABLEGRADEHISTORY : 'disableGradeHistory'
3f35a7ff 25 };
a70eb30f 26 /** CSS classes for nodes in structure **/
3f35a7ff 27 var CSS = {
a70eb30f
SH
28 PANEL : 'user-enroller-panel',
29 WRAP : 'uep-wrap',
30 HEADER : 'uep-header',
31 CONTENT : 'uep-content',
32 AJAXCONTENT : 'uep-ajax-content',
33 SEARCHRESULTS : 'uep-search-results',
34 TOTALUSERS : 'totalusers',
35 USERS : 'users',
36 USER : 'user',
37 MORERESULTS : 'uep-more-results',
38 LIGHTBOX : 'uep-loading-lightbox',
39 LOADINGICON : 'loading-icon',
40 FOOTER : 'uep-footer',
41 ENROL : 'enrol',
42 ENROLLED : 'enrolled',
43 COUNT : 'count',
44 PICTURE : 'picture',
45 DETAILS : 'details',
46 FULLNAME : 'fullname',
47 EMAIL : 'email',
48 OPTIONS : 'options',
49 ODD : 'odd',
50 EVEN : 'even',
51 HIDDEN : 'hidden',
13ba9036
AD
52 RECOVERGRADESCHECK : 'uep-recovergradescheck',
53 RECOVERGRADESCHECKTITLE : 'uep-recovergradeschecktitle',
a70eb30f
SH
54 SEARCHOPTIONS : 'uep-searchoptions',
55 COLLAPSIBLEHEADING : 'collapsibleheading',
56 COLLAPSIBLEAREA : 'collapsiblearea',
57 SEARCHOPTION : 'uep-enrolment-option',
4a370785 58 SEARCHCONTROLS : 'uep-controls',
a70eb30f
SH
59 ROLE : 'role',
60 STARTDATE : 'startdate',
61 DURATION : 'duration',
62 ACTIVE : 'active',
63 SEARCH : 'uep-search',
af885128
SH
64 CLOSE : 'close',
65 CLOSEBTN : 'close-button'
a70eb30f
SH
66 };
67
68 var USERENROLLER = function(config) {
69 USERENROLLER.superclass.constructor.apply(this, arguments);
70 };
71 Y.extend(USERENROLLER, Y.Base, {
72 _searchTimeout : null,
73 _loadingNode : null,
74 _escCloseEvent : null,
75 initializer : function(config) {
13ba9036
AD
76 recovergradescheckbox = null;
77 if (this.get(UEP.DISABLEGRADEHISTORY) != true) {
78 recovergradescheckbox = Y.Node.create('<div class="'+CSS.RECOVERGRADESCHECK+'"><input type="checkbox" id="recovergrades" name="recovergrades" /><span class="'+CSS.RECOVERGRADESCHECKTITLE+'"><label for="recovergrades">'+M.str.enrol.recovergrades+'</label></span></div>');
79 }
80
a70eb30f
SH
81 this.set(UEP.BASE, Y.Node.create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
82 .append(Y.Node.create('<div class="'+CSS.WRAP+'"></div>')
83 .append(Y.Node.create('<div class="'+CSS.HEADER+' header"></div>')
84 .append(Y.Node.create('<div class="'+CSS.CLOSE+'"></div>'))
85 .append(Y.Node.create('<h2>'+M.str.enrol.enrolusers+'</h2>')))
86 .append(Y.Node.create('<div class="'+CSS.CONTENT+'"></div>')
4a370785 87 .append(Y.Node.create('<div class="'+CSS.SEARCHCONTROLS+'"></div>')
88 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTION+' '+CSS.ROLE+'">'+M.str.role.assignroles+'</div>')
89 .append(Y.Node.create('<select><option value="">'+M.str.enrol.none+'</option></select>'))
90 )
13ba9036 91 .append(recovergradescheckbox)
4a370785 92 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTIONS+'"></div>')
93 .append(Y.Node.create('<div class="'+CSS.COLLAPSIBLEHEADING+'"><img alt="" />'+M.str.enrol.enrolmentoptions+'</div>'))
94 .append(Y.Node.create('<div class="'+CSS.COLLAPSIBLEAREA+' '+CSS.HIDDEN+'"></div>')
95 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTION+' '+CSS.STARTDATE+'">'+M.str.moodle.startingfrom+'</div>')
96 .append(Y.Node.create('<select></select>')))
97 .append(Y.Node.create('<div class="'+CSS.SEARCHOPTION+' '+CSS.DURATION+'">'+M.str.enrol.enrolperiod+'</div>')
98 .append(Y.Node.create('<select><option value="0" selected="selected">'+M.str.enrol.unlimitedduration+'</option></select>')))
99 )
100 )
101 )
a70eb30f
SH
102 .append(Y.Node.create('<div class="'+CSS.AJAXCONTENT+'"></div>'))
103 .append(Y.Node.create('<div class="'+CSS.LIGHTBOX+' '+CSS.HIDDEN+'"></div>')
104 .append(Y.Node.create('<img alt="loading" class="'+CSS.LOADINGICON+'" />')
105 .setAttribute('src', M.util.image_url('i/loading', 'moodle')))
106 .setStyle('opacity', 0.5)))
107 .append(Y.Node.create('<div class="'+CSS.FOOTER+'"></div>')
108 .append(Y.Node.create('<div class="'+CSS.SEARCH+'"><label>'+M.str.enrol.usersearch+'</label></div>')
8505d925 109 .append(Y.Node.create('<input type="text" id="enrolusersearch" value="" />'))
a70eb30f 110 )
af885128
SH
111 .append(Y.Node.create('<div class="'+CSS.CLOSEBTN+'"></div>')
112 .append(Y.Node.create('<input type="button" value="'+M.str.enrol.finishenrollingusers+'" />'))
113 )
a70eb30f
SH
114 )
115 )
116 );
117
118 this.set(UEP.SEARCH, this.get(UEP.BASE).one('#enrolusersearch'));
b69ca6be 119 Y.all('.enrol_manual_plugin input').each(function(node){
a70eb30f
SH
120 if (node.getAttribute('type', 'submit')) {
121 node.on('click', this.show, this);
122 }
123 }, this);
124 this.get(UEP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
af885128 125 this.get(UEP.BASE).one('.'+CSS.FOOTER+' .'+CSS.CLOSEBTN+' input').on('click', this.hide, this);
a70eb30f
SH
126 this._loadingNode = this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX);
127 var params = this.get(UEP.PARAMS);
128 params['id'] = this.get(UEP.COURSEID);
129 this.set(UEP.PARAMS, params);
130
131 Y.on('key', this.preSearch, this.get(UEP.SEARCH), 'down:13', this);
8505d925 132
a70eb30f
SH
133 Y.one(document.body).append(this.get(UEP.BASE));
134
135 var base = this.get(UEP.BASE);
136 base.plug(Y.Plugin.Drag);
137 base.dd.addHandle('.'+CSS.HEADER+' h2');
138 base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
139
140
141 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle'));
142 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).on('click', function(){
143 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).toggleClass(CSS.ACTIVE);
144 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).toggleClass(CSS.HIDDEN);
145 if (this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).hasClass(CSS.HIDDEN)) {
146 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle'));
147 } else {
148 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/expanded', 'moodle'));
149 }
150 }, this);
151
152 this.populateAssignableRoles();
153 this.populateStartDates();
154 this.populateDuration();
155 },
156 populateAssignableRoles : function() {
157 this.on('assignablerolesloaded', function(){
158 var roles = this.get(UEP.ASSIGNABLEROLES);
159 var s = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select');
160 var v = this.get(UEP.DEFAULTROLE);
161 var index = 0, count = 0;
162 for (var i in roles) {
163 count++;
164 var option = Y.Node.create('<option value="'+i+'">'+roles[i]+'</option>');
165 if (i == v) {
166 index = count;
167 }
168 s.append(option);
169 }
170 s.set('selectedIndex', index);
171 }, this);
172 this.getAssignableRoles();
173 },
174 populateStartDates : function() {
175 var select = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select');
176 var defaultvalue = this.get(UEP.DEFAULTSTARTDATE);
177 var options = this.get(UEP.OPTIONSTARTDATE);
178 var index = 0, count = 0;
179 for (var i in options) {
180 count++;
181 var option = Y.Node.create('<option value="'+i+'">'+options[i]+'</option>');
182 if (i == defaultvalue) {
183 index = count;
184 }
185 select.append(option);
186 }
187 select.set('selectedIndex', index);
188 },
189 populateDuration : function() {
190 var select = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select');
191 var defaultvalue = this.get(UEP.DEFAULTDURATION);
192 var index = 0, count = 0;
193 for (var i = 1; i <= 365; i++) {
194 count++;
05e7fca4 195 var option = Y.Node.create('<option value="'+i+'">'+M.util.get_string('durationdays', 'enrol', i)+'</option>');
a70eb30f
SH
196 if (i == defaultvalue) {
197 index = count;
198 }
199 select.append(option);
200 }
201 select.set('selectedIndex', index);
202 },
203 getAssignableRoles : function(){
204 Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
205 method:'POST',
206 data:'id='+this.get(UEP.COURSEID)+'&action=getassignable&sesskey='+M.cfg.sesskey,
207 on: {
208 complete: function(tid, outcome, args) {
209 try {
210 var roles = Y.JSON.parse(outcome.responseText);
211 this.set(UEP.ASSIGNABLEROLES, roles.response);
212 } catch (e) {
6db3eee0 213 new M.core.exception(e);
a70eb30f
SH
214 }
215 this.getAssignableRoles = function() {
216 this.fire('assignablerolesloaded');
8505d925 217 };
a70eb30f
SH
218 this.getAssignableRoles();
219 }
220 },
221 context:this
222 });
223 },
224 preSearch : function(e) {
225 this.search(null, false);
226 /*
227 var value = this.get(UEP.SEARCH).get('value');
228 if (value.length < 3 || value == this.get(UEP.LASTSEARCH)) {
229 return;
230 }
231 this.set(UEP.LASTSEARCH, value);
232 if (this._searchTimeout) {
233 clearTimeout(this._searchTimeout);
234 this._searchTimeout = null;
235 }
236 var self = this;
237 this._searchTimeout = setTimeout(function(){
238 self._searchTimeout = null;
239 self.search(null, false);
240 }, 300);
241 */
242 },
243 show : function(e) {
244 e.preventDefault();
245 e.halt();
246
247 var base = this.get(UEP.BASE);
248 base.removeClass(CSS.HIDDEN);
249 var x = (base.get('winWidth') - 400)/2;
250 var y = (parseInt(base.get('winHeight'))-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY'));
251 if (y < parseInt(base.get('winHeight'))*0.1) {
252 y = parseInt(base.get('winHeight'))*0.1;
253 }
254 base.setXY([x,y]);
8505d925 255
a70eb30f
SH
256 if (this.get(UEP.USERS)===null) {
257 this.search(e, false);
258 }
259
260 this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
261 },
262 hide : function(e) {
263 if (this._escCloseEvent) {
264 this._escCloseEvent.detach();
265 this._escCloseEvent = null;
266 }
267 this.get(UEP.BASE).addClass(CSS.HIDDEN);
268 if (this.get(UEP.REQUIREREFRESH)) {
269 window.location = this.get(UEP.URL);
270 }
271 },
272 search : function(e, append) {
273 if (e) {
274 e.halt();
275 e.preventDefault();
276 }
277 var on, params;
278 if (append) {
279 this.set(UEP.PAGE, this.get(UEP.PAGE)+1);
280 } else {
281 this.set(UEP.USERCOUNT, 0);
282 }
283 params = this.get(UEP.PARAMS);
284 params['sesskey'] = M.cfg.sesskey;
285 params['action'] = 'searchusers';
286 params['search'] = this.get(UEP.SEARCH).get('value');
287 params['page'] = this.get(UEP.PAGE);
288 if (this.get(UEP.MULTIPLE)) {
289 alert('oh no there are multiple');
290 } else {
291 var instance = this.get(UEP.INSTANCES)[0];
292 params['enrolid'] = instance.id;
293 }
294 Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), {
295 method:'POST',
296 data:build_querystring(params),
297 on : {
298 start : this.displayLoading,
299 complete: this.processSearchResults,
300 end : this.removeLoading
301 },
302 context:this,
303 arguments:{
304 append:append,
305 enrolid:params['enrolid']
306 }
307 });
308 },
309 displayLoading : function() {
310 this._loadingNode.removeClass(CSS.HIDDEN);
311 },
312 removeLoading : function() {
313 this._loadingNode.addClass(CSS.HIDDEN);
314 },
315 processSearchResults : function(tid, outcome, args) {
316 try {
317 var result = Y.JSON.parse(outcome.responseText);
6db3eee0
SH
318 if (result.error) {
319 return new M.core.ajaxException(result);
320 }
a70eb30f 321 } catch (e) {
6db3eee0 322 new M.core.exception(e);
a70eb30f
SH
323 }
324 if (!result.success) {
325 this.setContent = M.str.enrol.errajaxsearch;
326 }
327 var users;
328 if (!args.append) {
329 users = Y.Node.create('<div class="'+CSS.USERS+'"></div>');
330 } else {
331 users = this.get(UEP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS);
332 }
333 var count = this.get(UEP.USERCOUNT);
334 for (var i in result.response.users) {
335 count++;
336 var user = result.response.users[i];
337 users.append(Y.Node.create('<div class="'+CSS.USER+' clearfix" rel="'+user.id+'"></div>')
338 .addClass((i%2)?CSS.ODD:CSS.EVEN)
339 .append(Y.Node.create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
340 .append(Y.Node.create('<div class="'+CSS.PICTURE+'"></div>')
341 .append(Y.Node.create(user.picture)))
342 .append(Y.Node.create('<div class="'+CSS.DETAILS+'"></div>')
343 .append(Y.Node.create('<div class="'+CSS.FULLNAME+'">'+user.fullname+'</div>'))
344 .append(Y.Node.create('<div class="'+CSS.EMAIL+'">'+user.email+'</div>')))
345 .append(Y.Node.create('<div class="'+CSS.OPTIONS+'"></div>')
4a370785 346 .append(Y.Node.create('<input type="button" class="'+CSS.ENROL+'" value="'+M.str.enrol.enrol+'" />')))
a70eb30f
SH
347 );
348 }
349 this.set(UEP.USERCOUNT, count);
350 if (!args.append) {
049e880c 351 var usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
a70eb30f
SH
352 var content = Y.Node.create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
353 .append(Y.Node.create('<div class="'+CSS.TOTALUSERS+'">'+usersstr+'</div>'))
354 .append(users);
355 if (result.response.totalusers > (this.get(UEP.PAGE)+1)*25) {
356 var fetchmore = Y.Node.create('<div class="'+CSS.MORERESULTS+'"><a href="#">'+M.str.enrol.ajaxnext25+'</a></div>');
357 fetchmore.on('click', this.search, this, true);
358 content.append(fetchmore)
359 }
360 this.setContent(content);
361 Y.delegate("click", this.enrolUser, users, '.'+CSS.USER+' .'+CSS.ENROL, this, args);
362 } else {
363 if (result.response.totalusers <= (this.get(UEP.PAGE)+1)*25) {
364 this.get(UEP.BASE).one('.'+CSS.MORERESULTS).remove();
365 }
366 }
367 },
368 enrolUser : function(e, args) {
369 var user = e.currentTarget.ancestor('.'+CSS.USER);
370 var params = [];
371 params['id'] = this.get(UEP.COURSEID);
372 params['userid'] = user.getAttribute("rel");
373 params['enrolid'] = args.enrolid;
374 params['sesskey'] = M.cfg.sesskey;
375 params['action'] = 'enrol';
376 params['role'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select').get('value');
377 params['startdate'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select').get('value');
378 params['duration'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select').get('value');
13ba9036
AD
379 params['recovergrades'] = this.get(UEP.BASE).one('#recovergrades').get('checked')?1:0;
380
a70eb30f
SH
381 Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), {
382 method:'POST',
383 data:build_querystring(params),
384 on: {
385 start : this.displayLoading,
386 complete : function(tid, outcome, args) {
387 try {
388 var result = Y.JSON.parse(outcome.responseText);
6db3eee0
SH
389 if (result.error) {
390 return new M.core.ajaxException(result);
391 } else {
392 args.userNode.addClass(CSS.ENROLLED);
393 args.userNode.one('.'+CSS.ENROL).remove();
394 this.set(UEP.REQUIREREFRESH, true);
395 }
a70eb30f 396 } catch (e) {
6db3eee0 397 new M.core.exception(e);
a70eb30f
SH
398 }
399 },
400 end : this.removeLoading
401 },
402 context:this,
403 arguments:{
404 params : params,
405 userNode : user
406 }
407 });
408
409 },
410 setContent: function(content) {
411 this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content);
412 }
413 }, {
414 NAME : UEP.NAME,
415 ATTRS : {
416 url : {
417 validator : Y.Lang.isString
418 },
419 ajaxurl : {
420 validator : Y.Lang.isString
421 },
422 base : {
423 setter : function(node) {
424 var n = Y.one(node);
425 if (!n) {
426 Y.fail(UEP.NAME+': invalid base node set');
427 }
428 return n;
429 }
430 },
431 users : {
432 validator : Y.Lang.isArray,
433 value : null
434 },
435 courseid : {
436 value : null
437 },
438 params : {
439 validator : Y.Lang.isArray,
440 value : []
441 },
442 instances : {
443 validator : Y.Lang.isArray,
444 setter : function(instances) {
445 var i,ia = [], count=0;
446 for (i in instances) {
447 ia.push(instances[i]);
448 count++;
449 }
450 this.set(UEP.MULTIPLE, (count>1));
451 }
452 },
453 multiple : {
454 validator : Y.Lang.isBool,
455 value : false
456 },
457 page : {
458 validator : Y.Lang.isNumber,
459 value : 0
460 },
461 userCount : {
462 value : 0,
463 validator : Y.Lang.isNumber
464 },
465 requiresRefresh : {
466 value : false,
467 validator : Y.Lang.isBool
468 },
469 search : {
470 setter : function(node) {
471 var n = Y.one(node);
472 if (!n) {
473 Y.fail(UEP.NAME+': invalid search node set');
474 }
475 return n;
476 }
477 },
478 lastPreSearchValue : {
479 value : '',
480 validator : Y.Lang.isString
481 },
482 strings : {
483 value : {},
484 validator : Y.Lang.isObject
485 },
486 defaultRole : {
23cee7a4 487 value : 0
a70eb30f
SH
488 },
489 defaultStartDate : {
490 value : 2,
491 validator : Y.Lang.isNumber
492 },
493 defaultDuration : {
494 value : ''
495 },
496 assignableRoles : {
497 value : []
498 },
499 optionsStartDate : {
500 value : []
13ba9036
AD
501 },
502 disableGradeHistory : {
503 value : 0
a70eb30f
SH
504 }
505 }
506 });
507 Y.augment(USERENROLLER, Y.EventTarget);
508
b69ca6be
SH
509 M.enrol_manual = M.enrol_manual || {};
510 M.enrol_manual.quickenrolment = {
a70eb30f
SH
511 init : function(cfg) {
512 new USERENROLLER(cfg);
513 }
514 }
515
05e7fca4 516}, '@VERSION@', {requires:['base','node', 'overlay', 'io', 'test', 'json-parse', 'event-delegate', 'dd-plugin', 'event-key', 'moodle-enrol-notification']});