A day of “extreme programming” on the Feedback Widget

On Monday this week, Pat and I booked out a meeting room and set up our laptops side-by-side so that we could begin making progress on the Portfolios Feedback widget. I’ve been conscious that development of this widget has slipped since Karsten left and since the beginning of term, so it was good to set aside a solid block of time to focus on it.

In this post, I’m going to try and explain in the simplest possible terms some of what we’ve managed to achieve. Although I have included some examples of code in the post (JavaScript), hopefully the explanation of what the code does will be clear enough for non-coders to be able to interpret it and perhaps even learn something about JavaScript syntax.

Let’s start by restating the purpose of this development: The Feedback widget should allow a user to look at a e-portfolio that they have access to, highlight nearly any part of a page within it and leave a comment on that part. It’s like an annotation tool for leaving targetted feedback. The owner of the e-portfolio or anyone else seeing it should then be able to see the comments left by other users if they have access to the widget too. As a result of this aim, there are some issues around privacy and confidentiality but these will have to wait for another post.

I had made some progress with the Feedback widget previously by creating a frameset page that the user could launch from the e-Portfolio Templates widget (explained here and here). To summarise, the frameset contains three frames, arranged as rows:

  • Frame 1: toolbar frame (where we hope to put buttons/controls)
  • Frame 2: e-portfolio frame (where the user’s e-portfolio appears)
  • Frame 3: hidden frame (this is where we load the place in which we want to store our comments — in this case, the comments page within the user’s e-portfolio)

This is roughly what it looks like from our development point of view…

A crude rendering of the Portfolio Feedback widget (click to enlarge)

… but all the user should see in the final interface is their e-portfolio with a simple toolbar above it.

By its definition, a portfolio (e- or otherwise) can consist of one or more pages. Arguably, a one-page portfolio isn’t much of a portfolio at all, so let’s say that a portfolio should consist of more than one page, even though it can consist of just one.

The Feedback widget we’re developing works by attaching an “event listener” to the page the user is looking at within their e-portfolio. An event listener is a property one can use with elements on a webpage so that a piece of code is executed when that event occurs. In this case, the event listener is “onmouseup” — so whenever the user lifts their mouse button on the portfolio page, the widget looks at what the user has selected. The “onmouseup” event seems like the best one to listen for since it means that the user can push their mouse button down, drag the cursor over a piece of text in order to select it (or highlight it), and then when they let go over the mouse button the widget checks to see what their selection is.

Now consider that the user might, at any point, change the page they are looking at within their portfolio. It’s not enough for us to attach the “onmouseup” event to the page the portfolio happens to open on. So one of the first things that Pat and I looked at was how to attach this event to whichever page the user decides to load.

Normally the “onload” event listener would be ideal for dealing with this. The “onload” event can be used in conjunction with a window or frame to trigger a piece of code whenever a page or document within that window or frame is fully loaded — and it therefore triggers every time a new page is loaded. This would be ideal for attaching our “onmouseup” event listener to the page/document since we would know when the page had changed and then we could add the onmouseup event listener to the new page.

This is just an example of that might work:

window.frames[“portfolio_frame”].window.frames[“Portfolio_RightFrame”].onload=
“document.body.onmouseup=’thisFeedbackSession.getActiveText()'”;

Unfortunately, for us this was harder than it sounds for a couple of related reasons:

  1. The portfolio itself consists of two frames, but arranged in columns. On the left, you have the menu and on the right the portfolio page. But these two frames are written by Blackboard. Unlike the aforementioned three frames that we control, we’re not able to put an inline “onload” event into either.
  2. On top of this, it is not possible in JavaScript, so far as I can tell, to dynamically alter the onload property of a frame. Otherwise, we could simply put some code in to onload so that whenever the user clicks on a different page, the onmouseup event is added.

My initial solution to this problem was to write a piece of code that was timed so that at an interval of every 100ms the address of the page would be checked against the last one noted and if they differed, we would wait until that page had fully loaded and then add our onmouseup event. This is approximately what the code looked like:

this.interCheck=window.setInterval(function() { thisFeedbackSession.checkPage() },100);

this.checkPage=function() {
if (this.portfolioPageFrame.location != this.portfolioPageLocation) {
this.portfolioPageLocation=this.portfolioPageFrame.location;
this.tempInt=window.setInterval(function() { whenPageReady(); },100);
}
}

this.whenPageReady=function() {
if (this.portfolioPageFrame.document.readyState == “complete”) {
this.addMouseUpEventListener();
window.clearInterval(this.tempInt);
}
}

Unfortunately, this caused quite a few problems — we managed to get thousands of errors clocking up in our consoles and after much head-scratching and drawing on the board, we could see that this was no good because we’d set up what looked like two mutually recursive loops. Errors aside, it wasn’t good enough because it only checked to see if a page had changed. What if the user decided to refresh the page they were looking at? The page would reload but there would be no difference in the address so onmouseup would never be added and the highlighting facility would not work.

We now have a much more elegant code that regularly checks (i.e., every 100ms) to see whether the portfolio page’s readystate is complete (i.e., whether the document has fully loaded) regardless of which page it is and then simply checks the document to see if the onmouseup event listener is there or not. If the event listener isn’t attached, then we attach it!

Here’s what it looks like now (much nicer, I think):

this.checkPage=function() {
if (this.portfolioPageFrame.document.readyState == “complete”) {
if (this.portfolioPageFrame.document.body.onmouseup == null) {
this.addMouseUpEventListener();
this.highlightComments();
}
}
}

You might also notice there’s an extra unexplained line in there — namely “this.highlightComments()”. Once Pat and I had solved the problem of the user’s being able to change pages, we were also able to address one of the key features that the widget is supposed to provide — how to show what existing comments were there on the page, comments which need reloading every time the page is.

Although we made quite a bit of progress with this, we still have a fundamental problem with the way the widget works, one that may be insurmountable. But that’s for another post!

About Guy

I am currently Enhancement Officer (for Education Technologies) at the University of Reading. I am also studying for a Masters in Research at the University's School of Systems Engineering.
This entry was posted in e-Portfolio Feedback, Plugin development. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *