[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 // This file is part of Moodle - http://moodle.org/ 2 // 3 // Moodle is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // (at your option) any later version. 7 // 8 // Moodle is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 15 16 /** 17 * Javascript controller for the "Grading" panel at the right of the page. 18 * 19 * @module mod_assign/grading_panel 20 * @package mod_assign 21 * @class GradingPanel 22 * @copyright 2016 Damyon Wiese <damyon@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since 3.1 25 */ 26 define(['jquery', 'core/notification', 'core/templates', 'core/fragment', 27 'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker', 28 'mod_assign/grading_events'], 29 function($, notification, templates, fragment, ajax, str, checker, GradingEvents) { 30 31 /** 32 * GradingPanel class. 33 * 34 * @class GradingPanel 35 * @param {String} selector The selector for the page region containing the user navigation. 36 */ 37 var GradingPanel = function(selector) { 38 this._regionSelector = selector; 39 this._region = $(selector); 40 this._userCache = []; 41 42 this.registerEventListeners(); 43 }; 44 45 /** @type {String} Selector for the page region containing the user navigation. */ 46 GradingPanel.prototype._regionSelector = null; 47 48 /** @type {Integer} Remember the last user id to prevent unnessecary reloads. */ 49 GradingPanel.prototype._lastUserId = 0; 50 51 /** @type {Integer} Remember the last attempt number to prevent unnessecary reloads. */ 52 GradingPanel.prototype._lastAttemptNumber = -1; 53 54 /** @type {JQuery} JQuery node for the page region containing the user navigation. */ 55 GradingPanel.prototype._region = null; 56 57 /** 58 * Fade the dom node out, update it, and fade it back. 59 * 60 * @private 61 * @method _niceReplaceNodeContents 62 * @param {JQuery} node 63 * @param {String} html 64 * @param {String} js 65 * @return {Deferred} promise resolved when the animations are complete. 66 */ 67 GradingPanel.prototype._niceReplaceNodeContents = function(node, html, js) { 68 var promise = $.Deferred(); 69 70 node.fadeOut("fast", function() { 71 templates.replaceNodeContents(node, html, js); 72 node.fadeIn("fast", function() { 73 promise.resolve(); 74 }); 75 }); 76 77 return promise.promise(); 78 }; 79 80 /** 81 * Make sure all form fields have the latest saved state. 82 * @private 83 * @method _saveFormState 84 */ 85 GradingPanel.prototype._saveFormState = function() { 86 // Grrrrr! TinyMCE you know what you did. 87 if (typeof window.tinyMCE !== 'undefined') { 88 window.tinyMCE.triggerSave(); 89 } 90 91 // Copy data from notify students checkbox which was moved out of the form. 92 var checked = $('[data-region="grading-actions-form"] [name="sendstudentnotifications"]').val(); 93 $('.gradeform [name="sendstudentnotifications"]').val(checked); 94 }; 95 96 /** 97 * Make form submit via ajax. 98 * 99 * @private 100 * @param {Object} event 101 * @param {Integer} nextUserId 102 * @method _submitForm 103 */ 104 GradingPanel.prototype._submitForm = function(event, nextUserId) { 105 // The form was submitted - send it via ajax instead. 106 var form = $(this._region.find('form.gradeform')); 107 108 $('[data-region="overlay"]').show(); 109 110 // We call this, so other modules can update the form with the latest state. 111 form.trigger('save-form-state'); 112 113 // Now we get all the current values from the form. 114 var data = form.serialize(); 115 var assignmentid = this._region.attr('data-assignmentid'); 116 117 // Now we can continue... 118 ajax.call([{ 119 methodname: 'mod_assign_submit_grading_form', 120 args: {assignmentid: assignmentid, userid: this._lastUserId, jsonformdata: JSON.stringify(data)}, 121 done: this._handleFormSubmissionResponse.bind(this, data, nextUserId), 122 fail: notification.exception 123 }]); 124 }; 125 126 /** 127 * Handle form submission response. 128 * 129 * @private 130 * @method _handleFormSubmissionResponse 131 * @param {Array} formdata - submitted values 132 * @param {Integer} nextUserId - optional. The id of the user to load after the form is saved. 133 * @param {Array} response List of errors. 134 */ 135 GradingPanel.prototype._handleFormSubmissionResponse = function(formdata, nextUserId, response) { 136 if (typeof nextUserId === "undefined") { 137 nextUserId = this._lastUserId; 138 } 139 if (response.length) { 140 // There was an error saving the grade. Re-render the form using the submitted data so we can show 141 // validation errors. 142 $(document).trigger('reset', [this._lastUserId, formdata]); 143 } else { 144 str.get_strings([ 145 {key: 'changessaved', component: 'core'}, 146 {key: 'gradechangessaveddetail', component: 'mod_assign'}, 147 ]).done(function(strs) { 148 notification.alert(strs[0], strs[1]); 149 }).fail(notification.exception); 150 if (nextUserId == this._lastUserId) { 151 $(document).trigger('reset', nextUserId); 152 } else { 153 $(document).trigger('user-changed', nextUserId); 154 } 155 } 156 $('[data-region="overlay"]').hide(); 157 }; 158 159 /** 160 * Refresh form with default values. 161 * 162 * @private 163 * @method _resetForm 164 * @param {Event} e 165 * @param {Integer} userid 166 * @param {Array} formdata 167 */ 168 GradingPanel.prototype._resetForm = function(e, userid, formdata) { 169 // The form was cancelled - refresh with default values. 170 var event = $.Event("custom"); 171 if (typeof userid == "undefined") { 172 userid = this._lastUserId; 173 } 174 this._lastUserId = 0; 175 this._refreshGradingPanel(event, userid, formdata); 176 }; 177 178 /** 179 * Open a picker to choose an older attempt. 180 * 181 * @private 182 * @param {Object} e 183 * @method _chooseAttempt 184 */ 185 GradingPanel.prototype._chooseAttempt = function(e) { 186 // Show a dialog. 187 188 // The form is in the element pointed to by data-submissions. 189 var link = $(e.target); 190 var submissionsId = link.data('submissions'); 191 var submissionsform = $(document.getElementById(submissionsId)); 192 var formcopy = submissionsform.clone(); 193 var formhtml = formcopy.wrap($('<form/>')).html(); 194 195 str.get_strings([ 196 {key: 'viewadifferentattempt', component: 'mod_assign'}, 197 {key: 'view', component: 'core'}, 198 {key: 'cancel', component: 'core'}, 199 ]).done(function(strs) { 200 notification.confirm(strs[0], formhtml, strs[1], strs[2], function() { 201 var attemptnumber = $("input:radio[name='select-attemptnumber']:checked").val(); 202 203 this._refreshGradingPanel(null, this._lastUserId, '', attemptnumber); 204 }.bind(this)); 205 }.bind(this)).fail(notification.exception); 206 }; 207 208 /** 209 * Add popout buttons 210 * 211 * @private 212 * @method _addPopoutButtons 213 * @param {JQuery} selector The region selector to add popout buttons to. 214 */ 215 GradingPanel.prototype._addPopoutButtons = function(selector) { 216 var region = $(selector); 217 218 templates.render('mod_assign/popout_button', {}).done(function(html) { 219 region.find('.fitem_ffilemanager .fitemtitle').append(html); 220 region.find('.fitem_feditor .fitemtitle').append(html); 221 region.find('.fitem_f .fitemtitle').append(html); 222 223 region.on('click', '[data-region="popout-button"]', this._togglePopout.bind(this)); 224 }.bind(this)).fail(notification.exception); 225 }; 226 227 /** 228 * Make a div "popout" or "popback". 229 * 230 * @private 231 * @method _togglePopout 232 * @param {Event} event 233 */ 234 GradingPanel.prototype._togglePopout = function(event) { 235 event.preventDefault(); 236 var container = $(event.target).closest('.fitem'); 237 if (container.hasClass('popout')) { 238 $('.popout').removeClass('popout'); 239 } else { 240 $('.popout').removeClass('popout'); 241 container.addClass('popout'); 242 container.addClass('moodle-has-zindex'); 243 } 244 }; 245 246 /** 247 * Get the user context - re-render the template in the page. 248 * 249 * @private 250 * @method _refreshGradingPanel 251 * @param {Event} event 252 * @param {Number} userid 253 * @param {String} submissiondata serialised submission data. 254 * @param {Integer} attemptnumber 255 */ 256 GradingPanel.prototype._refreshGradingPanel = function(event, userid, submissiondata, attemptnumber) { 257 var contextid = this._region.attr('data-contextid'); 258 if (typeof submissiondata === 'undefined') { 259 submissiondata = ''; 260 } 261 if (typeof attemptnumber === 'undefined') { 262 attemptnumber = -1; 263 } 264 // Skip reloading if it is the same user. 265 if (this._lastUserId == userid && this._lastAttemptNumber == attemptnumber && submissiondata === '') { 266 return; 267 } 268 this._lastUserId = userid; 269 this._lastAttemptNumber = attemptnumber; 270 $(document).trigger('start-loading-user'); 271 // Tell behat to back off too. 272 window.M.util.js_pending('mod-assign-loading-user'); 273 // First insert the loading template. 274 templates.render('mod_assign/loading', {}).done(function(html, js) { 275 // Update the page. 276 this._niceReplaceNodeContents(this._region, html, js).done(function() { 277 if (userid > 0) { 278 this._region.show(); 279 // Reload the grading form "fragment" for this user. 280 var params = {userid: userid, attemptnumber: attemptnumber, jsonformdata: JSON.stringify(submissiondata)}; 281 fragment.loadFragment('mod_assign', 'gradingpanel', contextid, params).done(function(html, js) { 282 this._niceReplaceNodeContents(this._region, html, js) 283 .done(function() { 284 checker.saveFormState('[data-region="grade-panel"] .gradeform'); 285 $(document).on('editor-content-restored', function() { 286 // If the editor has some content that has been restored 287 // then save the form state again for comparison. 288 checker.saveFormState('[data-region="grade-panel"] .gradeform'); 289 }); 290 $('[data-region="attempt-chooser"]').on('click', this._chooseAttempt.bind(this)); 291 this._addPopoutButtons('[data-region="grade-panel"] .gradeform'); 292 $(document).trigger('finish-loading-user'); 293 // Tell behat we are friends again. 294 window.M.util.js_complete('mod-assign-loading-user'); 295 }.bind(this)) 296 .fail(notification.exception); 297 }.bind(this)).fail(notification.exception); 298 } else { 299 this._region.hide(); 300 var reviewPanel = $('[data-region="review-panel"]'); 301 if (reviewPanel.length) { 302 this._niceReplaceNodeContents(reviewPanel, '', ''); 303 } 304 $(document).trigger('finish-loading-user'); 305 // Tell behat we are friends again. 306 window.M.util.js_complete('mod-assign-loading-user'); 307 } 308 }.bind(this)); 309 }.bind(this)).fail(notification.exception); 310 }; 311 312 /** 313 * Get the grade panel element. 314 * 315 * @method getPanelElement 316 * @return {jQuery} 317 */ 318 GradingPanel.prototype.getPanelElement = function() { 319 return $('[data-region="grade-panel"]'); 320 }; 321 322 /** 323 * Hide the grade panel. 324 * 325 * @method collapsePanel 326 */ 327 GradingPanel.prototype.collapsePanel = function() { 328 this.getPanelElement().addClass('collapsed'); 329 }; 330 331 /** 332 * Show the grade panel. 333 * 334 * @method expandPanel 335 */ 336 GradingPanel.prototype.expandPanel = function() { 337 this.getPanelElement().removeClass('collapsed'); 338 }; 339 340 /** 341 * Register event listeners for the grade panel. 342 * 343 * @method registerEventListeners 344 */ 345 GradingPanel.prototype.registerEventListeners = function() { 346 var docElement = $(document); 347 348 docElement.on('user-changed', this._refreshGradingPanel.bind(this)); 349 docElement.on('save-changes', this._submitForm.bind(this)); 350 docElement.on('reset', this._resetForm.bind(this)); 351 352 docElement.on('save-form-state', this._saveFormState.bind(this)); 353 354 docElement.on(GradingEvents.COLLAPSE_GRADE_PANEL, function() { 355 this.collapsePanel(); 356 }.bind(this)); 357 358 // We should expand if the review panel is collapsed. 359 docElement.on(GradingEvents.COLLAPSE_REVIEW_PANEL, function() { 360 this.expandPanel(); 361 }.bind(this)); 362 363 docElement.on(GradingEvents.EXPAND_GRADE_PANEL, function() { 364 this.expandPanel(); 365 }.bind(this)); 366 }; 367 368 return GradingPanel; 369 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |