Monthly Archives: November 2013

Hacking Canvas

It’s been a while since my last post, so I’ve probably lost track of some of my recent insights. I really need to be more disciplined.

The topic of today’s post is hacking Canvas. One of the great things about Canvas is the handles it provides for enterprising (foolhardy?) administrators who want to tweak the system. You don’t have to write a module or External Tool to get started, either, because Canvas lets you mount custom css and javascript at the level of the account or sub-account. This gives administrators a remarkable amount of power, perhaps even too much.

So, what can you do with custom js and css? Lots, but here are just a couple of concrete examples of ways people have changed, not just the look, but the behavior of Canvas. Each of these examples was inspired by a need that made it’s way into the Canvas Feature Request forum. The forum is probably worth a blog post of its own, but for now I will only note that there are a LOT of requests out there, and only a small number are adopted in an update cycle. For those who can’t wait, a small subset can be handled via js and/or css.

Request #1: Make the group space visually distinct from the course space
solution: add this code to your custom js file! http://jsfiddle.net/pYnWN/12
    (kudos to Nathan Bierma)

Request #2: Unleash the Content Editor: Encourage RICH content & flexible layouts
     solution: jQueryUI is already sitting behind every Canvas page. With jQuery it is easy to add     layout elements like tabs and overlays to a page. Unfortunately, the so-called Rich Text Editor Canvas provides for editing pages strips out javascript. The solution is to add hooks into existing javascript objects with the clever use of carefully named classes, so that when your custom script ‘sees’ the classes, it automatically invokes the appropriate jQueryUI interface widget.

Request #3: Allow LTI redirect links to open in a new windows
solution: Once again, custom js to the rescue. As with the first example, this script looks for existing Canvas html elements to determine when new UI elements are needed. When the script sees an LTI iframe, it creates a show/hide button that collapses the nav menu, creating more space for the main frame. When an External Tool is launched from the nav menu, you get the show/hide, plus a button that will launch a new window with the same LTI data and destination.

https://apps.ats.udel.edu/canvas/collapse.js

collapse-js.png collapse-js.png (quick view)

As of this writing, only the show/hide button has been implemented on UD’s primary account, but I have the launch button in the test account, and the jQueryUI hooks in a sub-account. I’ll be pitching the group navigation options soon.

Class CanvasAPI

My goal for today is to move all my adhoc php functions that access the Canvas API into a php class. Once I have that working well, I will hopefully be able to redirect all the includes that are currently accessing the api to the one master file. If everything seems to be working well, I may even put the code up at GitHub. I have no illusions that anything I create will be the best it could be, but maybe at GitHub, someone will fork it and make needed improvements.

Properties:

  • private token
  • private domain
  • public error
  • public ready

Methods:

  • __construct($token,$domain)
  • get_canvas ($uri,$paginate=true)
  • post_canvas($uri,$method,$params)
    misnamed, you can use any curl method here, but no pagination
  • is_valid_token()
  • upload($file=array())

New window issues

This week, I tried to get cute by over-writing some classes within Canvas. The intent was to buy more screen real estate for my LTI tools, since Canvas themselves still has not provided a way for tools to open in a new window from the Navigation menu, nor to hide the menu.

Popping in a show/hide feature for the default Canvas left panel was easy. The hard part is getting the page that appears inside the newly expanded iframe to appear correctly. Most of the time, this takes care of itself, but I am having fits with tables that utilize the jQuery DataTables plugin. This plugin does a lot of heavy lifting, so I am loathe to give it up, but resizing my page is creating a problem, since only the body cells are taking advantage of the new real estate, and I can’t figure out how to get the header and footer to be responsize. Having not explored much inside the DataTables code, I don’t really know where to begin. Have tried running the DataTables redraw, but so far, that doesn’t seem to be helping. I need to solve this if I’m going to continue to use DataTables.

Supporting Providers

Today I squashed an ugly bug that popped up for users linking into my Peer Evaluation Tool from Sakai as opposed to Canvas. It was created when I tried to distinguish between Canvas users coming from UD vs other institutions, and really only consisted of of a code nesting error, which caused my to fail to capture the LTI data unless users were coming from Canvas.

The take-home message, however, is that if you support multiple providers, which at this point, I barely do, you need to have a way to test from each provider each time you make an update to the code. Testing becomes an even more major component of tool maintenance. Bad enough to have to test on different browsers, platforms and screen sizes. Now multiply all that by the number of LMS providers you want to support. Yikes!

Context IDs

So, in LTI, there is something called a context id. Best I can tell, it is a unique identifier for an LTI  course site. I don’t know how unique it really is, though. For example, is it possible for sites from two different LMS vendors to have courses with the same context id? You’d hope not, but you’d guess it might be possible, unless each vendor is issued some sort of unique string they and only they are to start their ids with. I don’t know much about the rules from the provider side.

So, this post is about a problem I just encountered in a tool I am playing with. The tool is currently storing some csv data, one record per course. Naturally, I am storing them under the contextid for the course. But, we have two Canvas instances at our disposal, the production and the test instance. The test instance is cloned from the production once a week or so. Recently I was playing with my tool using the test instance, and then realized that the contextids are the same for both. I suppose that’s not surprising given that they are clones, but the sub-domains are different. I was not actually expecting the upload I made on the test site to impact the data viewed on the production site. After all, that’s kind of the point of having a test site, so you can play without messing anything up on the real site. In retrospect, it should have been obvious that if I could SEE the data that had been stored on the production site, I would also be able to overwrite it.

So now I’m left with a thorny issue. How do I protect the real data from corruption based on actions taken in the test site? I think I’m going to have to put an extra column in my database for the site’s domain, and use a combination as a key. If I do that, then the weekly clones will not be able to see the same data that is in the production copy, which is sort of a bummer, but better than the alternative.

The other solution is to stop storing data in external databases, and switch instead to putting hidden files into the Canvas file system. I was planning to do that anyway, as much as possible. I don’t think I will attempt it for my Peer Evaluation tool, because the data is too complex, but for Post’Em and SBG, it should be no problem.

Hello world!

Now that we are on EduBlogs, maybe it’s time I actually start blogging. I’ve been spending a ton of time learning about LTI and the Canvas API, so I am thinking of recording my experiences here. It’s actually a bit late in the game to start on that topic, I’d have a lot of catching up to do, but then again, I don’t have a better idea.

I’m also going to use this blog as a testing ground for the WordPress LTI plugin, if I can get it installed here.