MDL-46570 gradereport_history: Converting JS to namespace'd module

Part of MDL-46191
This commit is contained in:
Frederic Massart 2014-07-31 14:50:17 +08:00 committed by Ankit Agarwal
parent 6668a9046f
commit 51abd213ba
11 changed files with 1323 additions and 488 deletions

View File

@ -657,7 +657,7 @@ class grade_report_history extends grade_report {
$button = new gradereport_history_user_button($PAGE->url, get_string('selectuser', 'gradereport_history'), 'get');
$button->class .= ' gradereport_history_plugin';
$modules = array('moodle-gradereport_history-quickselect', 'moodle-gradereport_history-quickselect-skin');
$modules = array('moodle-gradereport_history-userselector');
$arguments = array(
'courseid' => $courseid,
'ajaxurl' => '/grade/report/history/ajax.php',
@ -665,7 +665,7 @@ class grade_report_history extends grade_report {
'userfullnames' => $currentusers,
);
$function = 'M.gradereport_history.quickselect.init';
$function = 'Y.M.gradereport_history.UserSelector.init';
$button->require_yui_module($modules, $function, array($arguments));
$button->strings_for_js(array(
'ajaxoneuserfound',

View File

@ -18,9 +18,49 @@ table#gradestable th.header.selected {
}
.path-grade-report-history .singlebutton div {
margin-bottom: 0px;
margin-bottom: 0;
}
.path-grade-report-history .singlebutton div input[type="button"] {
margin-bottom: 0px;
margin-bottom: 0;
}
/* User Selector */
.user-selector-panel {width:455px;background-color:#666;position:absolute;top:10%;left:10%;border:1px solid #666;border-width:0 5px 5px 0;}
.user-selector-panel.hidden {display:none;}
.user-selector-panel .usp-wrap {margin-top:-5px;margin-left:-5px;background-color:#FFF;border:1px solid #999;height:inherit;}
.user-selector-panel .usp-header {background-color:#eee;padding:1px;}
.user-selector-panel .usp-header h2 {margin:3px 1em 0.5em 1em;font-size:1em;}
.user-selector-panel .usp-header .close {width:25px;height:15px;position:absolute;top:2px;right:1em;cursor:pointer;background:url([[pix:theme|sprite]]) no-repeat scroll 0 0 transparent;}
.user-selector-panel .usp-content {text-align:center;position:relative;width:100%;border-top:1px solid #999;border-bottom:1px solid #999;}
.user-selector-panel .usp-content .usp-controls {margin:0;padding:3px;background-color:#ddd;text-align:left;border-bottom:1px solid #BBB;}
.user-selector-panel .usp-content .usp-controls .usp-enrolment-option input {vertical-align:middle;margin-left:1em;}
.user-selector-panel .usp-ajax-content {height:375px;overflow:auto;}
.user-selector-panel .usp-search-results .totalusers {background-color:#eee;padding:5px;border-bottom:1px solid #BBB;font-size:7pt;font-weight: bold;}
.user-selector-panel .usp-search-results .user {width:100%;text-align:left;font-size:9pt;border-bottom:1px solid #ddd;border-top:1px solid #eee;}
.user-selector-panel .usp-search-results .user.odd {border-bottom:1px solid #ddd;border-top:1px solid #eee;background-color:#f9f9f9;}
.user-selector-panel .usp-search-results .user .count {width:20px;float:left;font-size:7pt;line-height:41px;border-right:1px solid #ddd;background-color:#EEE;text-align:right;padding:2px;}
.user-selector-panel .usp-search-results .user .picture {width:45px;float:left;margin:3px;}
.user-selector-panel .usp-search-results .user .details {width:250px;float:left;margin:3px;}
.user-selector-panel .usp-search-results .user .options {padding-right:7px;font-size:8pt;margin:3px;}
.user-selector-panel .usp-search-results .user .options .deselect {margin:3px;float:right;cursor:pointer;}
.user-selector-panel .usp-search-results .user .options .select {margin:3px;float:right;cursor:pointer;}
.user-selector-panel .usp-search-results .user.selected .count {width:40px;color:#eee;}
.user-selector-panel .usp-search-results .usp-more-results {background-color:#eee;padding:5px;border-top:1px solid #BBB;}
.user-selector-panel .usp-loading-lightbox {position:absolute;width:100%;height:100%;top:0;left:0;background-color:#FFF;min-width:50px;min-height:50px;}
.user-selector-panel .usp-loading-lightbox.hidden {display:none;}
.user-selector-panel .usp-loading-lightbox .loading-icon {margin:auto;vertical-align:middle;margin-top:125px;}
.user-selector-panel .usp-footer {padding:3px;background-color:#ddd;text-align:center;}
.user-selector-panel .usp-search {margin:3px;}
.user-selector-panel .usp-search label {padding-right:8px;}
.user-selector-panel .usp-search input {width:50%;}
.user-selector-panel .usp-search input.usp-search-btn {width:20%;}
.dir-rtl .user-selector-panel .usp-header .close {right: auto;left:1em;}
.dir-rtl .user-selector-panel .usp-search-results .user { text-align: right;}
.dir-rtl .user-selector-panel .usp-content .usp-controls { text-align: right;}

View File

@ -0,0 +1,423 @@
YUI.add('moodle-gradereport_history-userselector', function (Y, NAME) {
var USP = {
NAME : 'User Selector Manager',
/** Properties **/
BASE : 'base',
SEARCH : 'search',
SEARCHBTN : 'searchbtn',
PARAMS : 'params',
URL : 'url',
AJAXURL : 'ajaxurl',
MULTIPLE : 'multiple',
PAGE : 'page',
COURSEID : 'courseid',
SELECTEDUSERS : 'selectedusers',
USERFULLNAMES : 'userfullnames',
USERS : 'users',
USERCOUNT : 'userCount',
LASTSEARCH : 'lastPreSearchValue',
PERPAGE : 'perPage'
};
/** CSS classes for nodes in structure **/
var CSS = {
PANEL : 'user-selector-panel',
WRAP : 'usp-wrap',
HEADER : 'usp-header',
CONTENT : 'usp-content',
AJAXCONTENT : 'usp-ajax-content',
SEARCHRESULTS : 'usp-search-results',
TOTALUSERS : 'totalusers',
USERS : 'users',
USER : 'user',
MORERESULTS : 'usp-more-results',
LIGHTBOX : 'usp-loading-lightbox',
LOADINGICON : 'loading-icon',
FOOTER : 'usp-footer',
DESELECT : 'deselect',
SELECT : 'select',
SELECTED : 'selected',
COUNT : 'count',
PICTURE : 'picture',
DETAILS : 'details',
FULLNAME : 'fullname',
EXTRAFIELDS : 'extrafields',
OPTIONS : 'options',
ODD : 'odd',
EVEN : 'even',
HIDDEN : 'hidden',
SEARCH : 'usp-search',
SEARCHBTN : 'usp-search-btn',
CLOSE : 'close',
CLOSEBTN : 'close-button'
};
var create = Y.Node.create;
var USERSELECTOR = function() {
USERSELECTOR.superclass.constructor.apply(this, arguments);
};
Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, Y.Base, {
_searchTimeout : null,
_loadingNode : null,
_escCloseEvent : null,
initializer : function() {
var list,
params;
this.set(USP.BASE, create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
.append(create('<div class="'+CSS.WRAP+'"></div>')
.append(create('<div class="'+CSS.HEADER+' header"></div>')
.append(create('<div class="'+CSS.CLOSE+'"></div>'))
.append(create('<h2>'+M.str.gradereport_history.selectuser+'</h2>')))
.append(create('<div class="'+CSS.CONTENT+'"></div>')
.append(create('<div class="'+CSS.AJAXCONTENT+'"></div>'))
.append(create('<div class="'+CSS.LIGHTBOX+' '+CSS.HIDDEN+'"></div>')
.append(create('<img alt="loading" class="'+CSS.LOADINGICON+'" />')
.setAttribute('src', M.util.image_url('i/loading', 'moodle')))
.setStyle('opacity', 0.5)))
.append(create('<div class="'+CSS.FOOTER+'"></div>')
.append(create('<div class="'+CSS.SEARCH+'"><label for="enrolusersearch" class="accesshide">'+M.str.enrol.usersearch+'</label></div>')
.append(create('<input type="text" id="enrolusersearch" value="" />'))
.append(create('<input type="button" id="searchbtn" class="'+CSS.SEARCHBTN+'" value="'+M.str.enrol.usersearch+'" />'))
)
.append(create('<div class="'+CSS.CLOSEBTN+'"></div>')
.append(create('<input type="button" value="'+M.str.gradereport_history.finishselectingusers+'" />'))
)
)
)
);
this.set(USP.SEARCH, this.get(USP.BASE).one('#enrolusersearch'));
this.set(USP.SEARCHBTN, this.get(USP.BASE).one('#searchbtn'));
list = Y.one('input[name="userids"]').get('value').split(',');
if (list[0] === '') {
list = [];
}
this.set(USP.SELECTEDUSERS, list);
list = [];
if (this.get(USP.USERFULLNAMES) !== null) {
Y.each(this.get(USP.USERFULLNAMES), function(value, key) {
list[key] = value;
});
}
this.set(USP.USERFULLNAMES, list);
Y.all('.gradereport_history_plugin input').each(function(node){
if (node.hasClass('selectortrigger')) {
node.on('click', this.show, this);
}
}, this);
this.get(USP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
this.get(USP.BASE).one('.'+CSS.FOOTER+' .'+CSS.CLOSEBTN+' input').on('click', this.hide, this);
this._loadingNode = this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX);
params = this.get(USP.PARAMS);
params.id = this.get(USP.COURSEID);
this.set(USP.PARAMS, params);
Y.on('key', this.preSearch, this.get(USP.SEARCH), 'down:13', this);
this.get(USP.SEARCHBTN).on('click', this.preSearch, this);
Y.one(document.body).append(this.get(USP.BASE));
var base = this.get(USP.BASE);
base.plug(Y.Plugin.Drag);
base.dd.addHandle('.'+CSS.HEADER+' h2');
base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
},
preSearch : function(e) {
this.search(null, false);
},
show : function(e) {
e.preventDefault();
e.halt();
var base = this.get(USP.BASE);
base.removeClass(CSS.HIDDEN);
var x = (base.get('winWidth') - 400)/2;
var y = (parseInt(base.get('winHeight'), 10)-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY'), 10);
if (y < parseInt(base.get('winHeight'), 10)*0.1) {
y = parseInt(base.get('winHeight'), 10)*0.1;
}
base.setXY([x,y]);
if (this.get(USP.USERS)===null) {
this.search(e, false);
}
this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
},
hide : function(e) {
if (this._escCloseEvent) {
this._escCloseEvent.detach();
this._escCloseEvent = null;
}
this.get(USP.BASE).addClass(CSS.HIDDEN);
},
search : function(e, append) {
if (e) {
e.halt();
e.preventDefault();
}
var params;
if (append) {
this.set(USP.PAGE, this.get(USP.PAGE)+1);
} else {
this.set(USP.USERCOUNT, 0);
this.set(USP.PAGE, 0);
}
params = this.get(USP.PARAMS);
params.sesskey = M.cfg.sesskey;
params.action = 'searchusers';
params.search = this.get(USP.SEARCH).get('value');
params.page = this.get(USP.PAGE);
params.perpage = this.get(USP.PERPAGE);
Y.io(M.cfg.wwwroot+this.get(USP.AJAXURL), {
method:'POST',
data:build_querystring(params),
on : {
start : this.displayLoading,
complete: this.processSearchResults,
end : this.removeLoading
},
context:this,
arguments:{
append:append
}
});
},
displayLoading : function() {
this._loadingNode.removeClass(CSS.HIDDEN);
},
removeLoading : function() {
this._loadingNode.addClass(CSS.HIDDEN);
},
processSearchResults : function(tid, outcome, args) {
var result = false,
users,
count,
selected,
i,
actionnode,
node,
usersstr,
content,
fetchmore;
try {
result = Y.JSON.parse(outcome.responseText);
if (result.error) {
return new M.core.ajaxException(result);
}
} catch (e) {
new M.core.exception(e);
}
if (!result.success) {
this.setContent = M.str.enrol.errajaxsearch;
}
if (!args.append) {
users = create('<div class="'+CSS.USERS+'"></div>');
} else {
users = this.get(USP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS);
}
count = this.get(USP.USERCOUNT);
selected = '';
for (i in result.response.users) {
count++;
user = result.response.users[i];
// If already selected, add class.
if (this.get(USP.SELECTEDUSERS).indexOf(user.userid) >= 0) {
selected = ' '+CSS.SELECTED;
} else {
selected = '';
}
if (selected === '') {
actionnode = create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />');
} else {
actionnode = create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />');
}
node = create('<div class="'+CSS.USER+selected+' clearfix" rel="'+user.userid+'"></div>')
.addClass((count%2)?CSS.ODD:CSS.EVEN)
.append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
.append(create('<div class="'+CSS.PICTURE+'"></div>')
.append(create(user.picture)))
.append(create('<div class="'+CSS.DETAILS+'"></div>')
.append(create('<div class="'+CSS.FULLNAME+'">'+user.fullname+'</div>'))
.append(create('<div class="'+CSS.EXTRAFIELDS+'">'+user.extrafields+'</div>')))
.append(create('<div class="'+CSS.OPTIONS+'"></div>')
.append(actionnode));
users.append(node);
}
this.set(USP.USERCOUNT, count);
if (!args.append) {
usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
content = create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
.append(create('<div class="'+CSS.TOTALUSERS+'">'+usersstr+'</div>'))
.append(users);
if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
fetchmore = create('<div class="'+CSS.MORERESULTS+'"><a href="#">'+M.str.enrol.ajaxnext25+'</a></div>');
fetchmore.on('click', this.search, this, true);
content.append(fetchmore);
}
this.setContent(content);
Y.delegate("click", this.selectUser, users, '.'+CSS.USER+' .'+CSS.SELECT, this, args);
Y.delegate("click", this.deselectUser, users, '.'+CSS.USER+' .'+CSS.DESELECT, this, args);
} else {
if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
this.get(USP.BASE).one('.'+CSS.MORERESULTS).remove();
}
}
},
deselectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
var list = this.get(USP.SELECTEDUSERS);
// Find and remove item from the array.
var i = list.indexOf(user.getAttribute('rel'));
if (i != -1) {
list.splice(i, 1);
}
this.set(USP.SELECTEDUSERS, list);
Y.one('input[name="userids"]').set('value', list.join());
var namelist = this.get(USP.USERFULLNAMES);
delete namelist[user.getAttribute('rel')];
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
user.removeClass(CSS.SELECTED);
user.one('.'+CSS.DESELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />'));
},
selectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
// Add id to the userids element and internal js list.
var list = this.get(USP.SELECTEDUSERS);
list.push(user.getAttribute('rel'));
this.set(USP.SELECTEDUSERS, list);
var fullname = user.one('.fullname').get('innerHTML');
var namelist = this.get(USP.USERFULLNAMES);
namelist[user.getAttribute('rel')] = fullname;
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
Y.one('input[name="userids"]').set('value', list.join());
// Add name to selected list.
user.addClass(CSS.SELECTED);
user.one('.'+CSS.SELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />'));
},
setContent: function(content) {
this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content);
},
setnamedisplay: function() {
var namelist = this.get(USP.USERFULLNAMES);
namelist = namelist.filter(function(x) {
return x;
});
Y.one('.felement .selectednames').set('innerHTML', namelist.join(', '));
Y.one('input[name="userfullnames"]').set('value', namelist.join());
}
}, {
NAME : USP.NAME,
ATTRS : {
url : {
validator : Y.Lang.isString
},
ajaxurl : {
validator : Y.Lang.isString
},
base : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid base node set');
}
return n;
}
},
users : {
validator : Y.Lang.isArray,
value : null
},
selectedusers : {
validator : Y.Lang.isArray,
value : null
},
userfullnames : {
validator : Y.Lang.isObject,
value : null
},
courseid : {
value : null
},
params : {
validator : Y.Lang.isArray,
value : []
},
multiple : {
validator : Y.Lang.isBool,
value : false
},
page : {
validator : Y.Lang.isNumber,
value : 0
},
userCount : {
value : 0,
validator : Y.Lang.isNumber
},
requiresRefresh : {
value : false,
validator : Y.Lang.isBool
},
search : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid search node set');
}
return n;
}
},
lastPreSearchValue : {
value : '',
validator : Y.Lang.isString
},
strings : {
value : {},
validator : Y.Lang.isObject
},
perPage : {
value: 25,
Validator: Y.Lang.isNumber
}
}
});
Y.augment(Y.namespace('M.gradereport_history').UserSelector, Y.EventTarget);
Y.namespace('M.gradereport_history.UserSelector').init = function(cfg) {
return new USERSELECTOR(cfg);
};
}, '@VERSION@', {
"requires": [
"dd-plugin",
"event-delegate",
"event-key",
"io-base",
"json-parse",
"moodle-core-notification",
"overlay"
]
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,423 @@
YUI.add('moodle-gradereport_history-userselector', function (Y, NAME) {
var USP = {
NAME : 'User Selector Manager',
/** Properties **/
BASE : 'base',
SEARCH : 'search',
SEARCHBTN : 'searchbtn',
PARAMS : 'params',
URL : 'url',
AJAXURL : 'ajaxurl',
MULTIPLE : 'multiple',
PAGE : 'page',
COURSEID : 'courseid',
SELECTEDUSERS : 'selectedusers',
USERFULLNAMES : 'userfullnames',
USERS : 'users',
USERCOUNT : 'userCount',
LASTSEARCH : 'lastPreSearchValue',
PERPAGE : 'perPage'
};
/** CSS classes for nodes in structure **/
var CSS = {
PANEL : 'user-selector-panel',
WRAP : 'usp-wrap',
HEADER : 'usp-header',
CONTENT : 'usp-content',
AJAXCONTENT : 'usp-ajax-content',
SEARCHRESULTS : 'usp-search-results',
TOTALUSERS : 'totalusers',
USERS : 'users',
USER : 'user',
MORERESULTS : 'usp-more-results',
LIGHTBOX : 'usp-loading-lightbox',
LOADINGICON : 'loading-icon',
FOOTER : 'usp-footer',
DESELECT : 'deselect',
SELECT : 'select',
SELECTED : 'selected',
COUNT : 'count',
PICTURE : 'picture',
DETAILS : 'details',
FULLNAME : 'fullname',
EXTRAFIELDS : 'extrafields',
OPTIONS : 'options',
ODD : 'odd',
EVEN : 'even',
HIDDEN : 'hidden',
SEARCH : 'usp-search',
SEARCHBTN : 'usp-search-btn',
CLOSE : 'close',
CLOSEBTN : 'close-button'
};
var create = Y.Node.create;
var USERSELECTOR = function() {
USERSELECTOR.superclass.constructor.apply(this, arguments);
};
Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, Y.Base, {
_searchTimeout : null,
_loadingNode : null,
_escCloseEvent : null,
initializer : function() {
var list,
params;
this.set(USP.BASE, create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
.append(create('<div class="'+CSS.WRAP+'"></div>')
.append(create('<div class="'+CSS.HEADER+' header"></div>')
.append(create('<div class="'+CSS.CLOSE+'"></div>'))
.append(create('<h2>'+M.str.gradereport_history.selectuser+'</h2>')))
.append(create('<div class="'+CSS.CONTENT+'"></div>')
.append(create('<div class="'+CSS.AJAXCONTENT+'"></div>'))
.append(create('<div class="'+CSS.LIGHTBOX+' '+CSS.HIDDEN+'"></div>')
.append(create('<img alt="loading" class="'+CSS.LOADINGICON+'" />')
.setAttribute('src', M.util.image_url('i/loading', 'moodle')))
.setStyle('opacity', 0.5)))
.append(create('<div class="'+CSS.FOOTER+'"></div>')
.append(create('<div class="'+CSS.SEARCH+'"><label for="enrolusersearch" class="accesshide">'+M.str.enrol.usersearch+'</label></div>')
.append(create('<input type="text" id="enrolusersearch" value="" />'))
.append(create('<input type="button" id="searchbtn" class="'+CSS.SEARCHBTN+'" value="'+M.str.enrol.usersearch+'" />'))
)
.append(create('<div class="'+CSS.CLOSEBTN+'"></div>')
.append(create('<input type="button" value="'+M.str.gradereport_history.finishselectingusers+'" />'))
)
)
)
);
this.set(USP.SEARCH, this.get(USP.BASE).one('#enrolusersearch'));
this.set(USP.SEARCHBTN, this.get(USP.BASE).one('#searchbtn'));
list = Y.one('input[name="userids"]').get('value').split(',');
if (list[0] === '') {
list = [];
}
this.set(USP.SELECTEDUSERS, list);
list = [];
if (this.get(USP.USERFULLNAMES) !== null) {
Y.each(this.get(USP.USERFULLNAMES), function(value, key) {
list[key] = value;
});
}
this.set(USP.USERFULLNAMES, list);
Y.all('.gradereport_history_plugin input').each(function(node){
if (node.hasClass('selectortrigger')) {
node.on('click', this.show, this);
}
}, this);
this.get(USP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
this.get(USP.BASE).one('.'+CSS.FOOTER+' .'+CSS.CLOSEBTN+' input').on('click', this.hide, this);
this._loadingNode = this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX);
params = this.get(USP.PARAMS);
params.id = this.get(USP.COURSEID);
this.set(USP.PARAMS, params);
Y.on('key', this.preSearch, this.get(USP.SEARCH), 'down:13', this);
this.get(USP.SEARCHBTN).on('click', this.preSearch, this);
Y.one(document.body).append(this.get(USP.BASE));
var base = this.get(USP.BASE);
base.plug(Y.Plugin.Drag);
base.dd.addHandle('.'+CSS.HEADER+' h2');
base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
},
preSearch : function(e) {
this.search(null, false);
},
show : function(e) {
e.preventDefault();
e.halt();
var base = this.get(USP.BASE);
base.removeClass(CSS.HIDDEN);
var x = (base.get('winWidth') - 400)/2;
var y = (parseInt(base.get('winHeight'), 10)-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY'), 10);
if (y < parseInt(base.get('winHeight'), 10)*0.1) {
y = parseInt(base.get('winHeight'), 10)*0.1;
}
base.setXY([x,y]);
if (this.get(USP.USERS)===null) {
this.search(e, false);
}
this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
},
hide : function(e) {
if (this._escCloseEvent) {
this._escCloseEvent.detach();
this._escCloseEvent = null;
}
this.get(USP.BASE).addClass(CSS.HIDDEN);
},
search : function(e, append) {
if (e) {
e.halt();
e.preventDefault();
}
var params;
if (append) {
this.set(USP.PAGE, this.get(USP.PAGE)+1);
} else {
this.set(USP.USERCOUNT, 0);
this.set(USP.PAGE, 0);
}
params = this.get(USP.PARAMS);
params.sesskey = M.cfg.sesskey;
params.action = 'searchusers';
params.search = this.get(USP.SEARCH).get('value');
params.page = this.get(USP.PAGE);
params.perpage = this.get(USP.PERPAGE);
Y.io(M.cfg.wwwroot+this.get(USP.AJAXURL), {
method:'POST',
data:build_querystring(params),
on : {
start : this.displayLoading,
complete: this.processSearchResults,
end : this.removeLoading
},
context:this,
arguments:{
append:append
}
});
},
displayLoading : function() {
this._loadingNode.removeClass(CSS.HIDDEN);
},
removeLoading : function() {
this._loadingNode.addClass(CSS.HIDDEN);
},
processSearchResults : function(tid, outcome, args) {
var result = false,
users,
count,
selected,
i,
actionnode,
node,
usersstr,
content,
fetchmore;
try {
result = Y.JSON.parse(outcome.responseText);
if (result.error) {
return new M.core.ajaxException(result);
}
} catch (e) {
new M.core.exception(e);
}
if (!result.success) {
this.setContent = M.str.enrol.errajaxsearch;
}
if (!args.append) {
users = create('<div class="'+CSS.USERS+'"></div>');
} else {
users = this.get(USP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS);
}
count = this.get(USP.USERCOUNT);
selected = '';
for (i in result.response.users) {
count++;
user = result.response.users[i];
// If already selected, add class.
if (this.get(USP.SELECTEDUSERS).indexOf(user.userid) >= 0) {
selected = ' '+CSS.SELECTED;
} else {
selected = '';
}
if (selected === '') {
actionnode = create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />');
} else {
actionnode = create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />');
}
node = create('<div class="'+CSS.USER+selected+' clearfix" rel="'+user.userid+'"></div>')
.addClass((count%2)?CSS.ODD:CSS.EVEN)
.append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
.append(create('<div class="'+CSS.PICTURE+'"></div>')
.append(create(user.picture)))
.append(create('<div class="'+CSS.DETAILS+'"></div>')
.append(create('<div class="'+CSS.FULLNAME+'">'+user.fullname+'</div>'))
.append(create('<div class="'+CSS.EXTRAFIELDS+'">'+user.extrafields+'</div>')))
.append(create('<div class="'+CSS.OPTIONS+'"></div>')
.append(actionnode));
users.append(node);
}
this.set(USP.USERCOUNT, count);
if (!args.append) {
usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
content = create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
.append(create('<div class="'+CSS.TOTALUSERS+'">'+usersstr+'</div>'))
.append(users);
if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
fetchmore = create('<div class="'+CSS.MORERESULTS+'"><a href="#">'+M.str.enrol.ajaxnext25+'</a></div>');
fetchmore.on('click', this.search, this, true);
content.append(fetchmore);
}
this.setContent(content);
Y.delegate("click", this.selectUser, users, '.'+CSS.USER+' .'+CSS.SELECT, this, args);
Y.delegate("click", this.deselectUser, users, '.'+CSS.USER+' .'+CSS.DESELECT, this, args);
} else {
if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
this.get(USP.BASE).one('.'+CSS.MORERESULTS).remove();
}
}
},
deselectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
var list = this.get(USP.SELECTEDUSERS);
// Find and remove item from the array.
var i = list.indexOf(user.getAttribute('rel'));
if (i != -1) {
list.splice(i, 1);
}
this.set(USP.SELECTEDUSERS, list);
Y.one('input[name="userids"]').set('value', list.join());
var namelist = this.get(USP.USERFULLNAMES);
delete namelist[user.getAttribute('rel')];
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
user.removeClass(CSS.SELECTED);
user.one('.'+CSS.DESELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />'));
},
selectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
// Add id to the userids element and internal js list.
var list = this.get(USP.SELECTEDUSERS);
list.push(user.getAttribute('rel'));
this.set(USP.SELECTEDUSERS, list);
var fullname = user.one('.fullname').get('innerHTML');
var namelist = this.get(USP.USERFULLNAMES);
namelist[user.getAttribute('rel')] = fullname;
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
Y.one('input[name="userids"]').set('value', list.join());
// Add name to selected list.
user.addClass(CSS.SELECTED);
user.one('.'+CSS.SELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />'));
},
setContent: function(content) {
this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content);
},
setnamedisplay: function() {
var namelist = this.get(USP.USERFULLNAMES);
namelist = namelist.filter(function(x) {
return x;
});
Y.one('.felement .selectednames').set('innerHTML', namelist.join(', '));
Y.one('input[name="userfullnames"]').set('value', namelist.join());
}
}, {
NAME : USP.NAME,
ATTRS : {
url : {
validator : Y.Lang.isString
},
ajaxurl : {
validator : Y.Lang.isString
},
base : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid base node set');
}
return n;
}
},
users : {
validator : Y.Lang.isArray,
value : null
},
selectedusers : {
validator : Y.Lang.isArray,
value : null
},
userfullnames : {
validator : Y.Lang.isObject,
value : null
},
courseid : {
value : null
},
params : {
validator : Y.Lang.isArray,
value : []
},
multiple : {
validator : Y.Lang.isBool,
value : false
},
page : {
validator : Y.Lang.isNumber,
value : 0
},
userCount : {
value : 0,
validator : Y.Lang.isNumber
},
requiresRefresh : {
value : false,
validator : Y.Lang.isBool
},
search : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid search node set');
}
return n;
}
},
lastPreSearchValue : {
value : '',
validator : Y.Lang.isString
},
strings : {
value : {},
validator : Y.Lang.isObject
},
perPage : {
value: 25,
Validator: Y.Lang.isNumber
}
}
});
Y.augment(Y.namespace('M.gradereport_history').UserSelector, Y.EventTarget);
Y.namespace('M.gradereport_history.UserSelector').init = function(cfg) {
return new USERSELECTOR(cfg);
};
}, '@VERSION@', {
"requires": [
"dd-plugin",
"event-delegate",
"event-key",
"io-base",
"json-parse",
"moodle-core-notification",
"overlay"
]
});

