From 855e13784b442707fd2580c1e396b0dd430a4549 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 5 Aug 2014 16:56:09 +0800 Subject: [PATCH] MDL-46570 gradereport_history: Reworked search and load more mechanism Part of MDL-46191 --- grade/report/history/classes/filter_form.php | 2 +- .../history/lang/en/gradereport_history.php | 4 + grade/report/history/lib.php | 16 +- grade/report/history/styles.css | 96 ++++--- ...-gradereport_history-userselector-debug.js | 245 +++++++++++------- ...le-gradereport_history-userselector-min.js | 4 +- ...moodle-gradereport_history-userselector.js | 245 +++++++++++------- .../yui/src/userselector/js/userselector.js | 244 ++++++++++------- .../src/userselector/meta/userselector.json | 1 - 9 files changed, 520 insertions(+), 337 deletions(-) diff --git a/grade/report/history/classes/filter_form.php b/grade/report/history/classes/filter_form.php index 5ee1382540c81..cc073750ce818 100644 --- a/grade/report/history/classes/filter_form.php +++ b/grade/report/history/classes/filter_form.php @@ -52,7 +52,7 @@ public function definition() { $userbutton = $this->_customdata['userbutton']; $names = \html_writer::span('', 'selectednames'); - $mform->addElement('static', 'userselect', get_string('selectuser', 'gradereport_history'), $userbutton); + $mform->addElement('static', 'userselect', get_string('selectusers', 'gradereport_history'), $userbutton); $mform->addElement('static', 'selectednames', get_string('selectedusers', 'gradereport_history'), $names); $mform->addElement('select', 'itemid', get_string('gradeitem', 'gradereport_history'), $itemids); diff --git a/grade/report/history/lang/en/gradereport_history.php b/grade/report/history/lang/en/gradereport_history.php index 09779fee99dad..770e0b5894d09 100644 --- a/grade/report/history/lang/en/gradereport_history.php +++ b/grade/report/history/lang/en/gradereport_history.php @@ -29,8 +29,11 @@ $string['datetill'] = 'Date till'; $string['datetime'] = 'Date and time'; $string['deleteditemid'] = 'Delete item with id {$a}'; +$string['errajaxsearch'] = 'Error when searching users'; $string['eventgradereportviewed'] = 'Grade history report viewed'; $string['excluded'] = 'Excluded from calculations'; +$string['foundoneuser'] = '1 user found'; +$string['foundnusers'] = '{$a} users found'; $string['feedbacktext'] = 'Feedback text'; $string['finishselectingusers'] = 'Finish selecting users'; $string['gradeitem'] = 'Grade item'; @@ -40,6 +43,7 @@ $string['history:view'] = 'View the grade history'; $string['historyperpage'] = 'History entries per page'; $string['historyperpage_help'] = 'This setting determines the number of history entries displayed per page in the history report.'; +$string['loadmoreusers'] = 'Load more users...'; $string['locked'] = 'Locked'; $string['no'] = 'N'; $string['overridden'] = 'Overridden'; diff --git a/grade/report/history/lib.php b/grade/report/history/lib.php index b8251c5b98b3d..46e5c1c78848a 100644 --- a/grade/report/history/lib.php +++ b/grade/report/history/lib.php @@ -654,7 +654,7 @@ public function get_sort_arrows(array $extrafields = array()) { */ public static function get_user_select_button($courseid, $currentusers = array()) { global $PAGE; - $button = new gradereport_history_user_button($PAGE->url, get_string('selectuser', 'gradereport_history'), 'get'); + $button = new gradereport_history_user_button($PAGE->url, get_string('selectusers', 'gradereport_history'), 'get'); $button->class .= ' gradereport_history_plugin'; $modules = array('moodle-gradereport_history-userselector'); @@ -668,21 +668,19 @@ public static function get_user_select_button($courseid, $currentusers = array() $function = 'Y.M.gradereport_history.UserSelector.init'; $button->require_yui_module($modules, $function, array($arguments)); $button->strings_for_js(array( - 'ajaxoneuserfound', - 'ajaxxusersfound', - 'ajaxnext25', 'errajaxsearch', - 'none', - 'usersearch'), 'enrol'); - $button->strings_for_js(array( - 'selectusers', 'finishselectingusers', + 'foundoneuser', + 'foundnusers', + 'loadmoreusers', + 'selectusers', ), 'gradereport_history'); $button->strings_for_js(array( 'loading' ), 'admin'); $button->strings_for_js(array( - 'select' + 'noresults', + 'search' )); return $button; diff --git a/grade/report/history/styles.css b/grade/report/history/styles.css index fb44aed5e80ef..9a1bbb4105249 100644 --- a/grade/report/history/styles.css +++ b/grade/report/history/styles.css @@ -17,54 +17,88 @@ table#gradestable th.header.selected { overflow-x: scroll; } -.path-grade-report-history .singlebutton div { - margin-bottom: 0; -} - +.path-grade-report-history .singlebutton div, .path-grade-report-history .singlebutton div input[type="button"] { - margin-bottom: 0; + margin: 0; } /* User Selector */ .yui3-gradereport_history_usp-hidden {display:none;} +.gradereport_history_usp .usp-content { + position: relative; +} .gradereport_history_usp .usp-ajax-content { - height: 375px; overflow: auto; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; } -.gradereport_history_usp .usp-search-results .totalusers { - text-align: center; - font-size: .8em; - font-weight: bold; +.gradereport_history_usp .usp-ajax-content, +.gradereport_history_usp .usp-loading-lightbox { + height: 375px; } -.gradereport_history_usp .user {width:100%;text-align:left;font-size:9pt;border-bottom:1px solid #ddd;border-top:1px solid #eee;} -.gradereport_history_usp .user:nth-child(odd) {border-bottom:1px solid #ddd;border-top:1px solid #eee;background-color:#f9f9f9;} -.gradereport_history_usp .usp-checkbox {width:20px;float:left;font-size:7pt;line-height:41px;border-right:1px solid #ddd;background-color:#EEE;text-align:right;padding:2px;} -.gradereport_history_usp .user .picture {width:45px;float:left;margin:3px;} -.gradereport_history_usp .user .details {width:250px;float:left;margin:3px;} -.gradereport_history_usp .user .options {padding-right:7px;font-size:8pt;margin:3px;} -.gradereport_history_usp .user .options .deselect {margin:3px;float:right;cursor:pointer;display: none;} -.gradereport_history_usp .user .options .select {margin:3px;float:right;cursor:pointer;} -.gradereport_history_usp .user.selected .checkbox {width:40px;color:#eee;} -.gradereport_history_usp .user.selected .select { display: none; } -.gradereport_history_usp .user.selected .deselect { display: block; } -.gradereport_history_usp .usp-more-results {background-color:#eee;padding:5px;border-top:1px solid #BBB;} - .gradereport_history_usp .usp-loading-lightbox { + background-color: #fff; + opacity: .5; + position: absolute; text-align: center; + width: 100%; + top: 0; + left: 0; } -.gradereport_history_usp .usp-loading-lightbox .loading-icon { - margin: 2em; +.gradereport_history_usp .usp-loading-lightbox img { + margin-top: 100px; + opacity: 1; +} + +.gradereport_history_usp .usp-search { + text-align: center; } -.gradereport_history_usp .usp-footer { - padding: 3px; +.gradereport_history_usp .user { + width: 100%; + text-align: left; + border-top: 1px solid #eee; +} +.gradereport_history_usp .user:nth-child(odd) { + background-color: #f9f9f9; +} +.gradereport_history_usp .usp-first-added { + border-top: 1px solid #bbb; +} +.gradereport_history_usp .usp-checkbox { + text-align: center; + float: left; + padding: 11px 6px 0 6px; +} +.gradereport_history_usp .usp-checkbox input { + margin: 0; +} +.gradereport_history_usp .usp-picture { + margin: 6px 3px 0 3px; + float: left; +} +.gradereport_history_usp .userpicture{ + cursor: pointer; +} +.gradereport_history_usp .user .details { + margin-left: 67px; + padding: 3px 6px 0 6px; +} +.gradereport_history_usp .user .details label { + margin: 0; +} +.gradereport_history_usp .usp-more-results { + padding: 5px; + border-top: 1px solid #bbb; +} +.gradereport_history_usp .usp-finish { + padding-top: 1em; text-align: center; } -.gradereport_history_usp .usp-search {margin:3px;} -.gradereport_history_usp .usp-search label {padding-right:8px;} -.gradereport_history_usp .usp-search input {width:50%;} -.gradereport_history_usp .usp-search input.usp-search-btn {width:20%;} +.gradereport_history_usp .usp-finish input { + margin: 0; +} .dir-rtl .gradereport_history_usp .usp-search-results .user { text-align: right;} .dir-rtl .gradereport_history_usp .usp-content .usp-controls { text-align: right;} diff --git a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-debug.js b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-debug.js index 9ec14a62b561c..deb88e691954d 100644 --- a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-debug.js +++ b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-debug.js @@ -52,36 +52,39 @@ var CSS = { AJAXCONTENT : 'usp-ajax-content', CHECKBOX : 'usp-checkbox', CLOSE : 'close', - CLOSEBTN : 'close-button', + CLOSEBTN : 'usp-finish', CONTENT : 'usp-content', DETAILS : 'details', EXTRAFIELDS : 'extrafields', - FOOTER : 'usp-footer', + FIRSTADDED : 'usp-first-added', FULLNAME : 'fullname', + HEADER : 'usp-header', HIDDEN : 'hidden', LIGHTBOX : 'usp-loading-lightbox', LOADINGICON : 'loading-icon', MORERESULTS : 'usp-more-results', OPTIONS : 'options', - PICTURE : 'picture', + PICTURE : 'usp-picture', + RESULTSCOUNT : 'usp-results-count', SEARCH : 'usp-search', SEARCHBTN : 'usp-search-btn', SEARCHFIELD : 'usp-search-field', SEARCHRESULTS : 'usp-search-results', SELECTED : 'selected', - TOTALUSERS : 'totalusers', USER : 'user', USERS : 'users', WRAP : 'usp-wrap' }; var SELECTORS = { AJAXCONTENT: '.' + CSS.AJAXCONTENT, - FOOTER: '.' + CSS.FOOTER, - FOOTERCLOSE: '.' + CSS.FOOTER + ' .' + CSS.CLOSEBTN + ' input', + FINISHBTN: '.' + CSS.CLOSEBTN + ' input', + FIRSTADDED: '.' + CSS.FIRSTADDED, FULLNAME: '.' + CSS.FULLNAME + ' label', LIGHTBOX: '.' + CSS.LIGHTBOX, MORERESULTS: '.' + CSS.MORERESULTS, OPTIONS: '.' + CSS.OPTIONS, + PICTURE: '.' + CSS.USER + ' .userpicture', + RESULTSCOUNT: '.' + CSS.RESULTSCOUNT, RESULTSUSERS: '.' + CSS.SEARCHRESULTS + ' .' + CSS.USERS, SEARCHBTN: '.' + CSS.SEARCHBTN, SEARCHFIELD: '.' + CSS.SEARCHFIELD, @@ -90,7 +93,7 @@ var SELECTORS = { USER: '.' + CSS.USER, USERFULLNAMES: 'input[name="userfullnames"]', USERIDS: 'input[name="userids"]', - USERSELECT: '.' + CSS.USER + ' .' + CSS.CHECKBOX + ' input[type=checkbox]' + USERSELECT: '.' + CSS.CHECKBOX + ' input[type=checkbox]' }; var create = Y.Node.create; @@ -137,33 +140,35 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor initializer : function() { var bb = this.get('boundingBox'), content, - list, params, tpl; tpl = Y.Handlebars.compile( - '
' + - '
' + - '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + '
' + '{{get_string ' + '
' + - '
' + - '
' + - '
' + - '' + - '' + - '' + - '
' + '
' + - '' + + '' + '
' + - '
' + - '
'); + '' + + '
' + + '
'); content = create( tpl({ @@ -180,9 +185,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor // Use standard dialogue class name. This removes the default styling of the footer. this.get('boundingBox').one('.moodle-dialogue-wrap').addClass('moodle-dialogue-content'); - this.set(USP.SEARCH, bb.one(SELECTORS.SEARCHFIELD)); - this.set(USP.SEARCHBTN, bb.one(SELECTORS.SEARCHBTN)); - // Load the list of users. this.loadUsersFromForm(); @@ -190,23 +192,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor Y.one(SELECTORS.TRIGGER).on('click', this.show, this); // The button to finalize the selection. - bb.one(SELECTORS.FOOTERCLOSE).on('click', this.finishSelectingUsers, this); + bb.one(SELECTORS.FINISHBTN).on('click', this.finishSelectingUsers, this); + + // Delegate the action to select a user. + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.USERSELECT, this); + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.PICTURE, this); 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); - }, - - /** - * Before the search starts. - * - * @method preSearch - */ - preSearch : function(e) { - this.search(null, false); + bb.one(SELECTORS.SEARCHBTN).on('click', this.search, this, false); }, /** @@ -253,7 +249,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor params = this.get(USP.PARAMS); params.sesskey = M.cfg.sesskey; params.action = 'searchusers'; - params.search = this.get(USP.SEARCH).get('value'); + params.search = this.get('boundingBox').one(SELECTORS.SEARCHFIELD).get('value'); params.page = this.get(USP.PAGE); params.perpage = this.get(USP.PERPAGE); @@ -261,40 +257,54 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor method:'POST', data:build_querystring(params), on : { - start : this.displayLoading, + start : this.preSearch, complete: this.processSearchResults, - end : this.removeLoading + end : this.postSearch }, context:this, - arguments:{ - append:append + "arguments": { // Quoted because this is a reserved keyword. + append: append } }); }, /** - * Display the loading info. + * Pre search callback. * - * @method displayLoading + * @method preSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - displayLoading : function() { + preSearch: function(unused, args) { var bb = this.get('boundingBox'); + + // Display the lightbox. bb.one(SELECTORS.LIGHTBOX).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).addClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).addClass(CSS.HIDDEN); + + // Set the number of results to 'loading...'. + if (!args.append) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('loading', 'admin')); + } }, /** - * Hide the loading info. + * Post search callback. * - * @method removeLoading + * @method postSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - removeLoading : function() { - var bb = this.get('boundingBox'); + postSearch: function(unused, args) { + var bb = this.get('boundingBox'), + firstAdded = bb.one(SELECTORS.FIRSTADDED); + + // Hide the lightbox. bb.one(SELECTORS.LIGHTBOX).addClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).removeClass(CSS.HIDDEN); - this.centerDialogue(); + + // Sets the focus on the newly added user if we are appending results. + if (args.append && firstAdded) { + firstAdded.one(SELECTORS.USERSELECT).focus(); + } }, /** @@ -304,34 +314,45 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ processSearchResults : function(tid, outcome, args) { var result = false, + error = false, + bb = this.get('boundingBox'), users, userTemplate, count, selected, i, + firstAdded = true, node, - usersstr, content, fetchmore, - checked; + checked, + totalUsers; + + // Decodes the result. try { result = Y.JSON.parse(outcome.responseText); - if (result.error) { - return new M.core.ajaxException(result); + if (!result.success || result.error) { + error = true; } } catch (e) { - new M.core.exception(e); + error = true; } - if (!result.success) { - this.setContent = M.util.get_string('errajaxsearch', 'enrol'); + + // There was an error. + if (error) { + this.setContent(''); + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('errajaxsearch', COMPONENT)); + return; } + // Create the div containing the users when it is a fresh search. if (!args.append) { users = create('
'); } else { - users = this.get('boundingBox').one(SELECTORS.RESULTSUSERS); + users = bb.one(SELECTORS.RESULTSUSERS); } + // Compile the template for each user node. if (!this._userTemplate) { this._userTemplate = Y.Handlebars.compile( '
' + @@ -351,6 +372,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor } userTemplate = this._userTemplate; + // Append the users one by one. count = this.get(USP.USERCOUNT); selected = ''; for (i in result.response.users) { @@ -380,34 +402,57 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor userId: user.userid, USP: USP })); + + // Noting the first user that was when adding more results. + if (args.append && firstAdded) { + users.all(SELECTORS.FIRSTADDED).removeClass(CSS.FIRSTADDED); + node.addClass(CSS.FIRSTADDED); + firstAdded = false; + } users.append(node); } this.set(USP.USERCOUNT, count); + + // Update the count of users, and add a button to load more if need be. + totalUsers = parseInt(result.response.totalusers, 10); if (!args.append) { - if (result.response.totalusers == '1') { - usersstr = M.util.get_string('ajaxoneuserfound', 'enrol'); + if (totalUsers === 0) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('noresults', 'moodle')); + content = ''; } else { - usersstr = M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers); - } - content = create('
') - .append(create('
'+usersstr+'
')) - .append(users); - if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - fetchmore = create(''); - fetchmore.on('click', this.search, this, true); - content.append(fetchmore); + if (totalUsers === 1) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundoneuser', COMPONENT)); + } else { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundnusers', COMPONENT, totalUsers)); + } + + content = create('
') + .append(users); + if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + fetchmore = create(''); + fetchmore.one('a').on('click', this.search, this, true); + fetchmore.one('a').on('key', this.search, 'space', this, true); + content.append(fetchmore); + } } this.setContent(content); - - // Delegate the action when selecting a user. - Y.delegate("click", this.selectUser, users, SELECTORS.USERSELECT, this); } else { - if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - this.get('boundingBox').one(SELECTORS.MORERESULTS).remove(); + if (totalUsers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + bb.one(SELECTORS.MORERESULTS).remove(); } } }, + /** + * Fetch more results. + * + * @param {EventFacade} e The event. + */ + fetchMore: function(e) { + this.search(e, true); + }, + /** * When the user has finished selecting users. * @@ -415,6 +460,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor * @param {EventFacade} e The event. */ finishSelectingUsers: function(e) { + e.preventDefault(); this.applySelection(); this.hide(); }, @@ -455,10 +501,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ selectUser : function(e) { var user = e.currentTarget.ancestor(SELECTORS.USER), + checkbox = user.one(SELECTORS.USERSELECT), fullname = user.one(SELECTORS.FULLNAME).get('innerHTML'), - checked = e.currentTarget.get('checked'), + checked = checkbox.get('checked'), userId = user.getData('userid'); + if (e.currentTarget !== checkbox) { + // We triggered the selection from another node, so we need to change the checkbox value. + checked = !checked; + checkbox.set('checked', checked); + } + if (checked) { // Selecting the user. this._usersBufferList[userId] = fullname; @@ -496,6 +549,12 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor CSS_PREFIX : USP.CSS_PREFIX, ATTRS : { + /** + * List of extra classes. + * + * @attribute extraClasses + * @type Array + */ extraClasses: { value: [ 'gradereport_history_usp' @@ -619,22 +678,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor validator : Y.Lang.isNumber }, - /** - * The search field. - * - * @attribute search - * @type Node - */ - search : { - setter : function(node) { - var n = Y.one(node); - if (!n) { - Y.fail(USP.NAME+': invalid search node set'); - } - return n; - } - }, - /** * The number of results per page. * @@ -674,6 +717,13 @@ Y.Base.modifyAttrs(Y.namespace('M.gradereport_history.UserSelector'), { value: true }, + /** + * Whether the widget should be draggable or not. + * + * @attribute draggable + * @type Boolean + * @default true + */ draggable: { value: true } @@ -687,7 +737,6 @@ Y.namespace('M.gradereport_history.UserSelector').init = function(cfg) { }, '@VERSION@', { "requires": [ - "dd-plugin", "escape", "event-delegate", "event-key", diff --git a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-min.js b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-min.js index b42b7a5890fea..fba610cc9e18d 100644 --- a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-min.js +++ b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-min.js @@ -1,2 +1,2 @@ -YUI.add("moodle-gradereport_history-userselector",function(e,t){var n="gradereport_history",r={AJAXURL:"ajaxurl",BASE:"base",CHECKBOX_NAME_PREFIX:"usp-u",COURSEID:"courseid",DIALOGUE_PREFIX:"moodle-dialogue",NAME:"gradereport_history_usp",PAGE:"page",PARAMS:"params",PERPAGE:"perPage",SEARCH:"search",SEARCHBTN:"searchbtn",SELECTEDUSERS:"selectedusers",URL:"url",USERCOUNT:"userCount",USERFULLNAMES:"userfullnames"},i={ACCESSHIDE:"accesshide",AJAXCONTENT:"usp-ajax-content",CHECKBOX:"usp-checkbox",CLOSE:"close",CLOSEBTN:"close-button",CONTENT:"usp-content",DETAILS:"details",EXTRAFIELDS:"extrafields",FOOTER:"usp-footer",FULLNAME:"fullname",HIDDEN:"hidden",LIGHTBOX:"usp-loading-lightbox",LOADINGICON:"loading-icon",MORERESULTS:"usp-more-results",OPTIONS:"options",PICTURE:"picture",SEARCH:"usp-search",SEARCHBTN:"usp-search-btn",SEARCHFIELD:"usp-search-field",SEARCHRESULTS:"usp-search-results",SELECTED:"selected",TOTALUSERS:"totalusers",USER:"user",USERS:"users",WRAP:"usp-wrap"},s={AJAXCONTENT:"."+i.AJAXCONTENT,FOOTER:"."+i.FOOTER,FOOTERCLOSE:"."+i.FOOTER+" ."+i.CLOSEBTN+" input",FULLNAME:"."+i.FULLNAME+" label",LIGHTBOX:"."+i.LIGHTBOX,MORERESULTS:"."+i.MORERESULTS,OPTIONS:"."+i.OPTIONS,RESULTSUSERS:"."+i.SEARCHRESULTS+" ."+i.USERS,SEARCHBTN:"."+i.SEARCHBTN,SEARCHFIELD:"."+i.SEARCHFIELD,SELECTEDNAMES:".felement .selectednames",TRIGGER:".gradereport_history_plugin input.selectortrigger",USER:"."+i.USER,USERFULLNAMES:'input[name="userfullnames"]',USERIDS:'input[name="userids"]',USERSELECT:"."+i.USER+" ."+i.CHECKBOX+" input[type=checkbox]"},o=e.Node.create,u=function(){u.superclass.constructor.apply(this,arguments)};e.namespace("M.gradereport_history").UserSelector=e.extend(u,M.core.dialogue,{_firstDisplay:!0,_usersBufferList:null,_userTemplate:null,initializer:function(){var t=this.get("boundingBox"),u,a,f,l;l=e.Handlebars.compile('
{{get_string
'),u=o(l({COMPONENT:n,CSS:i,loadingIcon:M.util.image_url("i/loading","moodle")})),this.getStdModNode(e.WidgetStdMod.HEADER).prepend(o("

"+this.get("title")+"

")),this.setStdModContent(e.WidgetStdMod.BODY,u,e.WidgetStdMod.REPLACE),this.get("boundingBox").one(".moodle-dialogue-wrap").addClass("moodle-dialogue-content"),this.set(r.SEARCH,t.one(s.SEARCHFIELD)),this.set(r.SEARCHBTN,t.one(s.SEARCHBTN)),this.loadUsersFromForm(),e.one(s.TRIGGER).on("click",this.show,this),t.one(s.FOOTERCLOSE).on("click",this.finishSelectingUsers,this),f=this.get(r.PARAMS),f.id=this.get(r.COURSEID),this.set(r.PARAMS,f),e.on("key",this.preSearch,this.get(r.SEARCH),"down:13",this),this.get(r.SEARCHBTN).on("click",this.preSearch,this)},preSearch:function(e){this.search(null,!1)},show:function(t){var n;this._usersBufferList={},this._firstDisplay?(this._firstDisplay=!1,this.search(t,!1)):(this._usersBufferList=e.clone(this.get(r.USERFULLNAMES)),n=this.get("boundingBox"),n.all(s.USERSELECT).set("checked",!1),e.Object.each(this._usersBufferList,function(e,t){n.one(s.USERSELECT+"[name="+r.CHECKBOX_NAME_PREFIX+t+"]").set("checked",!0)})),e.namespace("M.gradereport_history.UserSelector").superclass.show.call(this)},search:function(t,n){t&&(t.halt(),t.preventDefault());var i;n?this.set(r.PAGE,this.get(r.PAGE)+1):(this.set(r.USERCOUNT,0),this.set(r.PAGE,0)),i=this.get(r.PARAMS),i.sesskey=M.cfg.sesskey,i.action="searchusers",i.search=this.get(r.SEARCH).get("value"),i.page=this.get(r.PAGE),i.perpage=this.get(r.PERPAGE),e.io(M.cfg.wwwroot+this.get(r.AJAXURL),{method:"POST",data:build_querystring(i),on:{start:this.displayLoading,complete:this.processSearchResults,end:this.removeLoading},context:this,arguments:{append:n}})},displayLoading:function(){var e=this.get("boundingBox");e.one(s.LIGHTBOX).removeClass(i.HIDDEN),e.one(s.AJAXCONTENT).addClass(i.HIDDEN),e.one(s.FOOTER).addClass(i.HIDDEN)},removeLoading:function(){var e=this.get("boundingBox");e.one(s.LIGHTBOX).addClass(i.HIDDEN),e.one(s.AJAXCONTENT).removeClass(i.HIDDEN),e.one(s.FOOTER).removeClass(i.HIDDEN),this.centerDialogue()},processSearchResults:function(t,u,a){var f=!1,l,c,h,p,d,v,m,g,y,b;try{f=e.JSON.parse(u.responseText);if(f.error)return new M.core.ajaxException(f)}catch(w){new M.core.exception(w)}f.success||(this.setContent=M.util.get_string("errajaxsearch","enrol")),a.append?l=this.get("boundingBox").one(s.RESULTSUSERS):l=o('
'),this._userTemplate||(this._userTemplate=e.Handlebars.compile('
{{{picture}}}
{{extrafields}}
')),c=this._userTemplate,h=this.get(r.USERCOUNT),p="";for(d in f.response.users)h++,user=f.response.users[d],e.Object.hasKey(this._usersBufferList,user.userid)?(p=" "+i.SELECTED,b="checked"):(p="",b=""),v=o(c({checkboxId:e.guid(),checked:b,COMPONENT:n,count:h,CSS:i,extrafields:user.extrafields,extraFieldsId:e.guid(),fullname:user.fullname,picture:user.picture,selected:p,userId:user.userid,USP:r})),l.append(v);this.set(r.USERCOUNT,h -),a.append?f.response.totalusers<=(this.get(r.PAGE)+1)*this.get(r.PERPAGE)&&this.get("boundingBox").one(s.MORERESULTS).remove():(f.response.totalusers=="1"?m=M.util.get_string("ajaxoneuserfound","enrol"):m=M.util.get_string("ajaxxusersfound","enrol",f.response.totalusers),g=o('
').append(o('
'+m+"
")).append(l),f.response.totalusers>(this.get(r.PAGE)+1)*this.get(r.PERPAGE)&&(y=o('"),y.on("click",this.search,this,!0),g.append(y)),this.setContent(g),e.delegate("click",this.selectUser,l,s.USERSELECT,this))},finishSelectingUsers:function(e){this.applySelection(),this.hide()},applySelection:function(t){var n=e.Object.values(this._usersBufferList);this.set(r.SELECTEDUSERS,n),this.set(r.USERFULLNAMES,this._usersBufferList),this.setnamedisplay(),e.one(s.USERIDS).set("value",n.join())},loadUsersFromForm:function(){var t=e.one(s.USERIDS).get("value").split(",");t[0]===""&&(t=[]),this.set(r.SELECTEDUSERS,t)},selectUser:function(e){var t=e.currentTarget.ancestor(s.USER),n=t.one(s.FULLNAME).get("innerHTML"),r=e.currentTarget.get("checked"),o=t.getData("userid");r?(this._usersBufferList[o]=n,t.addClass(i.SELECTED)):(delete this._usersBufferList[o],delete this._usersBufferList[parseInt(o,10)],t.removeClass(i.SELECTED))},setContent:function(e){this.get("boundingBox").one(s.AJAXCONTENT).setContent(e)},setnamedisplay:function(){var t=e.Object.values(this.get(r.USERFULLNAMES));e.one(s.SELECTEDNAMES).set("innerHTML",t.join(", ")),e.one(s.USERFULLNAMES).set("value",t.join())}},{NAME:r.NAME,CSS_PREFIX:r.CSS_PREFIX,ATTRS:{extraClasses:{value:["gradereport_history_usp"]},title:{validator:e.Lang.isString,value:M.util.get_string("selectusers",n)},focusOnPreviousTargetAfterHide:{value:!0},width:{value:"500px"},url:{validator:e.Lang.isString},ajaxurl:{validator:e.Lang.isString},selectedusers:{validator:e.Lang.isArray,value:null},userfullnames:{validator:e.Lang.isObject,value:null},courseid:{value:null},params:{validator:e.Lang.isArray,value:[]},page:{validator:e.Lang.isNumber,value:0},userCount:{value:0,validator:e.Lang.isNumber},search:{setter:function(t){var n=e.one(t);return n||e.fail(r.NAME+": invalid search node set"),n}},perPage:{value:25,Validator:e.Lang.isNumber}}}),e.Base.modifyAttrs(e.namespace("M.gradereport_history.UserSelector"),{visible:{value:!1},modal:{value:!0},draggable:{value:!0}}),e.namespace("M.gradereport_history.UserSelector").init=function(e){return new u(e)}},"@VERSION@",{requires:["dd-plugin","escape","event-delegate","event-key","handlebars","io-base","json-parse","moodle-core-notification-dialogue","overlay"]}); +YUI.add("moodle-gradereport_history-userselector",function(e,t){var n="gradereport_history",r={AJAXURL:"ajaxurl",BASE:"base",CHECKBOX_NAME_PREFIX:"usp-u",COURSEID:"courseid",DIALOGUE_PREFIX:"moodle-dialogue",NAME:"gradereport_history_usp",PAGE:"page",PARAMS:"params",PERPAGE:"perPage",SEARCH:"search",SEARCHBTN:"searchbtn",SELECTEDUSERS:"selectedusers",URL:"url",USERCOUNT:"userCount",USERFULLNAMES:"userfullnames"},i={ACCESSHIDE:"accesshide",AJAXCONTENT:"usp-ajax-content",CHECKBOX:"usp-checkbox",CLOSE:"close",CLOSEBTN:"usp-finish",CONTENT:"usp-content",DETAILS:"details",EXTRAFIELDS:"extrafields",FIRSTADDED:"usp-first-added",FULLNAME:"fullname",HEADER:"usp-header",HIDDEN:"hidden",LIGHTBOX:"usp-loading-lightbox",LOADINGICON:"loading-icon",MORERESULTS:"usp-more-results",OPTIONS:"options",PICTURE:"usp-picture",RESULTSCOUNT:"usp-results-count",SEARCH:"usp-search",SEARCHBTN:"usp-search-btn",SEARCHFIELD:"usp-search-field",SEARCHRESULTS:"usp-search-results",SELECTED:"selected",USER:"user",USERS:"users",WRAP:"usp-wrap"},s={AJAXCONTENT:"."+i.AJAXCONTENT,FINISHBTN:"."+i.CLOSEBTN+" input",FIRSTADDED:"."+i.FIRSTADDED,FULLNAME:"."+i.FULLNAME+" label",LIGHTBOX:"."+i.LIGHTBOX,MORERESULTS:"."+i.MORERESULTS,OPTIONS:"."+i.OPTIONS,PICTURE:"."+i.USER+" .userpicture",RESULTSCOUNT:"."+i.RESULTSCOUNT,RESULTSUSERS:"."+i.SEARCHRESULTS+" ."+i.USERS,SEARCHBTN:"."+i.SEARCHBTN,SEARCHFIELD:"."+i.SEARCHFIELD,SELECTEDNAMES:".felement .selectednames",TRIGGER:".gradereport_history_plugin input.selectortrigger",USER:"."+i.USER,USERFULLNAMES:'input[name="userfullnames"]',USERIDS:'input[name="userids"]',USERSELECT:"."+i.CHECKBOX+" input[type=checkbox]"},o=e.Node.create,u=function(){u.superclass.constructor.apply(this,arguments)};e.namespace("M.gradereport_history").UserSelector=e.extend(u,M.core.dialogue,{_firstDisplay:!0,_usersBufferList:null,_userTemplate:null,initializer:function(){var t=this.get("boundingBox"),u,a,f;f=e.Handlebars.compile('
{{get_string
'),u=o(f({COMPONENT:n,CSS:i,loadingIcon:M.util.image_url("i/loading","moodle")})),this.getStdModNode(e.WidgetStdMod.HEADER).prepend(o("

"+this.get("title")+"

")),this.setStdModContent(e.WidgetStdMod.BODY,u,e.WidgetStdMod.REPLACE),this.get("boundingBox").one(".moodle-dialogue-wrap").addClass("moodle-dialogue-content"),this.loadUsersFromForm(),e.one(s.TRIGGER).on("click",this.show,this),t.one(s.FINISHBTN).on("click",this.finishSelectingUsers,this),e.delegate("click",this.selectUser,t.one(s.AJAXCONTENT),s.USERSELECT,this),e.delegate("click",this.selectUser,t.one(s.AJAXCONTENT),s.PICTURE,this),a=this.get(r.PARAMS),a.id=this.get(r.COURSEID),this.set(r.PARAMS,a),t.one(s.SEARCHBTN).on("click",this.search,this,!1)},show:function(t){var n;this._usersBufferList={},this._firstDisplay?(this._firstDisplay=!1,this.search(t,!1)):(this._usersBufferList=e.clone(this.get(r.USERFULLNAMES)),n=this.get("boundingBox"),n.all(s.USERSELECT).set("checked",!1),e.Object.each(this._usersBufferList,function(e,t){n.one(s.USERSELECT+"[name="+r.CHECKBOX_NAME_PREFIX+t+"]").set("checked",!0)})),e.namespace("M.gradereport_history.UserSelector").superclass.show.call(this)},search:function(t,n){t&&(t.halt(),t.preventDefault());var i;n?this.set(r.PAGE,this.get(r.PAGE)+1):(this.set(r.USERCOUNT,0),this.set(r.PAGE,0)),i=this.get(r.PARAMS),i.sesskey=M.cfg.sesskey,i.action="searchusers",i.search=this.get("boundingBox").one(s.SEARCHFIELD).get("value"),i.page=this.get(r.PAGE),i.perpage=this.get(r.PERPAGE),e.io(M.cfg.wwwroot+this.get(r.AJAXURL),{method:"POST",data:build_querystring(i),on:{start:this.preSearch,complete:this.processSearchResults,end:this.postSearch},context:this,arguments:{append:n}})},preSearch:function(e,t){var n=this.get("boundingBox");n.one(s.LIGHTBOX).removeClass(i.HIDDEN),t.append||n.one(s.RESULTSCOUNT).setContent(M.util.get_string("loading","admin"))},postSearch:function(e,t){var n=this.get("boundingBox"),r=n.one(s.FIRSTADDED);n.one(s.LIGHTBOX).addClass(i.HIDDEN),t.append&&r&&r.one(s.USERSELECT).focus()},processSearchResults:function(t,u,a){var f=!1,l=!1,c=this.get("boundingBox"),h,p,d,v,m,g=!0,y,b,w,E,S;try{f=e.JSON.parse(u.responseText);if(!f.success||f.error)l=!0}catch(x){l=!0}if(l){this.setContent(""),c.one(s.RESULTSCOUNT).setContent(M.util.get_string("errajaxsearch",n));return}a.append?h=c.one(s.RESULTSUSERS):h=o('
'),this._userTemplate||(this._userTemplate=e.Handlebars.compile('
{{{picture}}}
{{extrafields}}
')),p=this._userTemplate,d=this.get(r.USERCOUNT),v="";for(m in f.response.users)d++,user=f.response.users[m],e.Object.hasKey(this._usersBufferList,user.userid)?(v=" "+i.SELECTED,E="checked"):(v="",E=""),y=o(p({checkboxId:e.guid(),checked:E,COMPONENT:n,count:d,CSS:i,extrafields:user.extrafields,extraFieldsId:e.guid(),fullname:user.fullname +,picture:user.picture,selected:v,userId:user.userid,USP:r})),a.append&&g&&(h.all(s.FIRSTADDED).removeClass(i.FIRSTADDED),y.addClass(i.FIRSTADDED),g=!1),h.append(y);this.set(r.USERCOUNT,d),S=parseInt(f.response.totalusers,10),a.append?S<=(this.get(r.PAGE)+1)*this.get(r.PERPAGE)&&c.one(s.MORERESULTS).remove():(S===0?(c.one(s.RESULTSCOUNT).setContent(M.util.get_string("noresults","moodle")),b=""):(S===1?c.one(s.RESULTSCOUNT).setContent(M.util.get_string("foundoneuser",n)):c.one(s.RESULTSCOUNT).setContent(M.util.get_string("foundnusers",n,S)),b=o('
').append(h),f.response.totalusers>(this.get(r.PAGE)+1)*this.get(r.PERPAGE)&&(w=o('"),w.one("a").on("click",this.search,this,!0),w.one("a").on("key",this.search,"space",this,!0),b.append(w))),this.setContent(b))},fetchMore:function(e){this.search(e,!0)},finishSelectingUsers:function(e){e.preventDefault(),this.applySelection(),this.hide()},applySelection:function(t){var n=e.Object.values(this._usersBufferList);this.set(r.SELECTEDUSERS,n),this.set(r.USERFULLNAMES,this._usersBufferList),this.setnamedisplay(),e.one(s.USERIDS).set("value",n.join())},loadUsersFromForm:function(){var t=e.one(s.USERIDS).get("value").split(",");t[0]===""&&(t=[]),this.set(r.SELECTEDUSERS,t)},selectUser:function(e){var t=e.currentTarget.ancestor(s.USER),n=t.one(s.USERSELECT),r=t.one(s.FULLNAME).get("innerHTML"),o=n.get("checked"),u=t.getData("userid");e.currentTarget!==n&&(o=!o,n.set("checked",o)),o?(this._usersBufferList[u]=r,t.addClass(i.SELECTED)):(delete this._usersBufferList[u],delete this._usersBufferList[parseInt(u,10)],t.removeClass(i.SELECTED))},setContent:function(e){this.get("boundingBox").one(s.AJAXCONTENT).setContent(e)},setnamedisplay:function(){var t=e.Object.values(this.get(r.USERFULLNAMES));e.one(s.SELECTEDNAMES).set("innerHTML",t.join(", ")),e.one(s.USERFULLNAMES).set("value",t.join())}},{NAME:r.NAME,CSS_PREFIX:r.CSS_PREFIX,ATTRS:{extraClasses:{value:["gradereport_history_usp"]},title:{validator:e.Lang.isString,value:M.util.get_string("selectusers",n)},focusOnPreviousTargetAfterHide:{value:!0},width:{value:"500px"},url:{validator:e.Lang.isString},ajaxurl:{validator:e.Lang.isString},selectedusers:{validator:e.Lang.isArray,value:null},userfullnames:{validator:e.Lang.isObject,value:null},courseid:{value:null},params:{validator:e.Lang.isArray,value:[]},page:{validator:e.Lang.isNumber,value:0},userCount:{value:0,validator:e.Lang.isNumber},perPage:{value:25,Validator:e.Lang.isNumber}}}),e.Base.modifyAttrs(e.namespace("M.gradereport_history.UserSelector"),{visible:{value:!1},modal:{value:!0},draggable:{value:!0}}),e.namespace("M.gradereport_history.UserSelector").init=function(e){return new u(e)}},"@VERSION@",{requires:["escape","event-delegate","event-key","handlebars","io-base","json-parse","moodle-core-notification-dialogue","overlay"]}); diff --git a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector.js b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector.js index 9ec14a62b561c..deb88e691954d 100644 --- a/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector.js +++ b/grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector.js @@ -52,36 +52,39 @@ var CSS = { AJAXCONTENT : 'usp-ajax-content', CHECKBOX : 'usp-checkbox', CLOSE : 'close', - CLOSEBTN : 'close-button', + CLOSEBTN : 'usp-finish', CONTENT : 'usp-content', DETAILS : 'details', EXTRAFIELDS : 'extrafields', - FOOTER : 'usp-footer', + FIRSTADDED : 'usp-first-added', FULLNAME : 'fullname', + HEADER : 'usp-header', HIDDEN : 'hidden', LIGHTBOX : 'usp-loading-lightbox', LOADINGICON : 'loading-icon', MORERESULTS : 'usp-more-results', OPTIONS : 'options', - PICTURE : 'picture', + PICTURE : 'usp-picture', + RESULTSCOUNT : 'usp-results-count', SEARCH : 'usp-search', SEARCHBTN : 'usp-search-btn', SEARCHFIELD : 'usp-search-field', SEARCHRESULTS : 'usp-search-results', SELECTED : 'selected', - TOTALUSERS : 'totalusers', USER : 'user', USERS : 'users', WRAP : 'usp-wrap' }; var SELECTORS = { AJAXCONTENT: '.' + CSS.AJAXCONTENT, - FOOTER: '.' + CSS.FOOTER, - FOOTERCLOSE: '.' + CSS.FOOTER + ' .' + CSS.CLOSEBTN + ' input', + FINISHBTN: '.' + CSS.CLOSEBTN + ' input', + FIRSTADDED: '.' + CSS.FIRSTADDED, FULLNAME: '.' + CSS.FULLNAME + ' label', LIGHTBOX: '.' + CSS.LIGHTBOX, MORERESULTS: '.' + CSS.MORERESULTS, OPTIONS: '.' + CSS.OPTIONS, + PICTURE: '.' + CSS.USER + ' .userpicture', + RESULTSCOUNT: '.' + CSS.RESULTSCOUNT, RESULTSUSERS: '.' + CSS.SEARCHRESULTS + ' .' + CSS.USERS, SEARCHBTN: '.' + CSS.SEARCHBTN, SEARCHFIELD: '.' + CSS.SEARCHFIELD, @@ -90,7 +93,7 @@ var SELECTORS = { USER: '.' + CSS.USER, USERFULLNAMES: 'input[name="userfullnames"]', USERIDS: 'input[name="userids"]', - USERSELECT: '.' + CSS.USER + ' .' + CSS.CHECKBOX + ' input[type=checkbox]' + USERSELECT: '.' + CSS.CHECKBOX + ' input[type=checkbox]' }; var create = Y.Node.create; @@ -137,33 +140,35 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor initializer : function() { var bb = this.get('boundingBox'), content, - list, params, tpl; tpl = Y.Handlebars.compile( - '
' + - '
' + - '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + '
' + '{{get_string ' + '
' + - '
' + - '
' + - '
' + - '' + - '' + - '' + - '
' + '
' + - '' + + '' + '
' + - '
' + - '
'); + '' + + '
' + + '
'); content = create( tpl({ @@ -180,9 +185,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor // Use standard dialogue class name. This removes the default styling of the footer. this.get('boundingBox').one('.moodle-dialogue-wrap').addClass('moodle-dialogue-content'); - this.set(USP.SEARCH, bb.one(SELECTORS.SEARCHFIELD)); - this.set(USP.SEARCHBTN, bb.one(SELECTORS.SEARCHBTN)); - // Load the list of users. this.loadUsersFromForm(); @@ -190,23 +192,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor Y.one(SELECTORS.TRIGGER).on('click', this.show, this); // The button to finalize the selection. - bb.one(SELECTORS.FOOTERCLOSE).on('click', this.finishSelectingUsers, this); + bb.one(SELECTORS.FINISHBTN).on('click', this.finishSelectingUsers, this); + + // Delegate the action to select a user. + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.USERSELECT, this); + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.PICTURE, this); 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); - }, - - /** - * Before the search starts. - * - * @method preSearch - */ - preSearch : function(e) { - this.search(null, false); + bb.one(SELECTORS.SEARCHBTN).on('click', this.search, this, false); }, /** @@ -253,7 +249,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor params = this.get(USP.PARAMS); params.sesskey = M.cfg.sesskey; params.action = 'searchusers'; - params.search = this.get(USP.SEARCH).get('value'); + params.search = this.get('boundingBox').one(SELECTORS.SEARCHFIELD).get('value'); params.page = this.get(USP.PAGE); params.perpage = this.get(USP.PERPAGE); @@ -261,40 +257,54 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor method:'POST', data:build_querystring(params), on : { - start : this.displayLoading, + start : this.preSearch, complete: this.processSearchResults, - end : this.removeLoading + end : this.postSearch }, context:this, - arguments:{ - append:append + "arguments": { // Quoted because this is a reserved keyword. + append: append } }); }, /** - * Display the loading info. + * Pre search callback. * - * @method displayLoading + * @method preSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - displayLoading : function() { + preSearch: function(unused, args) { var bb = this.get('boundingBox'); + + // Display the lightbox. bb.one(SELECTORS.LIGHTBOX).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).addClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).addClass(CSS.HIDDEN); + + // Set the number of results to 'loading...'. + if (!args.append) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('loading', 'admin')); + } }, /** - * Hide the loading info. + * Post search callback. * - * @method removeLoading + * @method postSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - removeLoading : function() { - var bb = this.get('boundingBox'); + postSearch: function(unused, args) { + var bb = this.get('boundingBox'), + firstAdded = bb.one(SELECTORS.FIRSTADDED); + + // Hide the lightbox. bb.one(SELECTORS.LIGHTBOX).addClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).removeClass(CSS.HIDDEN); - this.centerDialogue(); + + // Sets the focus on the newly added user if we are appending results. + if (args.append && firstAdded) { + firstAdded.one(SELECTORS.USERSELECT).focus(); + } }, /** @@ -304,34 +314,45 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ processSearchResults : function(tid, outcome, args) { var result = false, + error = false, + bb = this.get('boundingBox'), users, userTemplate, count, selected, i, + firstAdded = true, node, - usersstr, content, fetchmore, - checked; + checked, + totalUsers; + + // Decodes the result. try { result = Y.JSON.parse(outcome.responseText); - if (result.error) { - return new M.core.ajaxException(result); + if (!result.success || result.error) { + error = true; } } catch (e) { - new M.core.exception(e); + error = true; } - if (!result.success) { - this.setContent = M.util.get_string('errajaxsearch', 'enrol'); + + // There was an error. + if (error) { + this.setContent(''); + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('errajaxsearch', COMPONENT)); + return; } + // Create the div containing the users when it is a fresh search. if (!args.append) { users = create('
'); } else { - users = this.get('boundingBox').one(SELECTORS.RESULTSUSERS); + users = bb.one(SELECTORS.RESULTSUSERS); } + // Compile the template for each user node. if (!this._userTemplate) { this._userTemplate = Y.Handlebars.compile( '
' + @@ -351,6 +372,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor } userTemplate = this._userTemplate; + // Append the users one by one. count = this.get(USP.USERCOUNT); selected = ''; for (i in result.response.users) { @@ -380,34 +402,57 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor userId: user.userid, USP: USP })); + + // Noting the first user that was when adding more results. + if (args.append && firstAdded) { + users.all(SELECTORS.FIRSTADDED).removeClass(CSS.FIRSTADDED); + node.addClass(CSS.FIRSTADDED); + firstAdded = false; + } users.append(node); } this.set(USP.USERCOUNT, count); + + // Update the count of users, and add a button to load more if need be. + totalUsers = parseInt(result.response.totalusers, 10); if (!args.append) { - if (result.response.totalusers == '1') { - usersstr = M.util.get_string('ajaxoneuserfound', 'enrol'); + if (totalUsers === 0) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('noresults', 'moodle')); + content = ''; } else { - usersstr = M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers); - } - content = create('
') - .append(create('
'+usersstr+'
')) - .append(users); - if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - fetchmore = create(''); - fetchmore.on('click', this.search, this, true); - content.append(fetchmore); + if (totalUsers === 1) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundoneuser', COMPONENT)); + } else { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundnusers', COMPONENT, totalUsers)); + } + + content = create('
') + .append(users); + if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + fetchmore = create(''); + fetchmore.one('a').on('click', this.search, this, true); + fetchmore.one('a').on('key', this.search, 'space', this, true); + content.append(fetchmore); + } } this.setContent(content); - - // Delegate the action when selecting a user. - Y.delegate("click", this.selectUser, users, SELECTORS.USERSELECT, this); } else { - if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - this.get('boundingBox').one(SELECTORS.MORERESULTS).remove(); + if (totalUsers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + bb.one(SELECTORS.MORERESULTS).remove(); } } }, + /** + * Fetch more results. + * + * @param {EventFacade} e The event. + */ + fetchMore: function(e) { + this.search(e, true); + }, + /** * When the user has finished selecting users. * @@ -415,6 +460,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor * @param {EventFacade} e The event. */ finishSelectingUsers: function(e) { + e.preventDefault(); this.applySelection(); this.hide(); }, @@ -455,10 +501,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ selectUser : function(e) { var user = e.currentTarget.ancestor(SELECTORS.USER), + checkbox = user.one(SELECTORS.USERSELECT), fullname = user.one(SELECTORS.FULLNAME).get('innerHTML'), - checked = e.currentTarget.get('checked'), + checked = checkbox.get('checked'), userId = user.getData('userid'); + if (e.currentTarget !== checkbox) { + // We triggered the selection from another node, so we need to change the checkbox value. + checked = !checked; + checkbox.set('checked', checked); + } + if (checked) { // Selecting the user. this._usersBufferList[userId] = fullname; @@ -496,6 +549,12 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor CSS_PREFIX : USP.CSS_PREFIX, ATTRS : { + /** + * List of extra classes. + * + * @attribute extraClasses + * @type Array + */ extraClasses: { value: [ 'gradereport_history_usp' @@ -619,22 +678,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor validator : Y.Lang.isNumber }, - /** - * The search field. - * - * @attribute search - * @type Node - */ - search : { - setter : function(node) { - var n = Y.one(node); - if (!n) { - Y.fail(USP.NAME+': invalid search node set'); - } - return n; - } - }, - /** * The number of results per page. * @@ -674,6 +717,13 @@ Y.Base.modifyAttrs(Y.namespace('M.gradereport_history.UserSelector'), { value: true }, + /** + * Whether the widget should be draggable or not. + * + * @attribute draggable + * @type Boolean + * @default true + */ draggable: { value: true } @@ -687,7 +737,6 @@ Y.namespace('M.gradereport_history.UserSelector').init = function(cfg) { }, '@VERSION@', { "requires": [ - "dd-plugin", "escape", "event-delegate", "event-key", diff --git a/grade/report/history/yui/src/userselector/js/userselector.js b/grade/report/history/yui/src/userselector/js/userselector.js index ab78aaa3b56fd..6dda25b49be84 100644 --- a/grade/report/history/yui/src/userselector/js/userselector.js +++ b/grade/report/history/yui/src/userselector/js/userselector.js @@ -50,36 +50,39 @@ var CSS = { AJAXCONTENT : 'usp-ajax-content', CHECKBOX : 'usp-checkbox', CLOSE : 'close', - CLOSEBTN : 'close-button', + CLOSEBTN : 'usp-finish', CONTENT : 'usp-content', DETAILS : 'details', EXTRAFIELDS : 'extrafields', - FOOTER : 'usp-footer', + FIRSTADDED : 'usp-first-added', FULLNAME : 'fullname', + HEADER : 'usp-header', HIDDEN : 'hidden', LIGHTBOX : 'usp-loading-lightbox', LOADINGICON : 'loading-icon', MORERESULTS : 'usp-more-results', OPTIONS : 'options', - PICTURE : 'picture', + PICTURE : 'usp-picture', + RESULTSCOUNT : 'usp-results-count', SEARCH : 'usp-search', SEARCHBTN : 'usp-search-btn', SEARCHFIELD : 'usp-search-field', SEARCHRESULTS : 'usp-search-results', SELECTED : 'selected', - TOTALUSERS : 'totalusers', USER : 'user', USERS : 'users', WRAP : 'usp-wrap' }; var SELECTORS = { AJAXCONTENT: '.' + CSS.AJAXCONTENT, - FOOTER: '.' + CSS.FOOTER, - FOOTERCLOSE: '.' + CSS.FOOTER + ' .' + CSS.CLOSEBTN + ' input', + FINISHBTN: '.' + CSS.CLOSEBTN + ' input', + FIRSTADDED: '.' + CSS.FIRSTADDED, FULLNAME: '.' + CSS.FULLNAME + ' label', LIGHTBOX: '.' + CSS.LIGHTBOX, MORERESULTS: '.' + CSS.MORERESULTS, OPTIONS: '.' + CSS.OPTIONS, + PICTURE: '.' + CSS.USER + ' .userpicture', + RESULTSCOUNT: '.' + CSS.RESULTSCOUNT, RESULTSUSERS: '.' + CSS.SEARCHRESULTS + ' .' + CSS.USERS, SEARCHBTN: '.' + CSS.SEARCHBTN, SEARCHFIELD: '.' + CSS.SEARCHFIELD, @@ -88,7 +91,7 @@ var SELECTORS = { USER: '.' + CSS.USER, USERFULLNAMES: 'input[name="userfullnames"]', USERIDS: 'input[name="userids"]', - USERSELECT: '.' + CSS.USER + ' .' + CSS.CHECKBOX + ' input[type=checkbox]' + USERSELECT: '.' + CSS.CHECKBOX + ' input[type=checkbox]' }; var create = Y.Node.create; @@ -135,33 +138,35 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor initializer : function() { var bb = this.get('boundingBox'), content, - list, params, tpl; tpl = Y.Handlebars.compile( - '
' + - '
' + - '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + '
' + '{{get_string ' + '
' + - '
' + - '
' + - '
' + - '' + - '' + - '' + - '
' + '
' + - '' + + '' + '
' + - '
' + - '
'); + '' + + '
' + + '
'); content = create( tpl({ @@ -178,9 +183,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor // Use standard dialogue class name. This removes the default styling of the footer. this.get('boundingBox').one('.moodle-dialogue-wrap').addClass('moodle-dialogue-content'); - this.set(USP.SEARCH, bb.one(SELECTORS.SEARCHFIELD)); - this.set(USP.SEARCHBTN, bb.one(SELECTORS.SEARCHBTN)); - // Load the list of users. this.loadUsersFromForm(); @@ -188,23 +190,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor Y.one(SELECTORS.TRIGGER).on('click', this.show, this); // The button to finalize the selection. - bb.one(SELECTORS.FOOTERCLOSE).on('click', this.finishSelectingUsers, this); + bb.one(SELECTORS.FINISHBTN).on('click', this.finishSelectingUsers, this); + + // Delegate the action to select a user. + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.USERSELECT, this); + Y.delegate("click", this.selectUser, bb.one(SELECTORS.AJAXCONTENT), SELECTORS.PICTURE, this); 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); - }, - - /** - * Before the search starts. - * - * @method preSearch - */ - preSearch : function(e) { - this.search(null, false); + bb.one(SELECTORS.SEARCHBTN).on('click', this.search, this, false); }, /** @@ -251,7 +247,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor params = this.get(USP.PARAMS); params.sesskey = M.cfg.sesskey; params.action = 'searchusers'; - params.search = this.get(USP.SEARCH).get('value'); + params.search = this.get('boundingBox').one(SELECTORS.SEARCHFIELD).get('value'); params.page = this.get(USP.PAGE); params.perpage = this.get(USP.PERPAGE); @@ -259,40 +255,54 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor method:'POST', data:build_querystring(params), on : { - start : this.displayLoading, + start : this.preSearch, complete: this.processSearchResults, - end : this.removeLoading + end : this.postSearch }, context:this, - arguments:{ - append:append + "arguments": { // Quoted because this is a reserved keyword. + append: append } }); }, /** - * Display the loading info. + * Pre search callback. * - * @method displayLoading + * @method preSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - displayLoading : function() { + preSearch: function(unused, args) { var bb = this.get('boundingBox'); + + // Display the lightbox. bb.one(SELECTORS.LIGHTBOX).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).addClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).addClass(CSS.HIDDEN); + + // Set the number of results to 'loading...'. + if (!args.append) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('loading', 'admin')); + } }, /** - * Hide the loading info. + * Post search callback. * - * @method removeLoading + * @method postSearch + * @param {Mixed} unused Not sure what that is. + * @param {Object} args The arguments passed from YUI.io() */ - removeLoading : function() { - var bb = this.get('boundingBox'); + postSearch: function(unused, args) { + var bb = this.get('boundingBox'), + firstAdded = bb.one(SELECTORS.FIRSTADDED); + + // Hide the lightbox. bb.one(SELECTORS.LIGHTBOX).addClass(CSS.HIDDEN); - bb.one(SELECTORS.AJAXCONTENT).removeClass(CSS.HIDDEN); - bb.one(SELECTORS.FOOTER).removeClass(CSS.HIDDEN); - this.centerDialogue(); + + // Sets the focus on the newly added user if we are appending results. + if (args.append && firstAdded) { + firstAdded.one(SELECTORS.USERSELECT).focus(); + } }, /** @@ -302,34 +312,45 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ processSearchResults : function(tid, outcome, args) { var result = false, + error = false, + bb = this.get('boundingBox'), users, userTemplate, count, selected, i, + firstAdded = true, node, - usersstr, content, fetchmore, - checked; + checked, + totalUsers; + + // Decodes the result. try { result = Y.JSON.parse(outcome.responseText); - if (result.error) { - return new M.core.ajaxException(result); + if (!result.success || result.error) { + error = true; } } catch (e) { - new M.core.exception(e); + error = true; } - if (!result.success) { - this.setContent = M.util.get_string('errajaxsearch', 'enrol'); + + // There was an error. + if (error) { + this.setContent(''); + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('errajaxsearch', COMPONENT)); + return; } + // Create the div containing the users when it is a fresh search. if (!args.append) { users = create('
'); } else { - users = this.get('boundingBox').one(SELECTORS.RESULTSUSERS); + users = bb.one(SELECTORS.RESULTSUSERS); } + // Compile the template for each user node. if (!this._userTemplate) { this._userTemplate = Y.Handlebars.compile( '
' + @@ -349,6 +370,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor } userTemplate = this._userTemplate; + // Append the users one by one. count = this.get(USP.USERCOUNT); selected = ''; for (i in result.response.users) { @@ -378,34 +400,57 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor userId: user.userid, USP: USP })); + + // Noting the first user that was when adding more results. + if (args.append && firstAdded) { + users.all(SELECTORS.FIRSTADDED).removeClass(CSS.FIRSTADDED); + node.addClass(CSS.FIRSTADDED); + firstAdded = false; + } users.append(node); } this.set(USP.USERCOUNT, count); + + // Update the count of users, and add a button to load more if need be. + totalUsers = parseInt(result.response.totalusers, 10); if (!args.append) { - if (result.response.totalusers == '1') { - usersstr = M.util.get_string('ajaxoneuserfound', 'enrol'); + if (totalUsers === 0) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('noresults', 'moodle')); + content = ''; } else { - usersstr = M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers); - } - content = create('
') - .append(create('
'+usersstr+'
')) - .append(users); - if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - fetchmore = create(''); - fetchmore.on('click', this.search, this, true); - content.append(fetchmore); + if (totalUsers === 1) { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundoneuser', COMPONENT)); + } else { + bb.one(SELECTORS.RESULTSCOUNT).setContent(M.util.get_string('foundnusers', COMPONENT, totalUsers)); + } + + content = create('
') + .append(users); + if (result.response.totalusers > (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + fetchmore = create(''); + fetchmore.one('a').on('click', this.search, this, true); + fetchmore.one('a').on('key', this.search, 'space', this, true); + content.append(fetchmore); + } } this.setContent(content); - - // Delegate the action when selecting a user. - Y.delegate("click", this.selectUser, users, SELECTORS.USERSELECT, this); } else { - if (result.response.totalusers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { - this.get('boundingBox').one(SELECTORS.MORERESULTS).remove(); + if (totalUsers <= (this.get(USP.PAGE)+1)*this.get(USP.PERPAGE)) { + bb.one(SELECTORS.MORERESULTS).remove(); } } }, + /** + * Fetch more results. + * + * @param {EventFacade} e The event. + */ + fetchMore: function(e) { + this.search(e, true); + }, + /** * When the user has finished selecting users. * @@ -413,6 +458,7 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor * @param {EventFacade} e The event. */ finishSelectingUsers: function(e) { + e.preventDefault(); this.applySelection(); this.hide(); }, @@ -453,10 +499,17 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor */ selectUser : function(e) { var user = e.currentTarget.ancestor(SELECTORS.USER), + checkbox = user.one(SELECTORS.USERSELECT), fullname = user.one(SELECTORS.FULLNAME).get('innerHTML'), - checked = e.currentTarget.get('checked'), + checked = checkbox.get('checked'), userId = user.getData('userid'); + if (e.currentTarget !== checkbox) { + // We triggered the selection from another node, so we need to change the checkbox value. + checked = !checked; + checkbox.set('checked', checked); + } + if (checked) { // Selecting the user. this._usersBufferList[userId] = fullname; @@ -494,6 +547,12 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor CSS_PREFIX : USP.CSS_PREFIX, ATTRS : { + /** + * List of extra classes. + * + * @attribute extraClasses + * @type Array + */ extraClasses: { value: [ 'gradereport_history_usp' @@ -617,22 +676,6 @@ Y.namespace('M.gradereport_history').UserSelector = Y.extend(USERSELECTOR, M.cor validator : Y.Lang.isNumber }, - /** - * The search field. - * - * @attribute search - * @type Node - */ - search : { - setter : function(node) { - var n = Y.one(node); - if (!n) { - Y.fail(USP.NAME+': invalid search node set'); - } - return n; - } - }, - /** * The number of results per page. * @@ -672,6 +715,13 @@ Y.Base.modifyAttrs(Y.namespace('M.gradereport_history.UserSelector'), { value: true }, + /** + * Whether the widget should be draggable or not. + * + * @attribute draggable + * @type Boolean + * @default true + */ draggable: { value: true } diff --git a/grade/report/history/yui/src/userselector/meta/userselector.json b/grade/report/history/yui/src/userselector/meta/userselector.json index d5dccc154f25c..d532a20b0e711 100644 --- a/grade/report/history/yui/src/userselector/meta/userselector.json +++ b/grade/report/history/yui/src/userselector/meta/userselector.json @@ -1,7 +1,6 @@ { "moodle-gradereport_history-userselector": { "requires": [ - "dd-plugin", "escape", "event-delegate", "event-key",