Sorting Dashboard Course Cards

James
Community Champion
76
43101

December 8, 2018 - No Longer Needed

Canvas has released their own solution for sorting the dashboard course cards. You should remove this script and use their solution. Things should continue to work until you do, but the effort is being duplicated. Any customization to the sort order will be lost when you remove this script.

I'm leaving the documentation and script out here for institutions that self-host and have not updated to the December 8, 2018, release.

Original Documentation

I've written a script that will allow users to sort their dashboard course cards by dragging and dropping the cards into the proper order.

This seems to have been a popular request that Canvas has repeatedly said will take too much effort to develop.

There are probably others that I'm missing, but that's a quick list.

The script was written as a user script, meant to be used by Greasemonkey with Firefox or Tampermonkey with Chrome or Safari. However, the exact same code can also be used in the custom JavaScript file for an institution.

What it does

The script runs on the dashboard for your Canvas installation. It checks to see if the user has sorted the course cards and arranges them in the order the user has specified.

If there is more than one course card, it allow the course cards to be sorted using a drag and drop capability. When cards are dragged to their new location, the current sort order is automatically saved.

If new courses are added to the favorites through the Courses navigation item, they are placed at the front of the existing course cards. The user will need to move them if they don't want them at the front.

The user's sort order can be removed and the ordering reset to the Canvas default by removing all but one course from the favorites and then loading the dashboard.

Video

The process is so simple and straight forward that coming up with a video that demonstrates what it does was challenging. I managed to stretch it out to 15 seconds.

Installation

As an institution for all users

If you are a Canvas Admin and would like to install this script in your Custom JavaScript file for the entire account, then obtain the source code from the Canvancement site.

The file is called dashcard_sorter.user.js. Normally, the *.user.js notation is reserved for user scripts, but in this case the code will work as either a user script or a custom JavaScript, so rather than create two identical files, I just used the one. You do not need to include the user script metadata (all the lines starting with //) at the top of the file.

Add this code to your existing custom JavaScript and re-upload it to your theme. Then save and apply the theme. I added it to the global JavaScript file as well as the global Mobile JavaScript file, although I'll admit I'm not clear on what the Mobile one does.

Of all the scripts I've written, this is actually the first one that we've installed in our custom JavaScript. It has been tested with the latest versions of Firefox, Chrome, Safari (Mac), and yes, even Internet Explorer and Edge.

As an individual for yourself

If your institution won't install this for all users, you can still use it by installing it yourself. If your institution later installs the script for all users, you will want to remove the version you installed.

Note that you will need to install this script on every browser that you want the course cards sorted.

The quick installation instructions are:

  1. Install a browser add-on: Greasemonkey for Firefox or Tampermonkey for Chrome/Safari.
  2. Install the Dashboard Card Sorter script

If your Canvas site has a custom domain that does not match *.instructure.com, then you will need to modify the // @include line to specify your Canvas installation.

Canvas apps aren't supported

I have tested this in various browsers, including Safari on an iPhone. It has worked in all those browsers that I tested.

However, it did not work within the Canvas iOS app and I can only assume that it will not work in the Android app either, but I don't have access to test it.

I don't know if this can be remedied or if we're just out of luck. I'm happy to hear from someone who is more knowledgeable with the apps and can tell me how to make it work or who can confirm that it never will.

Behinds the scenes (technical -- optional)

The script uses the jQuery sortable method, which enables the drag and drop feature. jQuery is included on each page by Canvas, so no extra libraries were needed. I used the browser's console to quickly add a .sortable() to the dashboard cards as a proof-of-concept before starting the project in earnest. That part was quick and relatively painless.

The first hurdle was waiting until the course cards were ready before acting on them. The course cards are available as an empty shell that is available as soon as the page is loaded, but all of the content of the cards is loaded after the initial load using JavaScript. That makes determining which course is associated with the card impossible until the cards are filled out. I guess that I could know the order of the cards based off the array that is included in the ENV.DASHBOARD_COURSES variable when the page is loaded, but I wasn't sure what else was going on behind the scenes so I decided not to risk manipulating it until Canvas had added the content. I used a MutationObserver to wait until the cards could be associated with a course and then begin the processing.

I've done a lot of work with MutationObservers with other scripts, so this was not as difficult as it seems. You just need to watch for the right thing to happen. It turned out that the first change that was made to the dashboard cards was sufficient to start the process.

A second hurdle was saving the sort order. When I originally contemplated this project, I thought about saving it using the local storage for the browser. That would have worked for people who use the same machine and browser every time, but it would not work for people who move around between computers or change browsers.

The solution to that problem was to use the Canvas User Custom Data API. It stores the preferred sort order within Canvas so that it can follow users from machine to machine and browser to browser. If an institution doesn't install the script in their global JavaScript, the user will still need to load the user script on the machines, but then they won't have to reconfigure it each time.

This was the first time I've used the custom user data, so I had to learn how that works. Here is some advice for those considering it:

  • You need a namespace to separate your applications data from possible conflicts. Canvas recommends a reverse domain name, but I don't have a domain name for my Canvancements, so I just used "canvancement" as the namespace.
  • You also specify a scope, which is a way to have multiple values within your namespace. I chose "/dashboard/order". These are specified near the top of the source code and you are free to modify them to something else.
  • The actual data is stored under the field "data" within the namespace and scope. So, if you're expecting a comma separated list of course IDs, you don't just get that, but you get a JSON object with a property called "data" that contains the comma separated list of course IDs. That's okay once you know that's what it's doing, but I was expecting it to work like a cookie. Once you understand it, it makes sense, but it either wasn't clear or I missed it in the documentation so I mention it here.
  • While developing this as a user script, it worked fine, but when I went to the global custom JavaScript file, my data was getting returned with a while(1); followed by the JSON object. I've seen that before when typing an API call directly from the browser, so I knew what it was. The trick to get rid of it was to force the dataType to be json. That can also be done by using the jQuery.getJSON() method instead of the jQuery.get() method.

A third hurdle was the timing issue. AJAX calls are asynchronous and so I had no idea whether the call to load the custom sort order would be done before or after the MutationObserver had detected it was ready to start sorting. I ended up using a couple of scoped variables to check and when the custom sort order was done loading, it checked to see if the cards were ready. The call that happened when the cards were ready checked to see if the sort order had been loaded. By the way, the sort order may not ever be loaded and won't be the user has never sorted the cards.

76 Comments