Sorting the All Courses list

James
Community Champion
21
6505

Many of the feature requests involve the ability to sort the information that Canvas provides. One of those requests was to sort the list of courses that you get by clicking on the Courses global navigation link and then choosing "All Courses." I've written a user script that adds that functionality.

After installing the user script, you may click at the top of any column (except the favorites) to sort by that column. Clicking a second time reverses the sort while clicking it a third time returns it to its original order. You may also hold the shift key while clicking the column header to sort by multiple columns.

The script also adds the ability to filter any column in the table by typing in the text you want to find. This is useful when your course naming scheme uses weird values that don't sort the way that you want.

Quick Install

  1. Install Tampermonkey for Chrome, Firefox, or Safari.
  2. Install the All Courses Sort user script.

Using the Script

Once installed, click on Courses and then All Courses. It runs on the /courses page in your Canvas instance.

It adds the ability to sort any column by clicking on the heading.

317466_pastedImage_1.png

It also adds a filter row below the header so you can type text and filter any column except for the favorites. 

317467_pastedImage_2.png

About

The feature idea to add sorting to the all courses list has appeared multiple times. When I wrote this, two related open-for-voting feature ideas were https://community.canvaslms.com/ideas/3666-new-ui-add-option-to-group-courses-in-all-course-list-by-...  and https://community.canvaslms.com/ideas/10886-make-the-course-list-sortable" modifiedtitle="true" titl.... There were several others in cold storage that referred to one of those.

During InstructureCon 2019, David Theriault came up to me before the start of the last session on Wednesday and asked me about this feature. He hinted that Chris Long had suggested I could do something about it. He had commented on the one about sorting by term, but when he approached me, he mentioned the ability to sort. I told him to look me up at hack night and we would take a look at it.

Dave went over to set down and I got up and confirmed which page he was talking about, reiterated to look me up during hack night, and then I went back and sat through the session. I then walked the 15 minutes back to the room and took an hour to write the script and had it ready, but not published, by the time we went to supper.


When Dave found me during hack night, I gave him a copy and said I would get it published after I did some more testing. He indicated that he could see that I was thinking about it when he brought up the idea, so he knew there was a chance he would get it.

Customization

Custom URLs

The script automatically runs on any page that matches *.instructure.com/courses. This is the all courses page when your site is hosted by Instructure without a custom URL. If you have a custom URL, like canvas.university.edu, then you will need to modify the script to get it to work.

 

To make this change in Tampermonkey, click on the Tampermonkey Icon, choose Dashboard, and then click on Rubric Importer. Then change the *.instructure.com in the // @include statements on line 5 to match your instance and save your script.

Filtering

If you don't want the filtering, then comment out the 'widgets' line or remove 'filter' from the list of widgets added. You can also remove the code that adds the filter-false class to each of the favorites columns.

CSS

The CSS included is the default for the library I'm using to do the sorting. I'll admit that it does not fit well with Canvas. My goal here was to get something out there quickly, so I didn't invest time trying to figure out how to duplicate Canvas' default look and feel. The CSS also changes the font size of all the data in the table, which I do not like, but didn't take the time to figure out.

Since this is a user script, meaning the user decides whether or not to run it, I felt the default CSS and its ugliness was an acceptable tradeoff. If you end up adding this to your custom global JavaScript and CSS, there are probably improvements that should be made.

If someone wants to contribute a better CSS back to me, please do.

Version 2: July 17, 2019

I dug into the CSS and modified to to look more like Canvas does. The only overrides that really needed done were to change the CSS for the filtering, so I added those to the stylesheet for the page.

The Tablesorter script had the ability to specify classes that should be added when a column is sorted, so I used Canvas icons of icon-mini-arrow-up and icon-mini-arrow-down. It now looks a lot nicer than it did with the original release. The tradeoff is that there is no indicator that the sort feature is available.

Sort by Term

I did not add sorting by term for several reasons. Foremost is that the list enrollment terms API requires admin-level permissions, so it wouldn't benefit most users. Extracting the information from the course name is problematic because there is no inter-institutional standard for naming courses, so it would vary from school to school.

However, if you want to sort by term, I did include a commented line in the code that will allow you to do this. Just remove the // from in front of the sortList line. The value in there sorts the term column in descending order. If your terms start off with the year, this is a good way to get the most recent ones to the top.

