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