View File

@ -1,79 +0,0 @@
/**************************************
Structure of the user selector panel
.user-selector-panel(.visible)
.uep-wrap
.uep-header
.uep-content
.uep-ajax-content
.uep-search-results
.totalusers
.users
.user.clearfix(.odd|.even)(.selected)
.count
.picture
.details
.fullname
.extrafields
.options
.select
.uep-more-results
.uep-loading-lightbox(.hidden)
.loading-icon
.uep-footer
.uep-search
input
.uep-searchoptions
.collapsibleheading
.collapsiblearea(.hidden)
.uep-enrolment-option
.role
.startdate
.duration
**************************************/
.user-selector-panel {width:455px;background-color:#666;position:absolute;top:10%;left:10%;border:1px solid #666;border-width:0 5px 5px 0;}
.user-selector-panel.hidden {display:none;}
.user-selector-panel .uep-wrap {margin-top:-5px;margin-left:-5px;background-color:#FFF;border:1px solid #999;height:inherit;}
.user-selector-panel .uep-header {background-color:#eee;padding:1px;}
.user-selector-panel .uep-header h2 {margin:3px 1em 0.5em 1em;font-size:1em;}
.user-selector-panel .uep-header .close {width:25px;height:15px;position:absolute;top:2px;right:1em;cursor:pointer;background:url("sprite.png") no-repeat scroll 0 0 transparent;}
.user-selector-panel .uep-content {text-align:center;position:relative;width:100%;border-top:1px solid #999;border-bottom:1px solid #999;}
.user-selector-panel .uep-content .uep-controls {margin:0;padding:3px;background-color:#ddd;text-align:left;border-bottom:1px solid #BBB;}
.user-selector-panel .uep-content .uep-controls .uep-enrolment-option input {vertical-align:middle;margin-left:1em;}
.user-selector-panel .uep-ajax-content {height:375px;overflow:auto;}
.user-selector-panel .uep-search-results .totalusers {background-color:#eee;padding:5px;border-bottom:1px solid #BBB;font-size:7pt;font-weight: bold;}
.user-selector-panel .uep-search-results .user {width:100%;text-align:left;font-size:9pt;border-bottom:1px solid #ddd;border-top:1px solid #eee;}
.user-selector-panel .uep-search-results .user.odd {border-bottom:1px solid #ddd;border-top:1px solid #eee;background-color:#f9f9f9;}
.user-selector-panel .uep-search-results .user .count {width:20px;float:left;font-size:7pt;line-height:41px;border-right:1px solid #ddd;background-color:#EEE;text-align:right;padding:2px;}
.user-selector-panel .uep-search-results .user .picture {width:45px;float:left;margin:3px;}
.user-selector-panel .uep-search-results .user .details {width:250px;float:left;margin:3px;}
.user-selector-panel .uep-search-results .user .options {padding-right:7px;font-size:8pt;margin:3px;}
.user-selector-panel .uep-search-results .user .options .deselect {margin:3px;float:right;cursor:pointer;}
.user-selector-panel .uep-search-results .user .options .select {margin:3px;float:right;cursor:pointer;}
.user-selector-panel .uep-search-results .user.selected .count {width:40px;color:#eee;}
.user-selector-panel .uep-search-results .uep-more-results {background-color:#eee;padding:5px;border-top:1px solid #BBB;}
.user-selector-panel .uep-loading-lightbox {position:absolute;width:100%;height:100%;top:0;left:0;background-color:#FFF;min-width:50px;min-height:50px;}
.user-selector-panel .uep-loading-lightbox.hidden {display:none;}
.user-selector-panel .uep-loading-lightbox .loading-icon {margin:auto;vertical-align:middle;margin-top:125px;}
.user-selector-panel .uep-footer {padding:3px;background-color:#ddd;text-align:center;}
.user-selector-panel .uep-search {margin:3px;}
.user-selector-panel .uep-search label {padding-right:8px;}
.user-selector-panel .uep-search input {width:50%;}
.user-selector-panel .uep-search input.uep-search-btn {width:20%;}
.user-selector-panel .uep-searchoptions {margin:3px;cursor:pointer;}
.user-selector-panel .uep-searchoptions select {margin-left:1em;}
.user-selector-panel .collapsibleheading img {margin-right:8px;}
.user-selector-panel .collapsiblearea {border:1px solid #bbb;background-color:#f6f6f6;}
.user-selector-panel .collapsiblearea.hidden {display:none;}
.user-selector-panel .collapsiblearea .uep-enrolment-option {margin:5px 1em;}
.dir-rtl .user-selector-panel .uep-header .close {right: auto;left:1em;}
.dir-rtl .user-selector-panel .uep-search-results .user { text-align: right;}
.dir-rtl .user-selector-panel .uep-content .uep-controls { text-align: right;}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1002 B

View File

@ -1,405 +0,0 @@
// shifter-ify
YUI.add('moodle-gradereport_history-quickselect', function(Y) {
var UEP = {
NAME : 'User Selector Manager',
/** Properties **/
BASE : 'base',
SEARCH : 'search',
SEARCHBTN : 'searchbtn',
PARAMS : 'params',
URL : 'url',
AJAXURL : 'ajaxurl',
MULTIPLE : 'multiple',
PAGE : 'page',
COURSEID : 'courseid',
SELECTEDUSERS : 'selectedusers',
USERFULLNAMES : 'userfullnames',
USERS : 'users',
USERCOUNT : 'userCount',
LASTSEARCH : 'lastPreSearchValue',
PERPAGE : 'perPage'
};
/** CSS classes for nodes in structure **/
var CSS = {
PANEL : 'user-selector-panel',
WRAP : 'uep-wrap',
HEADER : 'uep-header',
CONTENT : 'uep-content',
AJAXCONTENT : 'uep-ajax-content',
SEARCHRESULTS : 'uep-search-results',
TOTALUSERS : 'totalusers',
USERS : 'users',
USER : 'user',
MORERESULTS : 'uep-more-results',
LIGHTBOX : 'uep-loading-lightbox',
LOADINGICON : 'loading-icon',
FOOTER : 'uep-footer',
DESELECT : 'deselect',
SELECT : 'select',
SELECTED : 'selected',
COUNT : 'count',
PICTURE : 'picture',
DETAILS : 'details',
FULLNAME : 'fullname',
EXTRAFIELDS : 'extrafields',
OPTIONS : 'options',
ODD : 'odd',
EVEN : 'even',
HIDDEN : 'hidden',
SEARCHOPTIONS : 'uep-searchoptions',
ACTIVE : 'active',
SEARCH : 'uep-search',
SEARCHBTN : 'uep-search-btn',
CLOSE : 'close',
CLOSEBTN : 'close-button'
};
var create = Y.Node.create;
var USERSELECTOR = function(config) {
USERSELECTOR.superclass.constructor.apply(this, arguments);
};
Y.extend(USERSELECTOR, Y.Base, {
_searchTimeout : null,
_loadingNode : null,
_escCloseEvent : null,
initializer : function(config) {
this.set(UEP.BASE, create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
.append(create('<div class="'+CSS.WRAP+'"></div>')
.append(create('<div class="'+CSS.HEADER+' header"></div>')
.append(create('<div class="'+CSS.CLOSE+'"></div>'))
.append(create('<h2>'+M.str.gradereport_history.selectuser+'</h2>')))
.append(create('<div class="'+CSS.CONTENT+'"></div>')
.append(create('<div class="'+CSS.AJAXCONTENT+'"></div>'))
.append(create('<div class="'+CSS.LIGHTBOX+' '+CSS.HIDDEN+'"></div>')
.append(create('<img alt="loading" class="'+CSS.LOADINGICON+'" />')
.setAttribute('src', M.util.image_url('i/loading', 'moodle')))
.setStyle('opacity', 0.5)))
.append(create('<div class="'+CSS.FOOTER+'"></div>')
.append(create('<div class="'+CSS.SEARCH+'"><label for="enrolusersearch" class="accesshide">'+M.str.enrol.usersearch+'</label></div>')
.append(create('<input type="text" id="enrolusersearch" value="" />'))
.append(create('<input type="button" id="searchbtn" class="'+CSS.SEARCHBTN+'" value="'+M.str.enrol.usersearch+'" />'))
)
.append(create('<div class="'+CSS.CLOSEBTN+'"></div>')
.append(create('<input type="button" value="'+M.str.gradereport_history.finishselectingusers+'" />'))
)
)
)
);
this.set(UEP.SEARCH, this.get(UEP.BASE).one('#enrolusersearch'));
this.set(UEP.SEARCHBTN, this.get(UEP.BASE).one('#searchbtn'));
var list = Y.one('input[name="userids"]').get('value').split(',');
if (list[0] == '') {
list = [];
}
this.set(UEP.SELECTEDUSERS, list);
var list = [];
if (this.get(UEP.USERFULLNAMES) != null) {
Y.each(this.get(UEP.USERFULLNAMES), function(value, key) {
list[key] = value;
});
}
this.set(UEP.USERFULLNAMES, list);
Y.all('.gradereport_history_plugin input').each(function(node){
if (node.hasClass('selectortrigger')) {
node.on('click', this.show, this);
}
}, this);
this.get(UEP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
this.get(UEP.BASE).one('.'+CSS.FOOTER+' .'+CSS.CLOSEBTN+' input').on('click', this.hide, this);
this._loadingNode = this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX);
var params = this.get(UEP.PARAMS);
params['id'] = this.get(UEP.COURSEID);
this.set(UEP.PARAMS, params);
Y.on('key', this.preSearch, this.get(UEP.SEARCH), 'down:13', this);
this.get(UEP.SEARCHBTN).on('click', this.preSearch, this);
Y.one(document.body).append(this.get(UEP.BASE));
var base = this.get(UEP.BASE);
base.plug(Y.Plugin.Drag);
base.dd.addHandle('.'+CSS.HEADER+' h2');
base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
},
preSearch : function(e) {
this.search(null, false);
},
show : function(e) {
e.preventDefault();
e.halt();
var base = this.get(UEP.BASE);
base.removeClass(CSS.HIDDEN);
var x = (base.get('winWidth') - 400)/2;
var y = (parseInt(base.get('winHeight'))-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY'));
if (y < parseInt(base.get('winHeight'))*0.1) {
y = parseInt(base.get('winHeight'))*0.1;
}
base.setXY([x,y]);
if (this.get(UEP.USERS)===null) {
this.search(e, false);
}
this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
},
hide : function(e) {
if (this._escCloseEvent) {
this._escCloseEvent.detach();
this._escCloseEvent = null;
}
this.get(UEP.BASE).addClass(CSS.HIDDEN);
},
search : function(e, append) {
if (e) {
e.halt();
e.preventDefault();
}
var on, params;
if (append) {
this.set(UEP.PAGE, this.get(UEP.PAGE)+1);
} else {
this.set(UEP.USERCOUNT, 0);
this.set(UEP.PAGE, 0);
}
params = this.get(UEP.PARAMS);
params['sesskey'] = M.cfg.sesskey;
params['action'] = 'searchusers';
params['search'] = this.get(UEP.SEARCH).get('value');
params['page'] = this.get(UEP.PAGE);
params['perpage'] = this.get(UEP.PERPAGE);
Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), {
method:'POST',
data:build_querystring(params),
on : {
start : this.displayLoading,
complete: this.processSearchResults,
end : this.removeLoading
},
context:this,
arguments:{
append:append,
}
});
},
displayLoading : function() {
this._loadingNode.removeClass(CSS.HIDDEN);
},
removeLoading : function() {
this._loadingNode.addClass(CSS.HIDDEN);
},
processSearchResults : function(tid, outcome, args) {
try {
var result = Y.JSON.parse(outcome.responseText);
if (result.error) {
return new M.core.ajaxException(result);
}
} catch (e) {
new M.core.exception(e);
}
if (!result.success) {
this.setContent = M.str.enrol.errajaxsearch;
}
var users;
if (!args.append) {
users = create('<div class="'+CSS.USERS+'"></div>');
} else {
users = this.get(UEP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS);
}
var count = this.get(UEP.USERCOUNT);
var selected = '';
for (var i in result.response.users) {
count++;
var user = result.response.users[i];
// If already selected, add class.
if (this.get(UEP.SELECTEDUSERS).indexOf(user.userid) >= 0) {
selected = ' '+CSS.SELECTED;
} else {
selected = '';
}
if (selected == '') {
var actionnode = create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />');
} else {
var actionnode = create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />');
}
var node = create('<div class="'+CSS.USER+selected+' clearfix" rel="'+user.userid+'"></div>')
.addClass((count%2)?CSS.ODD:CSS.EVEN)
.append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
.append(create('<div class="'+CSS.PICTURE+'"></div>')
.append(create(user.picture)))
.append(create('<div class="'+CSS.DETAILS+'"></div>')
.append(create('<div class="'+CSS.FULLNAME+'">'+user.fullname+'</div>'))
.append(create('<div class="'+CSS.EXTRAFIELDS+'">'+user.extrafields+'</div>')))
.append(create('<div class="'+CSS.OPTIONS+'"></div>')
.append(actionnode));
users.append(node);
}
this.set(UEP.USERCOUNT, count);
if (!args.append) {
var usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
var content = create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
.append(create('<div class="'+CSS.TOTALUSERS+'">'+usersstr+'</div>'))
.append(users);
if (result.response.totalusers > (this.get(UEP.PAGE)+1)*this.get(UEP.PERPAGE)) {
var fetchmore = create('<div class="'+CSS.MORERESULTS+'"><a href="#">'+M.str.enrol.ajaxnext25+'</a></div>');
fetchmore.on('click', this.search, this, true);
content.append(fetchmore)
}
this.setContent(content);
Y.delegate("click", this.selectUser, users, '.'+CSS.USER+' .'+CSS.SELECT, this, args);
Y.delegate("click", this.deselectUser, users, '.'+CSS.USER+' .'+CSS.DESELECT, this, args);
} else {
if (result.response.totalusers <= (this.get(UEP.PAGE)+1)*this.get(UEP.PERPAGE)) {
this.get(UEP.BASE).one('.'+CSS.MORERESULTS).remove();
}
}
},
deselectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
var list = this.get(UEP.SELECTEDUSERS);
// Find and remove item from the array.
var i = list.indexOf(user.getAttribute('rel'));
if (i != -1) {
list.splice(i, 1);
}
this.set(UEP.SELECTEDUSERS, list);
Y.one('input[name="userids"]').set('value', list.join());
var namelist = this.get(UEP.USERFULLNAMES);
delete namelist[user.getAttribute('rel')];
this.set(UEP.USERFULLNAMES, namelist);
this.setnamedisplay();
user.removeClass(CSS.SELECTED);
user.one('.'+CSS.DESELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />'));
},
selectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
// Add id to the userids element and internal js list.
var list = this.get(UEP.SELECTEDUSERS);
list.push(user.getAttribute('rel'));
this.set(UEP.SELECTEDUSERS, list);
var fullname = user.one('.fullname').get('innerHTML');
var namelist = this.get(UEP.USERFULLNAMES);
namelist[user.getAttribute('rel')] = fullname;
this.set(UEP.USERFULLNAMES, namelist);
this.setnamedisplay();
Y.one('input[name="userids"]').set('value', list.join());
// Add name to selected list.
user.addClass(CSS.SELECTED);
user.one('.'+CSS.SELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />'));
},
setContent: function(content) {
this.get(UEP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content);
},
setnamedisplay: function() {
var namelist = this.get(UEP.USERFULLNAMES);
namelist = namelist.filter(function(x) {
return x;
});
Y.one('.felement .selectednames').set('innerHTML', namelist.join(', '));
Y.one('input[name="userfullnames"]').set('value', namelist.join());
}
}, {
NAME : UEP.NAME,
ATTRS : {
url : {
validator : Y.Lang.isString
},
ajaxurl : {
validator : Y.Lang.isString
},
base : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(UEP.NAME+': invalid base node set');
}
return n;
}
},
users : {
validator : Y.Lang.isArray,
value : null
},
selectedusers : {
validator : Y.Lang.isArray,
value : null
},
userfullnames : {
validator : Y.Lang.isObject,
value : null
},
courseid : {
value : null
},
params : {
validator : Y.Lang.isArray,
value : []
},
multiple : {
validator : Y.Lang.isBool,
value : false
},
page : {
validator : Y.Lang.isNumber,
value : 0
},
userCount : {
value : 0,
validator : Y.Lang.isNumber
},
requiresRefresh : {
value : false,
validator : Y.Lang.isBool
},
search : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(UEP.NAME+': invalid search node set');
}
return n;
}
},
lastPreSearchValue : {
value : '',
validator : Y.Lang.isString
},
strings : {
value : {},
validator : Y.Lang.isObject
},
perPage : {
value: 25,
Validator: Y.Lang.isNumber
}
}
});
Y.augment(USERSELECTOR, Y.EventTarget);
M.gradereport_history = M.gradereport_history || {};
M.gradereport_history.quickselect = {
init : function(cfg) {
new USERSELECTOR(cfg);
}
}
}, '@VERSION@', {requires:['base','node', 'overlay', 'io-base', 'test', 'json-parse', 'event-delegate', 'dd-plugin', 'event-key', 'moodle-core-notification']});

View File

@ -0,0 +1,10 @@
{
"name": "moodle-gradereport_history-userselector",
"builds": {
"moodle-gradereport_history-userselector": {
"jsfiles": [
"userselector.js"
]
}
}
}

View File

@ -0,0 +1,408 @@
var USP = {
NAME : 'User Selector Manager',
/** Properties **/
BASE : 'base',
SEARCH : 'search',
SEARCHBTN : 'searchbtn',
PARAMS : 'params',
URL : 'url',
AJAXURL : 'ajaxurl',
MULTIPLE : 'multiple',
PAGE : 'page',
COURSEID : 'courseid',
SELECTEDUSERS : 'selectedusers',
USERFULLNAMES : 'userfullnames',
USERS : 'users',
USERCOUNT : 'userCount',
LASTSEARCH : 'lastPreSearchValue',
PERPAGE : 'perPage'
};
/** CSS classes for nodes in structure **/
var CSS = {
PANEL : 'user-selector-panel',
WRAP : 'usp-wrap',
HEADER : 'usp-header',
CONTENT : 'usp-content',
AJAXCONTENT : 'usp-ajax-content',
SEARCHRESULTS : 'usp-search-results',
TOTALUSERS : 'totalusers',
USERS : 'users',
USER : 'user',
MORERESULTS : 'usp-more-results',
LIGHTBOX : 'usp-loading-lightbox',
LOADINGICON : 'loading-icon',
FOOTER : 'usp-footer',
DESELECT : 'deselect',
SELECT : 'select',
SELECTED : 'selected',
COUNT : 'count',
PICTURE : 'picture',
DETAILS : 'details',
FULLNAME : 'fullname',
EXTRAFIELDS : 'extrafields',
OPTIONS : 'options',
ODD : 'odd',
EVEN : 'even',
HIDDEN : 'hidden',
SEARCH : 'usp-search',
SEARCHBTN : 'usp-search-btn',
CLOSE : 'close',
CLOSEBTN : 'close-button'
};
var create = Y.Node.create;
var USERSELECTOR = function() {
USERSELECTOR.superclass.constructor.apply(this, arguments);
};
Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, Y.Base, {
_searchTimeout : null,
_loadingNode : null,
_escCloseEvent : null,
initializer : function() {
var list,
params;
this.set(USP.BASE, create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
.append(create('<div class="'+CSS.WRAP+'"></div>')
.append(create('<div class="'+CSS.HEADER+' header"></div>')
.append(create('<div class="'+CSS.CLOSE+'"></div>'))
.append(create('<h2>'+M.str.gradereport_history.selectuser+'</h2>')))
.append(create('<div class="'+CSS.CONTENT+'"></div>')
.append(create('<div class="'+CSS.AJAXCONTENT+'"></div>'))
.append(create('<div class="'+CSS.LIGHTBOX+' '+CSS.HIDDEN+'"></div>')
.append(create('<img alt="loading" class="'+CSS.LOADINGICON+'" />')
.setAttribute('src', M.util.image_url('i/loading', 'moodle')))
.setStyle('opacity', 0.5)))
.append(create('<div class="'+CSS.FOOTER+'"></div>')
.append(create('<div class="'+CSS.SEARCH+'"><label for="enrolusersearch" class="accesshide">'+M.str.enrol.usersearch+'</label></div>')
.append(create('<input type="text" id="enrolusersearch" value="" />'))
.append(create('<input type="button" id="searchbtn" class="'+CSS.SEARCHBTN+'" value="'+M.str.enrol.usersearch+'" />'))
)
.append(create('<div class="'+CSS.CLOSEBTN+'"></div>')
.append(create('<input type="button" value="'+M.str.gradereport_history.finishselectingusers+'" />'))
)
)
)
);
this.set(USP.SEARCH, this.get(USP.BASE).one('#enrolusersearch'));
this.set(USP.SEARCHBTN, this.get(USP.BASE).one('#searchbtn'));
list = Y.one('input[name="userids"]').get('value').split(',');
if (list[0] === '') {
list = [];
}
this.set(USP.SELECTEDUSERS, list);
list = [];
if (this.get(USP.USERFULLNAMES) !== null) {
Y.each(this.get(USP.USERFULLNAMES), function(value, key) {
list[key] = value;
});
}
this.set(USP.USERFULLNAMES, list);
Y.all('.gradereport_history_plugin input').each(function(node){
if (node.hasClass('selectortrigger')) {
node.on('click', this.show, this);
}
}, this);
this.get(USP.BASE).one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
this.get(USP.BASE).one('.'+CSS.FOOTER+' .'+CSS.CLOSEBTN+' input').on('click', this.hide, this);
this._loadingNode = this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.LIGHTBOX);
params = this.get(USP.PARAMS);
params.id = this.get(USP.COURSEID);
this.set(USP.PARAMS, params);
Y.on('key', this.preSearch, this.get(USP.SEARCH), 'down:13', this);
this.get(USP.SEARCHBTN).on('click', this.preSearch, this);
Y.one(document.body).append(this.get(USP.BASE));
var base = this.get(USP.BASE);
base.plug(Y.Plugin.Drag);
base.dd.addHandle('.'+CSS.HEADER+' h2');
base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
},
preSearch : function(e) {
this.search(null, false);
},
show : function(e) {
e.preventDefault();
e.halt();
var base = this.get(USP.BASE);
base.removeClass(CSS.HIDDEN);
var x = (base.get('winWidth') - 400)/2;
var y = (parseInt(base.get('winHeight'), 10)-base.get('offsetHeight'))/2 + parseInt(base.get('docScrollY'), 10);
if (y < parseInt(base.get('winHeight'), 10)*0.1) {
y = parseInt(base.get('winHeight'), 10)*0.1;
}
base.setXY([x,y]);
if (this.get(USP.USERS)===null) {
this.search(e, false);
}
this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
},
hide : function(e) {
if (this._escCloseEvent) {
this._escCloseEvent.detach();
this._escCloseEvent = null;
}
this.get(USP.BASE).addClass(CSS.HIDDEN);
},
search : function(e, append) {
if (e) {
e.halt();
e.preventDefault();
}
var params;
if (append) {
this.set(USP.PAGE, this.get(USP.PAGE)+1);
} else {
this.set(USP.USERCOUNT, 0);
this.set(USP.PAGE, 0);
}
params = this.get(USP.PARAMS);
params.sesskey = M.cfg.sesskey;
params.action = 'searchusers';
params.search = this.get(USP.SEARCH).get('value');
params.page = this.get(USP.PAGE);
params.perpage = this.get(USP.PERPAGE);
Y.io(M.cfg.wwwroot+this.get(USP.AJAXURL), {
method:'POST',
data:build_querystring(params),
on : {
start : this.displayLoading,
complete: this.processSearchResults,
end : this.removeLoading
},
context:this,
arguments:{
append:append
}
});
},
displayLoading : function() {
this._loadingNode.removeClass(CSS.HIDDEN);
},
removeLoading : function() {
this._loadingNode.addClass(CSS.HIDDEN);
},
processSearchResults : function(tid, outcome, args) {
var result = false,
users,
count,
selected,
i,
actionnode,
node,
usersstr,
content,
fetchmore;
try {
result = Y.JSON.parse(outcome.responseText);
if (result.error) {
return new M.core.ajaxException(result);
}
} catch (e) {
new M.core.exception(e);
}
if (!result.success) {
this.setContent = M.str.enrol.errajaxsearch;
}
if (!args.append) {
users = create('<div class="'+CSS.USERS+'"></div>');
} else {
users = this.get(USP.BASE).one('.'+CSS.SEARCHRESULTS+' .'+CSS.USERS);
}
count = this.get(USP.USERCOUNT);
selected = '';
for (i in result.response.users) {
count++;
user = result.response.users[i];
// If already selected, add class.
if (this.get(USP.SELECTEDUSERS).indexOf(user.userid) >= 0) {
selected = ' '+CSS.SELECTED;
} else {
selected = '';
}
if (selected === '') {
actionnode = create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />');
} else {
actionnode = create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />');
}
node = create('<div class="'+CSS.USER+selected+' clearfix" rel="'+user.userid+'"></div>')
.addClass((count%2)?CSS.ODD:CSS.EVEN)
.append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
.append(create('<div class="'+CSS.PICTURE+'"></div>')
.append(create(user.picture)))
.append(create('<div class="'+CSS.DETAILS+'"></div>')
.append(create('<div class="'+CSS.FULLNAME+'">'+user.fullname+'</div>'))
.append(create('<div class="'+CSS.EXTRAFIELDS+'">'+user.extrafields+'</div>')))
.append(create('<div class="'+CSS.OPTIONS+'"></div>')
.append(actionnode));
users.append(node);
}
this.set(USP.USERCOUNT, count);
if (!args.append) {
usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
content = create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
.append(create('<div class="'+CSS.TOTALUSERS+'">'+usersstr+'</div>'))
.append(users);
if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
fetchmore = create('<div class="'+CSS.MORERESULTS+'"><a href="#">'+M.str.enrol.ajaxnext25+'</a></div>');
fetchmore.on('click', this.search, this, true);
content.append(fetchmore);
}
this.setContent(content);
Y.delegate("click", this.selectUser, users, '.'+CSS.USER+' .'+CSS.SELECT, this, args);
Y.delegate("click", this.deselectUser, users, '.'+CSS.USER+' .'+CSS.DESELECT, this, args);
} else {
if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) {
this.get(USP.BASE).one('.'+CSS.MORERESULTS).remove();
}
}
},
deselectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
var list = this.get(USP.SELECTEDUSERS);
// Find and remove item from the array.
var i = list.indexOf(user.getAttribute('rel'));
if (i != -1) {
list.splice(i, 1);
}
this.set(USP.SELECTEDUSERS, list);
Y.one('input[name="userids"]').set('value', list.join());
var namelist = this.get(USP.USERFULLNAMES);
delete namelist[user.getAttribute('rel')];
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
user.removeClass(CSS.SELECTED);
user.one('.'+CSS.DESELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.SELECT+'" value="'+M.str.moodle.select+'" />'));
},
selectUser : function(e, args) {
var user = e.currentTarget.ancestor('.'+CSS.USER);
// Add id to the userids element and internal js list.
var list = this.get(USP.SELECTEDUSERS);
list.push(user.getAttribute('rel'));
this.set(USP.SELECTEDUSERS, list);
var fullname = user.one('.fullname').get('innerHTML');
var namelist = this.get(USP.USERFULLNAMES);
namelist[user.getAttribute('rel')] = fullname;
this.set(USP.USERFULLNAMES, namelist);
this.setnamedisplay();
Y.one('input[name="userids"]').set('value', list.join());
// Add name to selected list.
user.addClass(CSS.SELECTED);
user.one('.'+CSS.SELECT).remove();
user.one('.'+CSS.OPTIONS).append(create('<input type="button" class="'+CSS.DESELECT+'" value="'+M.str.gradereport_history.deselect+'" />'));
},
setContent: function(content) {
this.get(USP.BASE).one('.'+CSS.CONTENT+' .'+CSS.AJAXCONTENT).setContent(content);
},
setnamedisplay: function() {
var namelist = this.get(USP.USERFULLNAMES);
namelist = namelist.filter(function(x) {
return x;
});
Y.one('.felement .selectednames').set('innerHTML', namelist.join(', '));
Y.one('input[name="userfullnames"]').set('value', namelist.join());
}
}, {
NAME : USP.NAME,
ATTRS : {
url : {
validator : Y.Lang.isString
},
ajaxurl : {
validator : Y.Lang.isString
},
base : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid base node set');
}
return n;
}
},
users : {
validator : Y.Lang.isArray,
value : null
},
selectedusers : {
validator : Y.Lang.isArray,
value : null
},
userfullnames : {
validator : Y.Lang.isObject,
value : null
},
courseid : {
value : null
},
params : {
validator : Y.Lang.isArray,
value : []
},
multiple : {
validator : Y.Lang.isBool,
value : false
},
page : {
validator : Y.Lang.isNumber,
value : 0
},
userCount : {
value : 0,
validator : Y.Lang.isNumber
},
requiresRefresh : {
value : false,
validator : Y.Lang.isBool
},
search : {
setter : function(node) {
var n = Y.one(node);
if (!n) {
Y.fail(USP.NAME+': invalid search node set');
}
return n;
}
},
lastPreSearchValue : {
value : '',
validator : Y.Lang.isString
},
strings : {
value : {},
validator : Y.Lang.isObject
},
perPage : {
value: 25,
Validator: Y.Lang.isNumber
}
}
});
Y.augment(Y.namespace('M.gradereport_history').UserSelector, Y.EventTarget);
Y.namespace('M.gradereport_history.UserSelector').init = function(cfg) {
return new USERSELECTOR(cfg);
};

View File

@ -0,0 +1,13 @@
{
"moodle-gradereport_history-userselector": {
"requires": [
"dd-plugin",
"event-delegate",
"event-key",
"io-base",
"json-parse",
"moodle-core-notification",
"overlay"
]
}
}