$('table.ic-Table').tablesorter({
'widgets' : [ 'filter' ],
// 'sortList' : [[3,1]]
});‍‍‍‍‍‍‍‍‍‍‍‍

Specific Tables

Some people may not want the sorting and filtering on every table and that's something I questioned when I wrote it. If you decide that you only want the capabilities on, for example, the past enrollments table, then you'll need to modify the CSS selector in the line that invokes tablesorter.

  • table.ic-Table is the default and covers all blocks of enrollments.
  • table#my_courses_table will select the list of current courses.
  • table#past_enrollments_table will select the past enrollments list of courses.
  • table#future_enrollments_table will select the future enrollments list of course.
  • table#my_groups_table will select the list of groups the user is in.

You can invoke the tablesorter plugin multiple times with different configurations on different tables if you like. Just repeat the $('css-selector').tablesorter() block with different selectors and configurations.

Advanced

The script use the jQuery Mottie Tablesorter plugin. This means that anything that you can do with that library you can do here.

The sortList is one of the options from the Tablesorter plugin. It is an array of arrays. The nested array contains two values, a 0-based column for the first item and a 0 (ascending) or 1 (descending) for the second item. The [3,1] listed above sorts on the 4th column (the term) in descending order. Additional arrays within the main array allow you to have an initial multicolumn sort.

The Tablesorter plugin allows people to write their own parsers, but I think the filtering capability should work for most people.

Global Custom JavaScript

Version 3: July 19, 2019

I normally try to write user scripts so that they could be used in the account's custom global JavaScript using the Theme Editor. Because this script requires a jQuery plugin, that didn't work.

With version 3 of the script, I check to see if the tablesorter plugin exists. If it doesn't, then it loads it for you by adding the script element to the header. Once the script has loaded, then it calls the routine to add the sorting and filtering capabilities.

If you are going to add this to your global custom JavaScript, then please bear in mind that you may need to check accessibility issues. Tablesorter is not Canvas and Canvas cares a lot more about accessibility than most people. Tablesorter does seem to work with the keyboard and adds aria labels, but it's still not as impressive as what Canvas does.

21 Comments
dla0009
Community Member

Wow, thank you James for your simple fix. You quickly illustrated the how easy this problem could be fixed.

It serves as a fine example of how little Canvas cares to fix this issue themselves! It is a problem that is easy to fix for which lot of people have express frustration and yet nothing has been done. How many votes does it take to get Canvas to respond act? Apparently these forums are not read by Canvas!

Shar
Community Champion

Hi  @James ! Another brilliant and easy to install script--up and working before I finished reading the post.

CSS

The CSS included is the default for the library I'm using to do the sorting. I'll admit that it does not fit well with Canvas. My goal here was to get something out there quickly, so I didn't invest time trying to figure out how to duplicate Canvas' default look and feel. The CSS also changes the font size of all the data in the table, which I do not like, but didn't take the time to figure out.

When you do figure out the font size let us know. hehehe I like that I can see so many courses at once, but I they are small listed. But I really like the filter feature because often I know (part of) the name of the course I'm looking for but who has time to scroll down a list, when I can just type it in the box (and not have to press Enter). Yahoo!!:smileycool:

Thanks a million once again!
Cheers - Shar

James
Community Champion

The CSS from Tablesorter doesn't appear to be too much to wade through. Mostly I wanted the arrows so people knew it was sortable and what the sort order was. If that's all I'm doing, then there looks to be about 6-8 classes that actually matter. I could strip out the rest.

Ultimately, I would like to mimic the behavior of Canvas when they allow sorting (say on the Pages main page). That means that I could use Canvas' classes (subject to them moving to InstUI and them not being available anymore). Maybe I don't need any external CSS at all -- that would would be even better.

317407_pastedImage_1.png

I will probably use the Pages list as a model. The main issue was I didn't know when I would get back to it (I took a summer off for the first time since starting teaching and it has been busier than when I was teaching) and I wanted to get this one out there for people before it got swept into the realm of "mostly finished, but not polished enough to release" things I've written.

