enrol MDL-22854 New ajaxified enrolment interface
[moodle.git] / enrol / yui / rolemanager / rolemanager.js
1 YUI.add('moodle-enrol-rolemanager', function(Y) {
3     var MOD_NAME                    = 'Moodle role manager',
4         MOD_USER                    = 'Moodle role user',
5         MOD_PANEL                   = 'Moodle role assignment panel',
6         USERIDS                     = 'userIds',
7         COURSEID                    = 'courseId',
8         USERID                      = 'userId',
9         CONTAINER                   = 'container',
10         CONTAINERID                 = 'containerId',
11         ASSIGNABLEROLES             = 'assignableRoles',
12         ASSIGNROLELINK              = 'assignRoleLink',
13         ASSIGNROLELINKSELECTOR      = 'assignRoleLinkSelector',
14         UNASSIGNROLELINKS           = 'unassignRoleLinks',
15         UNASSIGNROLELINKSSELECTOR   = 'unassignRoleLinksSelector',
16         MANIPULATOR                 = 'manipulator',
17         CURRENTROLES                = 'currentroles';
19     var ROLE = function(config) {
20         ROLE.superclass.constructor.apply(this, arguments);
21     }
22     ROLE.NAME = MOD_NAME;
23     ROLE.ATTRS = {
24         containerId : {
25             validator: Y.Lang.isString
26         },
27         container : {
28             setter : function(node) {
29                 var n = Y.one(node);
30                 if (!n) {
31                     Y.fail(MOD_NAME+': invalid container set');
32                 }
33                 return n;
34             }
35         },
36         courseId : {
37             value: 0,
38             setter : function(courseId) {
39                 if (!(/^\d+$/.test(courseId))) {
40                     Y.fail(MOD_NAME+': Invalid course id specified');
41                 }
42                 return courseId;
43             }
44         },
45         userIds : {
46             validator: Y.Lang.isArray
47         },
48         assignableRoles : {
49             value : []
50         }
51     }
52     Y.extend(ROLE, Y.Base, {
53         users : [],
54         roleAssignmentPanel : null,
55         panelsubmitevent : null,
56         rolesLoadedEvent : null,
57         escCloseEvent  : null,
58         initializer : function(config) {
59             var i;
60             var container = Y.one('#'+this.get(CONTAINERID));
61             container.addClass('ajaxactive');
62             this.set(CONTAINER, container);
63             
64             var userids = this.get(USERIDS);
65             for (i in userids) {
66                 this.users[userids[i]] = new ROLEUSER({userId:userids[i],manipulator:this}).wire();
67             }
68         },
69         addRole : function(e, user) {
70             e.halt();
71             this.rolesLoadedEvent = this.on('assignablerolesloaded', function(){
72                 this.rolesLoadedEvent.detach();
73                 var panel = this._getRoleAssignmentPanel();
74                 this.panelsubmitevent = panel.on('submit', this.addRoleCallback, this);
75                 panel.hide().display(user);
76             }, this);
77             this._loadAssignableRoles();
78         },
79         addRoleCallback : function(e, roleid, userid) {
80             this.panelsubmitevent.detach();
81             var panel = this._getRoleAssignmentPanel();
82             Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
83                 method:'POST',
84                 data:'id='+this.get(COURSEID)+'&action=assign&sesskey='+M.cfg.sesskey+'&roleid='+roleid+'&user='+userid,
85                 on: {
86                     complete: function(tid, outcome, args) {
87                         try {
88                             var o = Y.JSON.parse(outcome.responseText);
89                             if (o.success) {
90                                 panel.user.addRoleToDisplay(args.roleid, this.get(ASSIGNABLEROLES)[args.roleid]);
91                             }
92                         } catch (e) {
93                             Y.fail(MOD_PANEL+': Failed to parse role assignment response  ['+e.linenum+':'+e.message+']');
94                         }
95                         panel.hide();
96                     }
97                 },
98                 context:this,
99                 arguments:{
100                     roleid : roleid
101                 }
102             });
103         },
104         removeRole : function(e, user, roleid) {
105             e.halt();
106             if (confirm('Are you sure you wish to remove this role from this user?')) {
107                 this.removeRoleCallback(e, user.get(USERID), roleid);
108             }
109         },
110         removeRoleCallback : function(e, userid, roleid) {
111             Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
112                 method:'POST',
113                 data:'id='+this.get(COURSEID)+'&action=unassign&sesskey='+M.cfg.sesskey+'&role='+roleid+'&user='+userid,
114                 on: {
115                     complete: function(tid, outcome, args) {
116                         try {
117                             var o = Y.JSON.parse(outcome.responseText);
118                             if (o.success) {
119                                 this.users[userid].removeRoleFromDisplay(args.roleid);
120                             }
121                         } catch (e) {
122                             Y.fail(MOD_PANEL+': Failed to parse role assignment response ['+e.linenum+':'+e.message+']');
123                         }
124                     }
125                 },
126                 context:this,
127                 arguments:{
128                     roleid : roleid
129                 }
130             });
131         },
132         _loadAssignableRoles : function() {
133             var c = this.get(COURSEID);
134             Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
135                 method:'POST',
136                 data:'id='+this.get(COURSEID)+'&action=getassignable&sesskey='+M.cfg.sesskey,
137                 on: {
138                     complete: function(tid, outcome, args) {
139                         try {
140                             var roles = Y.JSON.parse(outcome.responseText);
141                             this.set(ASSIGNABLEROLES, roles.response);
142                         } catch (e) {
143                             Y.fail(MOD_NAME+': Failed to load assignable roles');
144                         }
145                         this._loadAssignableRoles = function() {
146                             this.fire('assignablerolesloaded');
147                         }
148                         this._loadAssignableRoles();
149                     }
150                 },
151                 context:this
152             });
153         },
154         _getRoleAssignmentPanel : function() {
155             if (this.roleAssignmentPanel === null) {
156                 this.roleAssignmentPanel = new ROLEPANEL({manipulator:this});
157             }
158             return this.roleAssignmentPanel;
159         }
160     });
161     Y.augment(ROLE, Y.EventTarget);
163     var ROLEUSER = function(config) {
164         ROLEUSER.superclass.constructor.apply(this, arguments);
165     }
166     ROLEUSER.NAME = MOD_USER;
167     ROLEUSER.ATTRS = {
168         userId  : {
169             validator: Y.Lang.isNumber
170         },
171         manipulator : {
172             validator: Y.Lang.isObject
173         },
174         container : {
175             setter : function(node) {
176                 var n = Y.one(node);
177                 if (!n) {
178                     Y.fail(MOD_USER+': invalid container set '+node);
179                 }
180                 return n;
181             }
182         },
183         assignableroles : {
184             value : []
185         },
186         currentroles : {
187             value : [],
188             validator: Y.Lang.isArray
189         },
190         assignRoleLink : {
191             setter : function(node) {
192                 if (node===false) {
193                     return node;
194                 }
195                 var n = Y.one(node);
196                 if (!n) {
197                     Y.fail(MOD_NAME+': invalid assign role link given '+node);
198                 }
199                 return n;
200             },
201             value : false
202         },
203         assignRoleLinkSelector : {
204             value : '.assignrolelink',
205             validator : Y.Lang.isString
206         },
207         unassignRoleLinks : {
208         },
209         unassignRoleLinksSelector : {
210             value : '.unassignrolelink',
211             validator : Y.Lang.isString
212         }
213     }
214     Y.extend(ROLEUSER, Y.Base, {
215         initializer : function() {
216             var container = this.get(MANIPULATOR).get(CONTAINER).one('#user_'+this.get(USERID));
217             this.set(CONTAINER,        container);
218             var assignrole = container.one(this.get(ASSIGNROLELINKSELECTOR));
219             if (assignrole) {
220                 this.set(ASSIGNROLELINK, assignrole.ancestor());
221             }
222             this.set(UNASSIGNROLELINKS , container.all(this.get(UNASSIGNROLELINKSSELECTOR)));
223         },
224         wire : function() {
225             var container = this.get(MANIPULATOR).get(CONTAINER).one('#user_'+this.get(USERID));
226             var arl = this.get(ASSIGNROLELINK);
227             var uarls = this.get(UNASSIGNROLELINKS);
228             var m = this.get(MANIPULATOR);
229             if (arl) {
230                 arl.ancestor().on('click', m.addRole, m, this);
231             }
232             var currentroles = [];
233             if (uarls.size() > 0) {
234                 uarls.each(function(link){
235                     link.roleId = link.getAttribute('rel');
236                     link.on('click', m.removeRole, m, this, link.roleId);
237                     currentroles[link.roleId] = true;
238                 }, this);
239             }
240             container.all('.role.unchangeable').each(function(node){
241                 currentroles[node.getAttribute('rel')] = true;
242             }, this);
243             
244             this.set(CURRENTROLES, currentroles);
245             return this;
246         },
247         _checkIfHasAllRoles : function() {
248             var roles = this.get(MANIPULATOR).get(ASSIGNABLEROLES);
249             var current = this.get(CURRENTROLES);
250             var allroles = true, i = 0;
251             for (i in roles) {
252                 if (!current[i]) {
253                     allroles = false;
254                     break;
255                 }
256             }
257             var link = this.get(ASSIGNROLELINK);
258             if (allroles) {
259                 this.get(CONTAINER).addClass('hasAllRoles');
260             } else {
261                 if (!link) {
262                     var m = this.get(MANIPULATOR);
263                     link = Y.Node.create('<div class="addrole">&nbsp;</div>');
264                     link.on('click', m.addRole, m, this);
265                     this.get(CONTAINER).one('.col_role').insert(link, 0);
266                     this.set(ASSIGNROLELINK, link);
267                 }
268                 this.get(CONTAINER).removeClass('hasAllRoles');
269             }
270         },
271         addRoleToDisplay : function(roleId, roleTitle) {
272             var m = this.get(MANIPULATOR);
273             var container = this.get(CONTAINER);
274             var role = Y.Node.create('<div class="role role_'+roleId+'">'+roleTitle+'<a class="unassignrolelink"><img src="'+M.util.image_url('t/delete', 'moodle')+'" alt="" /></a></div>');
275             var link = role.one('.unassignrolelink');
276             link.roleId = roleId;
277             link.on('click', m.removeRole, m, this, link.roleId);
278             container.one('.col_role .roles').append(role);
279             this._toggleCurrentRole(link.roleId, true);
280         },
281         removeRoleFromDisplay : function(roleId) {
282             var container = this.get(CONTAINER);
283             container.all('.role_'+roleId).remove();
284             this._toggleCurrentRole(roleId, false);
285         },
286         _toggleCurrentRole : function(roleId, hasRole) {
287             var roles = this.get(CURRENTROLES);
288             if (hasRole) {
289                 roles[roleId] = true;
290             } else {
291                 roles[roleId] = false;
292             }
293             this.set(CURRENTROLES, roles);
294             this._checkIfHasAllRoles();
295         }
296     });
298     var ROLEPANEL = function(config) {
299         ROLEPANEL.superclass.constructor.apply(this, arguments);
300     }
301     ROLEPANEL.NAME = MOD_PANEL;
302     ROLEPANEL.ATTRS = {
303         elementNode : {
304             setter : function(node) {
305                 var n = Y.one(node);
306                 if (!n) {
307                     Y.fail(MOD_PANEL+': Invalid element node');
308                 }
309                 return n;
310             }
311         },
312         contentNode : {
313             setter : function(node) {
314                 var n = Y.one(node);
315                 if (!n) {
316                     Y.fail(MOD_PANEL+': Invalid content node');
317                 }
318                 return n;
319             }
320         },
321         manipulator : {
322             validator: Y.Lang.isObject
323         }
324     }
325     Y.extend(ROLEPANEL, Y.Base, {
326         user : null,
327         roles : [],
328         initializer : function() {
329             var i, m = this.get(MANIPULATOR);
330             var element = Y.Node.create('<div class="enrolpanel roleassign"><div class="container"><div class="header"><h2>'+M.str.role.assignroles+'</h2><div class="close"></div></div><div class="content"></div></div></div>');
331             var content = element.one('.content');
332             var roles = m.get(ASSIGNABLEROLES);
333             for (i in roles) {
334                 var button = Y.Node.create('<input type="button" value="'+roles[i]+'" id="add_assignable_role_'+i+'" />');
335                 button.on('click', this.submit, this, i);
336                 content.append(button);
337             }
338             Y.one(document.body).append(element);
339             this.set('elementNode', element);
340             this.set('contentNode', content);
341             element.one('.header .close').on('click', this.hide, this);
342         },
343         display : function(user) {
344             var currentroles = user.get(CURRENTROLES);
345             for (var i in currentroles) {
346                 if (currentroles[i] === true) {
347                     this.get('contentNode').one('#add_assignable_role_'+i).setAttribute('disabled', 'disabled');
348                     this.roles.push(i);
349                 }
350             }
351             this.user = user;
352             var roles = this.user.get(CONTAINER).one('.col_role .roles');
353             var x = roles.getX() + 10;
354             var y = roles.getY() + this.user.get(CONTAINER).get('offsetHeight') - 10 + Y.one(window).get('scrollTop');
355             this.get('elementNode').setXY([x, y]);
356             this.get('elementNode').addClass('visible');
357             this.escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
358             this.displayed = true;
359         },
360         hide : function() {
361             if (this._escCloseEvent) {
362                 this._escCloseEvent.detach();
363                 this._escCloseEvent = null;
364             }
365             for (var i in this.roles) {
366                 this.get('contentNode').one('#add_assignable_role_'+this.roles[i]).removeAttribute('disabled');
367             }
368             this.roles = [];
369             this.user = null;
370             this.get('elementNode').removeClass('visible');
371             this.displayed = false;
372             return this;
373         },
374         submit : function(e, roleid) {
375             this.fire('submit', roleid, this.user.get(USERID));
376         }
377     });
378     Y.augment(ROLEPANEL, Y.EventTarget);
380     M.enrol = M.enrol || {};
381     M.enrol.rolemanager = {
382         instance : null,
383         init : function(config) {
384             M.enrol.rolemanager.instance = new ROLE(config);
385             return M.enrol.rolemanager.instance;
386         }
387     }
388     
389 }, '@VERSION@', {requires:['base','node','io','json-parse','test']});