When SpeedGrading an assignment, initialize points to rubric's max pts

Jump to solution
pxo4
Community Participant

Hello, All:

This is the first Tampermonkey script for me.

In Canvas, after manually doing this:

  1. View the assignment
  2. Click on SpeedGrader
  3. Click on View Rubric

I want to then click a button, and automatically populate each of the points with the maximum in the rubric.

So, I want to go from this:

298332_pastedImage_5.png

to this:

298334_pastedImage_7.png

Here's what I'm attempting:

Edit: Well, all my nicely-aligned code got collapsed into one.  Here's the full context:  https://pastebin.com/D52jRfZ7

(function() { 'use strict'; var D = document; function initialize() { var btn = create_button('Default Points', set_values); var submission_details = D.getElementById('submission_details'); submission_details.appendChild(btn); } function create_button(text, handler) { var btn = D.createElement('button'); btn.type = 'button'; btn.id = 'pjo_default_points'; btn.classList.add('btn', 'btn-small'); btn.appendChild(D.createTextNode(text)); btn.addEventListener('click', handler, false); return btn; } function set_values(e) { var fields=D.getElementById('rubric_full').querySelectorAll('input[type=text]'); for (var i=0; i<fields.length; i++) { var pts = fields[i]; pts.value = i+1; // just a test value for now pts.dispatchEvent(new Event('change', { 'bubbles' : true })); } }

It does populate the values on the screen.  (Note that I'm just using the index+1 for the value.  Later I plan on more scraping to get the real value.)

298344_pastedImage_9.png

But it's only superficial, because the score remains at 0:

298345_pastedImage_10.png

And if I hit Save, all the scores change to "--"

298346_pastedImage_13.png

I'm not sure what I'm doing wrong.

Any thoughts?

Thanks,

Phil

2 Solutions
James
Community Champion

 @pxo4 ,

I've spent more time on this than I want to admit -- even though I've not been posting things. I've fruitlessly tried for hours to make this work when I papers that needed graded. I tried change, blur, input, keypress, keyup, keydown, and anything else I could think of. None of them worked. None of them would trigger the event.  I even tried things with the isTrusted and it didn't make any difference. Typing the score manually was the only thing I could get to work.

Tonight, I finally got caught up on all my grading and came into the community to catch up. Spotting your message made me try one more time. After about 10 minutes, I gave up and took a different approach. Rather than trying to figure out how to make it work, I focused on the "what changed" portion.

The what changed thing threw me in my previous testing. There was a file with a really enticing name called rubric_assessment.js that was being loaded. I kept on adding break points to it and couldn't get it to fire when I changed stuff. I thought that was just because it was getting loaded before I opened the rubric and enabled the breakpoint, but it turns out that it's not being anymore. It was a red herring.

What changed is that Canvas is using React on the rubrics now. Tonight, I changed my search to include triggering change events in React and came across this post on Stack Overflow: What is the best way to trigger onchange event in react js. That one hit was all I needed (and following some of the links within it) to find the issue and the solution.

Following down that path lead me to a solution that will work. Here it is, line breaking was added to make it display nicely in the Community.

var nativeInputValueSetter =
  Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
document.getElementById('rubric_full')
  .querySelectorAll('tbody.criterions input[type=text]')
  .forEach(e => {
    var points = 2;
    nativeInputValueSetter.call(e, points);
    e.dispatchEvent(new Event('change', { 'bubbles': true }));
  });‍‍‍‍‍‍‍‍‍‍‍‍‍

The points = 2 line is just an example. Modifying it slightly to fetch the maximum points from the ENV.rubric.criteria variable, we get this code snippet.

const nativeInputValueSetter = 
  Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
let i = 0;
document.getElementById('rubric_full')
  .querySelectorAll('tbody.criterions input[type=text]')
  .forEach(e => {
    let points = ENV.rubric.criteria[i].points;
    nativeInputValueSetter.call(e, points);
    e.dispatchEvent(new Event('change', { 'bubbles': true }));
    i++;
  });

I did not do any error checking, so make sure that you use the tbody as part of the query selector otherwise you will get more inputs than criteria. I get 7 inputs without it but my rubric only has 4.

I checked this with Firefox and Chrome with both free-form comments and ratings that you can click.

Finally, just in case you were curious, the bubbles does need to be there or it doesn't fire.

This has been a wonderful exercise. I have a feeling that it will need to happen a lot more as Canvas moves more and more things to React.

Here are some screen shots to show what's happening. Although this does show the ratings, I have tested it without them.

Before Shot

298506_pastedImage_1.png

After shot

298507_pastedImage_2.png

After closing Rubric

298523_pastedImage_3.png

View solution in original post

James
Community Champion

@pxo4 , @fcurry1 

I revisited this after almost 3.5 years and wrapped it inside a userscript so that it automatically runs. This may duplicate some of the work that Phil had done, but I don't know where his script is and other people are asking for it. The code snippet I gave above doesn't work anymore unless you remove the .criterions from the selector. Still, it indiscriminately overwrote any existing point values and the process was not automatic.

It adds a "Max" button after the "Pts" in the rubric header. I had to widen the rubric pane to see it, but I thought that was the best place for the button since it applied to the points.

When you click the "Max" button, it will go through any rubric criteria that does not have a point value and assign it the maximum point value. This honors any ratings that you have already clicked on instead of setting them to the maximum value (as the code snippet I gave above does).

The two common uses I see are:

  • clicking the Max button at the very beginning and then changing the criteria that do not have the maximum ratings
  • clicking a few ratings and then clicking the Max button to fill in the rest.

I would recommend using it with QuizWiz, which is a script I wrote that adds a button that will save the rubric, advance to the next user, and re-open the rubric

I haven't written a blog post in the Community about it yet, but the code and installation instructions are on the Max Ratings GitHub page.

View solution in original post