I want to hope that when Canvas does move this over to ReactJS and InstUI that they will add sorting to it. I suspect that people with lots of courses are outside the typical use case that they target. Adding a filter system will probably be done as a search box or items at the top that affect all tables at once. It might also be part of the options menu at the top of each column. That's way more complex than I want to develop. It's the right way to do things, though, and I'm glad that Canvas delivers awesome when I deliver quick and dirty.

James
Community Champion

I went through and fixed the CSS with version 2. The arrows aren't there until you click at the top of a column, but it looks much better.

GideonWilliams
Community Champion

Outstanding work  @James ‌ and a huge improvement on the existing system. Many, many thanks for sharing this with the Community and supporting those without such capacity/know how.

Now installed - works a treat!

gharbor
Community Participant

 @James ‌ thanks for this. What changes would I need to make this javascript something that I could upload in the Theme Editor? I tried using the all-courses-sort file but that did not seem to work?

James
Community Champion

It uses the Mottie Tablesorter jQuery plugin. The userscript headers tell Tampermonkey to include this for you before the script runs by specifying it on the require line. However, Canvas doesn't include this, or at least they don't expose it to you if they do. That means that you need to load the library before the script executes.

If you don't want to load it for every page (that's overkill and a waste) or include it in your global JavaScript, then you can load it dynamically only on the All Courses page by using jQuery.getScript() within the main code after the page check. Within the done function, then you invoke the $.tablesorter() code. The rest of it can be done outside the getScript (or within it).

James
Community Champion

gharbor,

I just updated the script to load tablesorter dynamically if it's not loaded through the user script manager (tampermonkey). This means that as of version 3, you should be able to load the code into the custom global JavaScript and have it work.

I have not checked this for accessibility. I know that tablesorter adds a bunch of stuff, but it's not as good as Canvas does things.

clong
Community Champion

Works like a charm! Thanks again James!

saltman
Community Participant

You are just the best ever, James Jones!  I was just bragging about your made script skills to my superintendent this week!

mark_crane
Community Participant

I just discovered this when our support guy mentioned Canvancements.  What an elegant, useful addition.

Jason_Ross
Community Participant

This is truly an improvement to the original course listing.  I am wondering if its possible to have to columns changed.  We don't use nicknames at our college but our courses all have codes.  Wondering if its complicated to change the nickname field to the course code for searching?

346793_pastedImage_1.png

Thanks

Jason

James
Community Champion

 @Jason_Ross  

This script adds sorting and filtering to the information that Canvas provides on the page already. Since Canvas does not provide the course code on the course list, you would need to write code that would fetch the course list for the user (again, since Canvas has already done it but not made it available to you) and then replace the columns.

Are you sure you don't have nicknames enabled? I didn't know it was an option to disable them. There is even an open feature idea to prevent people from using nicknames: https://community.canvaslms.com/ideas/15692-remove-the-ability-for-students-to-change-course-nicknam... 

Just because you don't use nicknames doesn't mean that other people aren't using them, so I wouldn't make the change globally. Nickames have some good benefits in distinguishing courses. For example, if you are teaching 3 sections with identical titles because the school doesn't put the section number or term into them, faculty can use nicknames to tell them apart. In other cases, the official title is so long that you need something shorter to see it all. I regularly go through and rename my courses each semester, but I have access to do that since I'm an admin. Our faculty would only have the option to use nicknames.

Jason_Ross
Community Participant

Awesome thanks for the information.

We are still new to Canvas so users are not using nicknames, i see your point as it might get used down the road.  We find it hard for faculty who have hundreds of courses and cannot search by our course code only by name.  All our courses are automatically uploaded and we use the long name and course code.  Course code is not searchable in the all courses view.

Thanks again, also great work.

Jason

James
Community Champion

The ambiguity in course names is why many institutions include extra information in the course title. We use the course number, the term, and the name in it. For example: MATH 113 - Intro to Applied Stats (SP20)

There are other locations in Canvas where the course code is not shown and you will run into the ambiguity problem if you don't put more information in the name. I wouldn't use the course code for your number, that sounds more like the SIS course code than the course code. The course code is displayed in the breadcrumb and should be something simple and human friendly. 

346803_pastedImage_1.png

However, if someone uses a Nickname, then that nickname shows up instead of the Course Code. I nicknamed my course to be "Stats" and here is my breadcrumb now.

