From f6bb3f482d3594fbb526a75167350a695ec78c13 Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Fri, 20 May 2016 08:15:20 +0000 Subject: [PATCH] MDL-54165 mod_assign: Collapsible review and grade panel --- mod/assign/amd/build/grading_actions.min.js | 2 +- mod/assign/amd/build/grading_events.min.js | 1 + mod/assign/amd/build/grading_panel.min.js | 2 +- .../amd/build/grading_review_panel.min.js | 2 +- mod/assign/amd/src/grading_actions.js | 170 +++++++++++- mod/assign/amd/src/grading_events.js | 32 +++ mod/assign/amd/src/grading_panel.js | 67 ++++- mod/assign/amd/src/grading_review_panel.js | 109 +++++++- mod/assign/lang/en/assign.php | 5 + mod/assign/styles.css | 249 +++++++++++++++++- mod/assign/templates/grading_actions.mustache | 9 + mod/assign/templates/grading_app.mustache | 24 +- 12 files changed, 636 insertions(+), 36 deletions(-) create mode 100644 mod/assign/amd/build/grading_events.min.js create mode 100644 mod/assign/amd/src/grading_events.js diff --git a/mod/assign/amd/build/grading_actions.min.js b/mod/assign/amd/build/grading_actions.min.js index a68cc232e3f..b5d6827c3fa 100644 --- a/mod/assign/amd/build/grading_actions.min.js +++ b/mod/assign/amd/build/grading_actions.min.js @@ -1 +1 @@ -define(["jquery"],function(a){var b=function(b){this._regionSelector=b,this._region=a(b),a(document).on("user-changed",this._showActionsForm.bind(this)),this._region.find('[name="savechanges"]').on("click",this._trigger.bind(this,"save-changes")),this._region.find('[name="resetbutton"]').on("click",this._trigger.bind(this,"reset")),this._region.find("form").on("submit",function(a){a.preventDefault()})};return b.prototype._regionSelector=null,b.prototype._lastUserId=0,b.prototype._region=null,b.prototype._showActionsForm=function(a,b){var c=this._region.find("[data-region=grading-actions-form]");b!=this._lastUserId&&b>0&&(this._lastUserId=b),b>0?c.removeClass("hide"):c.addClass("hide")},b.prototype._trigger=function(b){a(document).trigger(b)},b}); \ No newline at end of file +define(["jquery","mod_assign/grading_events"],function(a,b){var c=function(b){this._regionSelector=b,this._region=a(b),this.registerEventListeners()};return c.prototype._regionSelector=null,c.prototype._lastUserId=0,c.prototype._region=null,c.prototype._showActionsForm=function(a,b){var c=this._region.find("[data-region=grading-actions-form]");b!=this._lastUserId&&b>0&&(this._lastUserId=b),b>0?c.removeClass("hide"):c.addClass("hide")},c.prototype._trigger=function(b){a(document).trigger(b)},c.prototype.getReviewPanelElement=function(){return a('[data-region="review-panel"]')},c.prototype.hasReviewPanelElement=function(){return this.getReviewPanelElement().length>0},c.prototype.getCollapseGradePanelButton=function(){return a('[data-region="grade-actions"] .collapse-grade-panel')},c.prototype.getCollapseReviewPanelButton=function(){return a('[data-region="grade-actions"] .collapse-review-panel')},c.prototype.getExpandAllPanelsButton=function(){return a('[data-region="grade-actions"] .collapse-none')},c.prototype.resetLayoutButtons=function(){this.getCollapseGradePanelButton().removeClass("active"),this.getCollapseReviewPanelButton().removeClass("active"),this.getExpandAllPanelsButton().removeClass("active")},c.prototype.collapseReviewPanel=function(){a(document).trigger(b.COLLAPSE_REVIEW_PANEL),a(document).trigger(b.EXPAND_GRADE_PANEL),this.resetLayoutButtons(),this.getCollapseReviewPanelButton().addClass("active")},c.prototype.collapseGradePanel=function(){a(document).trigger(b.COLLAPSE_GRADE_PANEL),a(document).trigger(b.EXPAND_REVIEW_PANEL),this.resetLayoutButtons(),this.getCollapseGradePanelButton().addClass("active")},c.prototype.expandAllPanels=function(){a(document).trigger(b.EXPAND_GRADE_PANEL),a(document).trigger(b.EXPAND_REVIEW_PANEL),this.resetLayoutButtons(),this.getExpandAllPanelsButton().addClass("active")},c.prototype.registerEventListeners=function(){if(this.hasReviewPanelElement()){var b=this.getCollapseReviewPanelButton();b.click(function(a){this.collapseReviewPanel(),a.preventDefault()}.bind(this)),b.keydown(function(a){a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(13===a.keyCode||32===a.keyCode)&&(this.collapseReviewPanel(),a.preventDefault())}.bind(this));var c=this.getCollapseGradePanelButton();c.click(function(a){this.collapseGradePanel(),a.preventDefault()}.bind(this)),c.keydown(function(a){a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(13===a.keyCode||32===a.keyCode)&&(this.collapseGradePanel(),a.preventDefault())}.bind(this));var d=this.getExpandAllPanelsButton();d.click(function(a){this.expandAllPanels(),a.preventDefault()}.bind(this)),d.keydown(function(a){a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(13===a.keyCode||32===a.keyCode)&&(this.expandAllPanels(),a.preventDefault())}.bind(this))}a(document).on("user-changed",this._showActionsForm.bind(this)),this._region.find('[name="savechanges"]').on("click",this._trigger.bind(this,"save-changes")),this._region.find('[name="resetbutton"]').on("click",this._trigger.bind(this,"reset")),this._region.find("form").on("submit",function(a){a.preventDefault()})},c}); \ No newline at end of file diff --git a/mod/assign/amd/build/grading_events.min.js b/mod/assign/amd/build/grading_events.min.js new file mode 100644 index 00000000000..6152079a36f --- /dev/null +++ b/mod/assign/amd/build/grading_events.min.js @@ -0,0 +1 @@ +define(function(){return{COLLAPSE_REVIEW_PANEL:"grading:collapse-review-panel",EXPAND_REVIEW_PANEL:"grading:expand-review-panel",COLLAPSE_GRADE_PANEL:"grading:collapse-grade-panel",EXPAND_GRADE_PANEL:"grading:expand-grade-panel"}}); \ No newline at end of file diff --git a/mod/assign/amd/build/grading_panel.min.js b/mod/assign/amd/build/grading_panel.min.js index 83022c463c7..2b81723fdb4 100644 --- a/mod/assign/amd/build/grading_panel.min.js +++ b/mod/assign/amd/build/grading_panel.min.js @@ -1 +1 @@ -define(["jquery","core/notification","core/templates","core/fragment","core/ajax","core/str","mod_assign/grading_form_change_checker"],function(a,b,c,d,e,f,g){var h=function(b){this._regionSelector=b,this._region=a(b),this._userCache=[],a(document).on("user-changed",this._refreshGradingPanel.bind(this)),a(document).on("save-changes",this._submitForm.bind(this)),a(document).on("reset",this._resetForm.bind(this)),a(document).on("save-form-state",this._saveFormState.bind(this))};return h.prototype._regionSelector=null,h.prototype._lastUserId=0,h.prototype._lastAttemptNumber=-1,h.prototype._region=null,h.prototype._niceReplaceNodeContents=function(b,d,e){var f=a.Deferred();return b.fadeOut("fast",function(){c.replaceNodeContents(b,d,e),b.fadeIn("fast",function(){f.resolve()})}),f.promise()},h.prototype._saveFormState=function(){"undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave();var b=a('[data-region="grading-actions-form"] [name="sendstudentnotifications"]').val();a('.gradeform [name="sendstudentnotifications"]').val(b)},h.prototype._submitForm=function(c,d){var f=a(this._region.find("form.gradeform"));a('[data-region="overlay"]').show(),f.trigger("save-form-state");var g=f.serialize(),h=this._region.attr("data-assignmentid");e.call([{methodname:"mod_assign_submit_grading_form",args:{assignmentid:h,userid:this._lastUserId,jsonformdata:JSON.stringify(g)},done:this._handleFormSubmissionResponse.bind(this,g,d),fail:b.exception}])},h.prototype._handleFormSubmissionResponse=function(c,d,e){"undefined"==typeof d&&(d=this._lastUserId),e.length?a(document).trigger("reset",[this._lastUserId,c]):(f.get_strings([{key:"changessaved",component:"core"},{key:"gradechangessaveddetail",component:"mod_assign"}]).done(function(a){b.alert(a[0],a[1])}).fail(b.exception),d==this._lastUserId?a(document).trigger("reset",d):a(document).trigger("user-changed",d)),a('[data-region="overlay"]').hide()},h.prototype._resetForm=function(b,c,d){var e=a.Event("custom");"undefined"==typeof c&&(c=this._lastUserId),this._lastUserId=0,this._refreshGradingPanel(e,c,d)},h.prototype._chooseAttempt=function(c){var d=a(c.target),e=d.data("submissions"),g=a(document.getElementById(e)),h=g.clone(),i=h.wrap(a("
")).html();f.get_strings([{key:"viewadifferentattempt",component:"mod_assign"},{key:"view",component:"core"},{key:"cancel",component:"core"}]).done(function(c){b.confirm(c[0],i,c[1],c[2],function(){var b=a("input:radio[name='select-attemptnumber']:checked").val();this._refreshGradingPanel(null,this._lastUserId,"",b)}.bind(this))}.bind(this)).fail(b.exception)},h.prototype._addPopoutButtons=function(d){var e=a(d);c.render("mod_assign/popout_button",{}).done(function(a){e.find(".fitem_ffilemanager .fitemtitle").append(a),e.find(".fitem_feditor .fitemtitle").append(a),e.find(".fitem_f .fitemtitle").append(a),e.on("click",'[data-region="popout-button"]',this._togglePopout.bind(this))}.bind(this)).fail(b.exception)},h.prototype._togglePopout=function(b){b.preventDefault();var c=a(b.target).closest(".fitem");c.hasClass("popout")?a(".popout").removeClass("popout"):(a(".popout").removeClass("popout"),c.addClass("popout"),c.addClass("moodle-has-zindex"))},h.prototype._refreshGradingPanel=function(e,f,h,i){var j=this._region.attr("data-contextid");"undefined"==typeof h&&(h=""),"undefined"==typeof i&&(i=-1),(this._lastUserId!=f||this._lastAttemptNumber!=i||""!==h)&&(this._lastUserId=f,this._lastAttemptNumber=i,a(document).trigger("start-loading-user"),window.M.util.js_pending("mod-assign-loading-user"),c.render("mod_assign/loading",{}).done(function(c,e){this._niceReplaceNodeContents(this._region,c,e).done(function(){if(f>0){this._region.show();var c={userid:f,attemptnumber:i,jsonformdata:JSON.stringify(h)};d.loadFragment("mod_assign","gradingpanel",j,c).done(function(c,d){this._niceReplaceNodeContents(this._region,c,d).done(function(){g.saveFormState('[data-region="grade-panel"] .gradeform'),a('[data-region="attempt-chooser"]').on("click",this._chooseAttempt.bind(this)),this._addPopoutButtons('[data-region="grade-panel"] .gradeform'),a(document).trigger("finish-loading-user"),window.M.util.js_complete("mod-assign-loading-user")}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)}else{this._region.hide();var e=a('[data-region="review-panel"]');e.length&&this._niceReplaceNodeContents(e,"",""),a(document).trigger("finish-loading-user"),window.M.util.js_complete("mod-assign-loading-user")}}.bind(this))}.bind(this)).fail(b.exception))},h}); \ No newline at end of file +define(["jquery","core/notification","core/templates","core/fragment","core/ajax","core/str","mod_assign/grading_form_change_checker","mod_assign/grading_events"],function(a,b,c,d,e,f,g,h){var i=function(b){this._regionSelector=b,this._region=a(b),this._userCache=[],this.registerEventListeners()};return i.prototype._regionSelector=null,i.prototype._lastUserId=0,i.prototype._lastAttemptNumber=-1,i.prototype._region=null,i.prototype._niceReplaceNodeContents=function(b,d,e){var f=a.Deferred();return b.fadeOut("fast",function(){c.replaceNodeContents(b,d,e),b.fadeIn("fast",function(){f.resolve()})}),f.promise()},i.prototype._saveFormState=function(){"undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave();var b=a('[data-region="grading-actions-form"] [name="sendstudentnotifications"]').val();a('.gradeform [name="sendstudentnotifications"]').val(b)},i.prototype._submitForm=function(c,d){var f=a(this._region.find("form.gradeform"));a('[data-region="overlay"]').show(),f.trigger("save-form-state");var g=f.serialize(),h=this._region.attr("data-assignmentid");e.call([{methodname:"mod_assign_submit_grading_form",args:{assignmentid:h,userid:this._lastUserId,jsonformdata:JSON.stringify(g)},done:this._handleFormSubmissionResponse.bind(this,g,d),fail:b.exception}])},i.prototype._handleFormSubmissionResponse=function(c,d,e){"undefined"==typeof d&&(d=this._lastUserId),e.length?a(document).trigger("reset",[this._lastUserId,c]):(f.get_strings([{key:"changessaved",component:"core"},{key:"gradechangessaveddetail",component:"mod_assign"}]).done(function(a){b.alert(a[0],a[1])}).fail(b.exception),d==this._lastUserId?a(document).trigger("reset",d):a(document).trigger("user-changed",d)),a('[data-region="overlay"]').hide()},i.prototype._resetForm=function(b,c,d){var e=a.Event("custom");"undefined"==typeof c&&(c=this._lastUserId),this._lastUserId=0,this._refreshGradingPanel(e,c,d)},i.prototype._chooseAttempt=function(c){var d=a(c.target),e=d.data("submissions"),g=a(document.getElementById(e)),h=g.clone(),i=h.wrap(a("")).html();f.get_strings([{key:"viewadifferentattempt",component:"mod_assign"},{key:"view",component:"core"},{key:"cancel",component:"core"}]).done(function(c){b.confirm(c[0],i,c[1],c[2],function(){var b=a("input:radio[name='select-attemptnumber']:checked").val();this._refreshGradingPanel(null,this._lastUserId,"",b)}.bind(this))}.bind(this)).fail(b.exception)},i.prototype._addPopoutButtons=function(d){var e=a(d);c.render("mod_assign/popout_button",{}).done(function(a){e.find(".fitem_ffilemanager .fitemtitle").append(a),e.find(".fitem_feditor .fitemtitle").append(a),e.find(".fitem_f .fitemtitle").append(a),e.on("click",'[data-region="popout-button"]',this._togglePopout.bind(this))}.bind(this)).fail(b.exception)},i.prototype._togglePopout=function(b){b.preventDefault();var c=a(b.target).closest(".fitem");c.hasClass("popout")?a(".popout").removeClass("popout"):(a(".popout").removeClass("popout"),c.addClass("popout"),c.addClass("moodle-has-zindex"))},i.prototype._refreshGradingPanel=function(e,f,h,i){var j=this._region.attr("data-contextid");"undefined"==typeof h&&(h=""),"undefined"==typeof i&&(i=-1),(this._lastUserId!=f||this._lastAttemptNumber!=i||""!==h)&&(this._lastUserId=f,this._lastAttemptNumber=i,a(document).trigger("start-loading-user"),window.M.util.js_pending("mod-assign-loading-user"),c.render("mod_assign/loading",{}).done(function(c,e){this._niceReplaceNodeContents(this._region,c,e).done(function(){if(f>0){this._region.show();var c={userid:f,attemptnumber:i,jsonformdata:JSON.stringify(h)};d.loadFragment("mod_assign","gradingpanel",j,c).done(function(c,d){this._niceReplaceNodeContents(this._region,c,d).done(function(){g.saveFormState('[data-region="grade-panel"] .gradeform'),a('[data-region="attempt-chooser"]').on("click",this._chooseAttempt.bind(this)),this._addPopoutButtons('[data-region="grade-panel"] .gradeform'),a(document).trigger("finish-loading-user"),window.M.util.js_complete("mod-assign-loading-user")}.bind(this)).fail(b.exception)}.bind(this)).fail(b.exception)}else{this._region.hide();var e=a('[data-region="review-panel"]');e.length&&this._niceReplaceNodeContents(e,"",""),a(document).trigger("finish-loading-user"),window.M.util.js_complete("mod-assign-loading-user")}}.bind(this))}.bind(this)).fail(b.exception))},i.prototype.getPanelElement=function(){return a('[data-region="grade-panel"]')},i.prototype.collapsePanel=function(){this.getPanelElement().addClass("collapsed")},i.prototype.expandPanel=function(){this.getPanelElement().removeClass("collapsed")},i.prototype.registerEventListeners=function(){var b=a(document);b.on("user-changed",this._refreshGradingPanel.bind(this)),b.on("save-changes",this._submitForm.bind(this)),b.on("reset",this._resetForm.bind(this)),b.on("save-form-state",this._saveFormState.bind(this)),b.on(h.COLLAPSE_GRADE_PANEL,function(){this.collapsePanel()}.bind(this)),b.on(h.COLLAPSE_REVIEW_PANEL,function(){this.expandPanel()}.bind(this)),b.on(h.EXPAND_GRADE_PANEL,function(){this.expandPanel()}.bind(this))},i}); \ No newline at end of file diff --git a/mod/assign/amd/build/grading_review_panel.min.js b/mod/assign/amd/build/grading_review_panel.min.js index 084992e7338..8ad6a6ebb4d 100644 --- a/mod/assign/amd/build/grading_review_panel.min.js +++ b/mod/assign/amd/build/grading_review_panel.min.js @@ -1 +1 @@ -define(["jquery"],function(a){var b=function(){this._region=a('[data-region="review-panel"]')};return b.prototype._region=null,b.prototype.getReviewPanel=function(a){var b=this._region.data("panel-owner");return"undefined"==typeof b&&this._region.data("review-panel-plugin",a),this._region.data("review-panel-plugin")==a?this._region[0]:!1},b}); \ No newline at end of file +define(["jquery","mod_assign/grading_events"],function(a,b){var c=function(){this._region=a('[data-region="review-panel-content"]'),this.registerEventListeners()};return c.prototype._region=null,c.prototype.getReviewPanel=function(a){var b=this._region.data("panel-owner");return"undefined"==typeof b&&this._region.data("review-panel-plugin",a),this._region.data("review-panel-plugin")==a?this._region[0]:!1},c.prototype.getTogglePanelButton=function(){return this.getPanelElement().find('[data-region="review-panel-toggle"]')},c.prototype.getPanelElement=function(){return a('[data-region="review-panel"]')},c.prototype.getPanelContentElement=function(){return a('[data-region="review-panel-content"]')},c.prototype.togglePanel=function(){this.getPanelElement().hasClass("collapsed")?a(document).trigger(b.EXPAND_REVIEW_PANEL):a(document).trigger(b.COLLAPSE_REVIEW_PANEL)},c.prototype.collapsePanel=function(){this.getPanelElement().addClass("collapsed").removeClass("grade-panel-collapsed"),this.getPanelContentElement().attr("aria-hidden",!0)},c.prototype.expandPanel=function(){this.getPanelElement().removeClass("collapsed"),this.getPanelContentElement().removeAttr("aria-hidden")},c.prototype.registerEventListeners=function(){var c=this.getTogglePanelButton();c.click(function(a){this.togglePanel(),a.preventDefault()}.bind(this)),c.keydown(function(a){a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(13===a.keyCode||32===a.keyCode)&&(this.togglePanel(),a.preventDefault())}.bind(this));var d=a(document);d.on(b.COLLAPSE_REVIEW_PANEL,function(){this.collapsePanel()}.bind(this)),d.on(b.COLLAPSE_GRADE_PANEL,function(){this.expandPanel(),this.getPanelElement().addClass("grade-panel-collapsed")}.bind(this)),d.on(b.EXPAND_REVIEW_PANEL,function(){this.expandPanel()}.bind(this)),d.on(b.EXPAND_GRADE_PANEL,function(){this.getPanelElement().removeClass("grade-panel-collapsed")}.bind(this))},c}); \ No newline at end of file diff --git a/mod/assign/amd/src/grading_actions.js b/mod/assign/amd/src/grading_actions.js index 753db518837..692c77d3ec5 100644 --- a/mod/assign/amd/src/grading_actions.js +++ b/mod/assign/amd/src/grading_actions.js @@ -23,7 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.1 */ -define(['jquery'], function($) { +define(['jquery', 'mod_assign/grading_events'], function($, GradingEvents) { /** * GradingActions class. @@ -35,13 +35,7 @@ define(['jquery'], function($) { this._regionSelector = selector; this._region = $(selector); - $(document).on('user-changed', this._showActionsForm.bind(this)); - - this._region.find('[name="savechanges"]').on('click', this._trigger.bind(this, 'save-changes')); - this._region.find('[name="resetbutton"]').on('click', this._trigger.bind(this, 'reset')); - this._region.find('form').on('submit', function(e) { - e.preventDefault(); - }); + this.registerEventListeners(); }; /** @type {String} Selector for the page region containing the user navigation. */ @@ -86,5 +80,165 @@ define(['jquery'], function($) { $(document).trigger(action); }; + /** + * Get the review panel element. + * + * @method getReviewPanelElement + * @return {jQuery} + */ + GradingActions.prototype.getReviewPanelElement = function() { + return $('[data-region="review-panel"]'); + }; + + /** + * Check if the page has a review panel. + * + * @method hasReviewPanelElement + * @return {bool} + */ + GradingActions.prototype.hasReviewPanelElement = function() { + return this.getReviewPanelElement().length > 0; + }; + + /** + * Get the collapse grade panel button. + * + * @method getCollapseGradePanelButton + * @return {jQuery} + */ + GradingActions.prototype.getCollapseGradePanelButton = function() { + return $('[data-region="grade-actions"] .collapse-grade-panel'); + }; + + /** + * Get the collapse review panel button. + * + * @method getCollapseReviewPanelButton + * @return {jQuery} + */ + GradingActions.prototype.getCollapseReviewPanelButton = function() { + return $('[data-region="grade-actions"] .collapse-review-panel'); + }; + + /** + * Get the expand all panels button. + * + * @method getExpandAllPanelsButton + * @return {jQuery} + */ + GradingActions.prototype.getExpandAllPanelsButton = function() { + return $('[data-region="grade-actions"] .collapse-none'); + }; + + /** + * Remove the active state from all layout buttons. + * + * @method resetLayoutButtons + */ + GradingActions.prototype.resetLayoutButtons = function() { + this.getCollapseGradePanelButton().removeClass('active'); + this.getCollapseReviewPanelButton().removeClass('active'); + this.getExpandAllPanelsButton().removeClass('active'); + }; + + /** + * Hide the review panel. + * + * @method collapseReviewPanel + */ + GradingActions.prototype.collapseReviewPanel = function() { + $(document).trigger(GradingEvents.COLLAPSE_REVIEW_PANEL); + $(document).trigger(GradingEvents.EXPAND_GRADE_PANEL); + this.resetLayoutButtons(); + this.getCollapseReviewPanelButton().addClass('active'); + }; + + /** + * Show/Hide the grade panel. + * + * @method collapseGradePanel + */ + GradingActions.prototype.collapseGradePanel = function() { + $(document).trigger(GradingEvents.COLLAPSE_GRADE_PANEL); + $(document).trigger(GradingEvents.EXPAND_REVIEW_PANEL); + this.resetLayoutButtons(); + this.getCollapseGradePanelButton().addClass('active'); + }; + + /** + * Return the layout to default. + * + * @method expandAllPanels + */ + GradingActions.prototype.expandAllPanels = function() { + $(document).trigger(GradingEvents.EXPAND_GRADE_PANEL); + $(document).trigger(GradingEvents.EXPAND_REVIEW_PANEL); + this.resetLayoutButtons(); + this.getExpandAllPanelsButton().addClass('active'); + }; + + /** + * Register event listeners for the grade panel. + * + * @method registerEventListeners + */ + GradingActions.prototype.registerEventListeners = function() { + // Don't need layout controls if there is no review panel. + if (this.hasReviewPanelElement()) { + var collapseReviewPanelButton = this.getCollapseReviewPanelButton(); + collapseReviewPanelButton.click(function(e) { + this.collapseReviewPanel(); + e.preventDefault(); + }.bind(this)); + + collapseReviewPanelButton.keydown(function(e) { + if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { + if (e.keyCode === 13 || e.keyCode === 32) { + this.collapseReviewPanel(); + e.preventDefault(); + } + } + }.bind(this)); + + var collapseGradePanelButton = this.getCollapseGradePanelButton(); + collapseGradePanelButton.click(function(e) { + this.collapseGradePanel(); + e.preventDefault(); + }.bind(this)); + + collapseGradePanelButton.keydown(function(e) { + if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { + if (e.keyCode === 13 || e.keyCode === 32) { + this.collapseGradePanel(); + e.preventDefault(); + } + } + }.bind(this)); + + var expandAllPanelsButton = this.getExpandAllPanelsButton(); + expandAllPanelsButton.click(function(e) { + this.expandAllPanels(); + e.preventDefault(); + }.bind(this)); + + expandAllPanelsButton.keydown(function(e) { + if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { + if (e.keyCode === 13 || e.keyCode === 32) { + this.expandAllPanels(); + e.preventDefault(); + } + } + }.bind(this)); + } + + $(document).on('user-changed', this._showActionsForm.bind(this)); + + this._region.find('[name="savechanges"]').on('click', this._trigger.bind(this, 'save-changes')); + this._region.find('[name="resetbutton"]').on('click', this._trigger.bind(this, 'reset')); + this._region.find('form').on('submit', function(e) { + e.preventDefault(); + }); + }; + return GradingActions; }); diff --git a/mod/assign/amd/src/grading_events.js b/mod/assign/amd/src/grading_events.js new file mode 100644 index 00000000000..a2336a8508d --- /dev/null +++ b/mod/assign/amd/src/grading_events.js @@ -0,0 +1,32 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Javascript controller for the "Actions" panel at the bottom of the page. + * + * @module mod_assign/grading_events + * @package mod_assign + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since 3.1 + */ +define(function() { + return { + COLLAPSE_REVIEW_PANEL: 'grading:collapse-review-panel', + EXPAND_REVIEW_PANEL: 'grading:expand-review-panel', + COLLAPSE_GRADE_PANEL: 'grading:collapse-grade-panel', + EXPAND_GRADE_PANEL: 'grading:expand-grade-panel', + }; +}); diff --git a/mod/assign/amd/src/grading_panel.js b/mod/assign/amd/src/grading_panel.js index 818d263e7c9..9d9e328fcf5 100644 --- a/mod/assign/amd/src/grading_panel.js +++ b/mod/assign/amd/src/grading_panel.js @@ -24,8 +24,9 @@ * @since 3.1 */ define(['jquery', 'core/notification', 'core/templates', 'core/fragment', - 'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker'], - function($, notification, templates, fragment, ajax, str, checker) { + 'core/ajax', 'core/str', 'mod_assign/grading_form_change_checker', + 'mod_assign/grading_events'], + function($, notification, templates, fragment, ajax, str, checker, GradingEvents) { /** * GradingPanel class. @@ -38,11 +39,7 @@ define(['jquery', 'core/notification', 'core/templates', 'core/fragment', this._region = $(selector); this._userCache = []; - $(document).on('user-changed', this._refreshGradingPanel.bind(this)); - $(document).on('save-changes', this._submitForm.bind(this)); - $(document).on('reset', this._resetForm.bind(this)); - - $(document).on('save-form-state', this._saveFormState.bind(this)); + this.registerEventListeners(); }; /** @type {String} Selector for the page region containing the user navigation. */ @@ -307,5 +304,61 @@ define(['jquery', 'core/notification', 'core/templates', 'core/fragment', }.bind(this)).fail(notification.exception); }; + /** + * Get the grade panel element. + * + * @method getPanelElement + * @return {jQuery} + */ + GradingPanel.prototype.getPanelElement = function() { + return $('[data-region="grade-panel"]'); + }; + + /** + * Hide the grade panel. + * + * @method collapsePanel + */ + GradingPanel.prototype.collapsePanel = function() { + this.getPanelElement().addClass('collapsed'); + }; + + /** + * Show the grade panel. + * + * @method expandPanel + */ + GradingPanel.prototype.expandPanel = function() { + this.getPanelElement().removeClass('collapsed'); + }; + + /** + * Register event listeners for the grade panel. + * + * @method registerEventListeners + */ + GradingPanel.prototype.registerEventListeners = function() { + var docElement = $(document); + + docElement.on('user-changed', this._refreshGradingPanel.bind(this)); + docElement.on('save-changes', this._submitForm.bind(this)); + docElement.on('reset', this._resetForm.bind(this)); + + docElement.on('save-form-state', this._saveFormState.bind(this)); + + docElement.on(GradingEvents.COLLAPSE_GRADE_PANEL, function() { + this.collapsePanel(); + }.bind(this)); + + // We should expand if the review panel is collapsed. + docElement.on(GradingEvents.COLLAPSE_REVIEW_PANEL, function() { + this.expandPanel(); + }.bind(this)); + + docElement.on(GradingEvents.EXPAND_GRADE_PANEL, function() { + this.expandPanel(); + }.bind(this)); + }; + return GradingPanel; }); diff --git a/mod/assign/amd/src/grading_review_panel.js b/mod/assign/amd/src/grading_review_panel.js index fffe2e41255..39a02d2f220 100644 --- a/mod/assign/amd/src/grading_review_panel.js +++ b/mod/assign/amd/src/grading_review_panel.js @@ -23,7 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.1 */ -define(['jquery'], function($) { +define(['jquery', 'mod_assign/grading_events'], function($, GradingEvents) { /** * GradingReviewPanel class. @@ -32,7 +32,8 @@ define(['jquery'], function($) { * @param {String} selector The selector for the page region containing the user navigation. */ var GradingReviewPanel = function() { - this._region = $('[data-region="review-panel"]'); + this._region = $('[data-region="review-panel-content"]'); + this.registerEventListeners(); }; /** @type {JQuery} JQuery node for the page region containing the user navigation. */ @@ -58,5 +59,109 @@ define(['jquery'], function($) { return false; }; + /** + * Get the toggle review panel button. + * + * @method getTogglePanelButton + * @return {jQuery} + */ + GradingReviewPanel.prototype.getTogglePanelButton = function() { + return this.getPanelElement().find('[data-region="review-panel-toggle"]'); + }; + + /** + * Get the review panel element. + * + * @method getPanelElement + * @return {jQuery} + */ + GradingReviewPanel.prototype.getPanelElement = function() { + return $('[data-region="review-panel"]'); + }; + + /** + * Get the review panel content element. + * + * @method getPanelContentElement + * @return {jQuery} + */ + GradingReviewPanel.prototype.getPanelContentElement = function() { + return $('[data-region="review-panel-content"]'); + }; + + /** + * Show/Hide the review panel. + * + * @method togglePanel + */ + GradingReviewPanel.prototype.togglePanel = function() { + if (this.getPanelElement().hasClass('collapsed')) { + $(document).trigger(GradingEvents.EXPAND_REVIEW_PANEL); + } else { + $(document).trigger(GradingEvents.COLLAPSE_REVIEW_PANEL); + } + }; + + /** + * Hide the review panel. + * + * @method collapsePanel + */ + GradingReviewPanel.prototype.collapsePanel = function() { + this.getPanelElement().addClass('collapsed').removeClass('grade-panel-collapsed'); + this.getPanelContentElement().attr('aria-hidden', true); + }; + + /** + * Show the review panel. + * + * @method expandPanel + */ + GradingReviewPanel.prototype.expandPanel = function() { + this.getPanelElement().removeClass('collapsed'); + this.getPanelContentElement().removeAttr('aria-hidden'); + }; + + /** + * Register event listeners for the review panel. + * + * @method registerEventListeners + */ + GradingReviewPanel.prototype.registerEventListeners = function() { + var toggleReviewPanelButton = this.getTogglePanelButton(); + toggleReviewPanelButton.click(function(e) { + this.togglePanel(); + e.preventDefault(); + }.bind(this)); + + toggleReviewPanelButton.keydown(function(e) { + if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { + if (e.keyCode === 13 || e.keyCode === 32) { + this.togglePanel(); + e.preventDefault(); + } + } + }.bind(this)); + + var docElement = $(document); + docElement.on(GradingEvents.COLLAPSE_REVIEW_PANEL, function() { + this.collapsePanel(); + }.bind(this)); + + // Need special styling when grade panel is collapsed. + docElement.on(GradingEvents.COLLAPSE_GRADE_PANEL, function() { + this.expandPanel(); + this.getPanelElement().addClass('grade-panel-collapsed'); + }.bind(this)); + + docElement.on(GradingEvents.EXPAND_REVIEW_PANEL, function() { + this.expandPanel(); + }.bind(this)); + + docElement.on(GradingEvents.EXPAND_GRADE_PANEL, function() { + this.getPanelElement().removeClass('grade-panel-collapsed'); + }.bind(this)); + }; + return GradingReviewPanel; }); diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php index 419e7c7c387..637b71e522a 100644 --- a/mod/assign/lang/en/assign.php +++ b/mod/assign/lang/en/assign.php @@ -108,6 +108,9 @@ $string['changegradewarning'] = 'This assignment has graded submissions and chan $string['choosegradingaction'] = 'Grading action'; $string['choosemarker'] = 'Choose...'; $string['chooseoperation'] = 'Choose operation'; +$string['clickexpandreviewpanel'] = 'Click to expand review panel'; +$string['collapsegradepanel'] = 'Collapse grade panel'; +$string['collapsereviewpanel'] = 'Collapse review panel'; $string['comment'] = 'Comment'; $string['completionsubmit'] = 'Student must submit to this activity to complete it'; $string['conversionexception'] = 'Could not convert assignment. Exception was: {$a}.'; @@ -127,6 +130,7 @@ $string['cutoffdatecolon'] = 'Cut-off date: {$a}'; $string['cutoffdate_help'] = 'If set, the assignment will not accept submissions after this date without an extension.'; $string['cutoffdatevalidation'] = 'The cut-off date cannot be earlier than the due date.'; $string['cutoffdatefromdatevalidation'] = 'Cut-off date must be after the allow submissions from date.'; +$string['defaultlayout'] = 'Restore default layout'; $string['defaultsettings'] = 'Default assignment settings'; $string['defaultsettings_help'] = 'These settings define the defaults for all new assignments.'; $string['defaultteam'] = 'Default group'; @@ -174,6 +178,7 @@ $string['eventsubmissionunlocked'] = 'The submissions have been unlocked for a u $string['eventsubmissionupdated'] = 'Submission updated.'; $string['eventsubmissionviewed'] = 'Submission viewed.'; $string['eventworkflowstateupdated'] = 'The state of the workflow has been updated.'; +$string['expandreviewpanel'] = 'Expand review panel'; $string['extensionduedate'] = 'Extension due date'; $string['extensionnotafterduedate'] = 'Extension date must be after the due date'; $string['extensionnotafterfromdate'] = 'Extension date must be after the allow submissions from date'; diff --git a/mod/assign/styles.css b/mod/assign/styles.css index c3a85051698..c838143e575 100644 --- a/mod/assign/styles.css +++ b/mod/assign/styles.css @@ -457,13 +457,78 @@ top: 85px; bottom: 60px; left: 0; - width: 70%; + right: 30%; + width: auto; box-sizing: border-box; + -webkit-transition: right 0.5s, left 0.5s; + -moz-transition: right 0.5s, left 0.5s; + transition: right 0.5s, left 0.5s; +} + +.path-mod-assign [data-region="review-panel"].grade-panel-collapsed { + right: 30px; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] { + display: none; + height: 30px; + width: 30px; + position: absolute; + top: 0; + right: 0; + left: auto; + box-sizing: border-box; + border-radius: 0 0 0 4px; + border: 1px solid #cccccc; + border-top: none; + background-color: #fff; + z-index: 99999; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon, +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon { + width: 100%; + height: 100%; + text-align: center; + line-height: 30px; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon .toggle-text, +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon .toggle-text { + visibility: hidden; + opacity: 0; + height: 0; + overflow: hidden; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] img { + height: 100%; + float: right; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon { + display: none; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon { + display: block; +} + +.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon.full-width { + display: none; } .path-mod-assign [data-region="review-panel"] .pageheader { border-right: 1px solid #ddd; } +.path-mod-assign [data-region="review-panel"] + [data-region="grade-panel"] [data-region="grade"] { + margin-left: auto; + margin-right: auto; + max-width: 100%; + -webkit-transition: max-width 0.5s; + -moz-transition: max-width 0.5s; + transition: max-width 0.5s; +} .path-mod-assign [data-region="review-panel"] .drawingregion { left: 0; @@ -471,16 +536,41 @@ border-color: #ddd; } -.path-mod-assign [data-region="grade-panel"].fullwidth { - position: absolute; - top: 7em; - left: 0; - right: 0; - width: 99%; - overflow: auto; - bottom: 7em; +.path-mod-assign [data-region="review-panel"].collapsed { + left: calc(30px - 70%); + right: calc(100% - 30px); + -webkit-transition: right 0.5s, left 0.5s; + -moz-transition: right 0.5s, left 0.5s; + transition: right 0.5s, left 0.5s; } +.path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-content"] { + visibility: hidden; + -webkit-transition: visibility 0s 0.5s; + -moz-transition: visibility 0s 0.5s; + transition: visibility 0s 0.5s; +} + +.path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] .expand-icon { + display: block; +} + +.path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] .collapse-icon { + display: none; +} + +.path-mod-assign [data-region="review-panel"].collapsed + [data-region="grade-panel"] { + position: absolute; + left: 30px; + right: 0; + width: calc(100% - 30px); + overflow: auto; + -webkit-transition: width 0.5s, right 0.5s, left 0.5s; + -moz-transition: width 0.5s, right 0.5s, left 0.5s; + transition: width 0.5s, right 0.5s, left 0.5s; +} + +.path-mod-assign [data-region="review-panel"].collapsed + [data-region="grade-panel"] [data-region="grade"], .path-mod-assign [data-region="grade-panel"].fullwidth [data-region="grade"] { max-width: 800px; margin-left: auto; @@ -492,12 +582,31 @@ top: 85px; bottom: 60px; right: 0; + left: 70%; width: 30%; overflow: auto; box-sizing: border-box; background-color: #f5f5f5; padding: 15px; padding-top: 0px; + -webkit-transition: width 0.5s, right 0.5s, left 0.5s; + -moz-transition: width 0.5s, right 0.5s, left 0.5s; + transition: width 0.5s, right 0.5s, left 0.5s; +} + +.path-mod-assign [data-region="grade-panel"].collapsed { + left: calc(100% - 30px); + right: calc(30px - 100%); + visibility: hidden; + -webkit-transition: right 0.5s, left 0.5s, visibility 0s 0.5s; + -moz-transition: right 0.5s, left 0.5s, visibility 0s 0.5s; + transition: right 0.5s, left 0.5s, visibility 0s 0.5s; +} + +.path-mod-assign [data-region="grade-panel"].fullwidth { + left: 0; + width: 100%; + overflow: auto; } .path-mod-assign [data-region="grade-panel"] h3 { @@ -853,6 +962,17 @@ height: 60px; } +.path-mod-assign [data-region="grade-actions-panel"] [data-region="grade-actions"] .collapse-buttons { + position: absolute; + top: 0; + left: auto; + right: 15px; + margin: 0; + height: 100%; + line-height: 60px; + direction: ltr; +} + .path-mod-assign [data-region="grade-actions"] { padding: 1em; text-align: center; @@ -890,18 +1010,26 @@ .path-mod-assign .page-context-header .page-header-headings { margin-top: 13px; } + .path-mod-assign [data-region="grade-actions-panel"] [data-region="grade-actions"] .collapse-buttons { + display: none; + } .path-mod-assign [data-region="grading-navigation-panel"], .path-mod-assign [data-region="review-panel"], .path-mod-assign [data-region="grade-panel"], + .path-mod-assign [data-region="review-panel"].collapsed + [data-region="grade-panel"], .path-mod-assign [data-region="grade-actions-panel"] { position: inherit; width: 100%; top: 0; left: 0; + right: auto; overflow: auto; height: auto; margin-bottom: 1em; } + .path-mod-assign [data-region="grade-panel"].collapsed { + visibility: visible; + } .path-mod-assign [data-region="grading-navigation"] { padding: 0; text-align: center; @@ -912,8 +1040,86 @@ .path-mod-assign [data-region="grade-panel"] [data-region="popout-button"] { display: none; } + .path-mod-assign [data-region="review-panel"] { + position: relative; + max-height: 2000px; + -webkit-transition: max-height 0.25s linear; + -moz-transition: max-height 0.25s linear; + transition: max-height 0.25s linear; + } .path-mod-assign [data-region="review-panel"] .pageheader { border-right: none; + padding-right: 20px; + padding-left: 40px; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] { + display: block; + height: 20px; + width: 20px; + position: absolute; + top: 0; + left: 0; + right: auto; + box-sizing: border-box; + border: 1px solid #cccccc; + border-radius: 0 0 4px 0; + background-color: #fff; + z-index: 99999; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon, + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon { + width: 100%; + height: 100%; + text-align: center; + line-height: 30px; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .ltr-icon, + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .rtl-icon { + height: 100%; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .ltr-icon { + float: left; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .rtl-icon { + float: right; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon .toggle-text, + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon .toggle-text { + line-height: 20px; + visibility: visible; + opacity: 1; + height: auto; + -webkit-transition: visibility 0s 0.25s, opacity 0s 0.25s; + -moz-transition: visibility 0s 0.25s, opacity 0s 0.25s; + transition: visibility 0s 0.25s, opacity 0s 0.25s; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon .rtl-icon { + display: none; + } + .path-mod-assign [data-region="review-panel"].collapsed { + max-height: 20px; + top: 0; + left: 0; + overflow: hidden; + -webkit-transition: max-height 0.25s linear; + -moz-transition: max-height 0.25s linear; + transition: max-height 0.25s linear; + } + .path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] { + width: 100%; + border-radius: 0 0 0 0; + -webkit-transition: all 0s 0.25s; + -moz-transition: all 0s 0.25s; + transition: all 0s 0.25s; + } + .path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] img { + height: 100%; + } + .path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .collapse-icon { + display: block; + } + .path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] .collapse-icon { + display: none; } .path-mod-assign.pagelayout-popup { overflow: inherit; @@ -928,6 +1134,31 @@ float: none; margin: 0 auto 10px; } + .dir-rtl.path-mod-assign [data-region="review-panel"] .pageheader { + padding-right: 40px; + padding-left: 20px; + } + .dir-rtl.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] { + left: auto; + right: 0; + border-radius: 0 0 0 4px; + } + .dir-rtl.path-mod-assign [data-region="review-panel"].collapsed { + right: 0; + left: auto; + } + .dir-rtl.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon .ltr-icon { + display: none; + } + .dir-rtl.path-mod-assign [data-region="review-panel"] [data-region="review-panel-toggle"] .expand-icon .rtl-icon { + display: block; + } + .dir-rtl.path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] .collapse-icon { + display: none; + } + .dir-rtl.path-mod-assign [data-region="review-panel"].collapsed [data-region="review-panel-toggle"] .expand-icon { + display: block; + } } /** Start of CSS to make forms vertical in the grading panel (taken from theme/bootstrapbase/less/moodle/forms.less). */ diff --git a/mod/assign/templates/grading_actions.mustache b/mod/assign/templates/grading_actions.mustache index ab4e365dfb2..28c89f1e0fd 100644 --- a/mod/assign/templates/grading_actions.mustache +++ b/mod/assign/templates/grading_actions.mustache @@ -39,6 +39,15 @@ +{{#showreview}} +
+
+ + + +
+
+{{/showreview}} {{#js}} require(['mod_assign/grading_actions'], function(GradingActions) { new GradingActions('[data-region="grade-actions"]'); diff --git a/mod/assign/templates/grading_app.mustache b/mod/assign/templates/grading_app.mustache index 62221f61551..23f192be6be 100644 --- a/mod/assign/templates/grading_app.mustache +++ b/mod/assign/templates/grading_app.mustache @@ -34,18 +34,28 @@
{{> mod_assign/grading_navigation }}
+{{#showreview}} +
+ +
{{#pix}} t/expanded, core, {{#str}} collapsereviewpanel, mod_assign {{/str}} {{/pix}}
+
+
{{#pix}} t/collapsed, core, {{#str}} expandreviewpanel, mod_assign {{/str}} {{/pix}}
+
{{#pix}} t/collapsed_rtl, core, {{#str}} expandreviewpanel, mod_assign {{/str}} {{/pix}}
+
{{#str}} clickexpandreviewpanel, mod_assign {{/str}}
+
+
+
+
+ {{> mod_assign/review_panel }} +
+
+
+{{/showreview}}
{{> mod_assign/grading_panel }}
-{{#showreview}} -
-
-{{> mod_assign/review_panel }} -
-
-{{/showreview}}
{{> mod_assign/grading_actions }}