346804_pastedImage_2.png

As a student, I wouldn't find 10128.201935 particularly friendly and would definitely create a nickname for it.

The SIS Course Code is something a computer would understand and needs to be unique.

If you have hundreds of courses, you should definitely be using terms and then you can filter on the terms with my script. Set up end dates in the Admin > Terms to help keep things organized as well and move them to the past enrollments section.

Ron_Bowman
Community Champion

@James -

I have not seen anything posted by you concerning this script, but I believe that Canvas has finally incorporated this Canvancement into Canvas.

I noticed it on firefox in my student account - checked tampermonkey and I did not have all courses sort installed.  I then Checked my instructor account - turned off all-courses-sort and the capability was still there.  even had the click on the column title to sort up or down.

It looks like you can retire another Canvancement.

 

James
Community Champion

Ron ( @Ron_Bowman ), I just checked and the functionality does not exist in Canvas. I would double check that everything was disabled and the page refreshed.

Another possibility is that your institution added the script at a global level, so it appears that it is part of Canvas to you. Disabling it on your end wouldn't make a difference in that case.

Ron_Bowman
Community Champion

@James -

Thanks.  I will have to double check that.  It was showing up in my student account on firefox which did not have the script installed at all.  So, maybe it is something where my school has incorporated your script into our instance of Canvas (Lucky us).  I just talked with one of our admins, and they did in fact take your script and modify it to hard code it into our canvas version.  They were getting a lot of questions/complaints about needing that functionality.

Now if they would have done that with UCF's script that allows for setting the accommodation times for students once and then automatically applying it to all future assignments I would be really happy.

 

patfm
Community Explorer

@James  Love your script!  Are there special considerations if we want to install the Javascript so it is global in our Canvas instance. 

James
Community Champion

@patfm 

When I write scripts (except for perhaps my earliest ones), I try to make it so that they could be stuck in the global custom JS for an account. I looked and this one checks to see if the jquery tablesorter plugin is loaded, which it would be if it was a userscript but perhaps not when loaded from a global JS. That suggests that I wrote it with a global JS in mind.

That said, it should work with a global JS -- you can just omit the metadata block at the top -- but I have not actually tried it. I would install it in your beta or test instance first to double check. If you have other scripts in your global JS, you'll want to make sure that nothing breaks.

With all custom JS, if Canvas changes something, it might break. That happens very infrequently, but just be aware of it.

James
Community Champion

@patfm 

About 5 hours after I posted this saying that Canvas infrequently changes things, Jeremy Perkins made a post that Canvas is upgrading their jQuery  tomorrow (Feb 28) from version 1.7.2 to 1.8.3 and again on March 13 from version 1.8.3 to 2.2.4. They are then hoping (but no dates) to get up to version 3.5 and eventually 3.7.1.

He wrote that it is expected some customer's custom JavaScript will break.

Notably, the version of the code I had included a newer version of jQuery than what Canvas was including. The check for a specific version was version 1.7.2, which will change after tomorrow.

I think what I was looking at was whether people had loaded their own version of jQuery and if so, make sure that I returned the $ to the other script via the jQuery.noConflict(); statement. Starting tomorrow, that will likely run the Canvas jQuery in noConflict mode. I am not sure if that will be a problem or not since other people might be depending on that. I suspect that it will be as returning the $ to other libraries could break everyone's code that used $.

I did just test the userscript in beta and it continued to function on that particular page. That is likely because I was using jQuery 3.4.1 as a userscript so it was using the jQuery installed by the script (3.4.1) not the jQuery delivered by Canvas (1.8.3). If you have other code using $ (as most people who just copy/paste jQuery code probably do), I don't know what will happen when it hits the noConflict(). That is, at a minimum, the "1.7.2" should be changed.

I would definitely test this in the global custom JavaScript of the beta instance before putting it into production. Even that may not be enough as beta is getting 2.2.4 so you cannot test whether it will work properly with 1.8.3.

Since Canvas is going to change things again relatively quickly, I would suggest holding off putting it into production until we're sure that it doesn't break with later versions.

At this point, I would make sure that nothing else breaks in your custom global JavaScript rather than trying to add something new right now. When Canvas has a new-enough version of jQuery, the code can be cleaned up.