Problem: I have a web site/page that I visit regularily which I want to annotate with my notes.
More specifically, I was regularly searching through the Homegate real estate hub looking for a new home. It goes without saying that I was again and again forgetting which objects I had already looked at, which objects were really interesting and I should check out more closely.
Therefore the need to annotate search results.
The here presented approach should be applicable for annotation of other web pages as well. It’s based on the observation, that restful web applications need to operate with asset IDs. These asset IDs can be reused to enrich the asset locally with additional data, such as notes. Thus we’re looking for those IDs in specific elements of the page and add a bit of HTML markup to those places.
Of course that aproach only works as long as the web site doesn’t heavily change its markup and doesn’t rendomly change asset IDs.
Here’s a screenshot of regular Homegate search results:
And here’s the same page after scripting it with Greasemonkey:
You’ll notice the input field with the comment in it.
The idea is simple: add an input box to each search result, where you write your comment. When the focus leaves the input box, the comment is stored to localStorage.
Starting with Greasemonkey is quite easy. There are howtos and templates to start from, such as this one.
However, regular JavaScripting and Greasemonkey JavaScripting do not work in exactly the same way:
One of the differences is that Greasemonkey creates a separate JavaScript environment, in which the Greasemonkey scripts are executed. That is calling Javascript contained in the page from Greasemonkey and the inverse calling Greasemonkey scripts from the page is not possible by default. This is on purpose, so that the web page can not detect and not interfere with the Greasemonkey scripts, because you want your Greasemonkey scripts to work allways on some page, whether or not that page likes it or not. Therefore no interference is possible.
Greasemonkey however provides a standard way to access the web page’s scripts, and that’s through the “unsafeWindow” object, which is a reference to the web page’s environment.
I had two mechanisms I had to make accessible using the “unsafeWindow” handle:
- the first was accessing JQuery, which is included by default by the Homegate page. Since I needed to use JQuery functions in my Greasemonkey script, I got a reference to it via the standard Greasemonkey precedure:
var jQuery = unsafeWindow['jQuery'];
- the second mechanism that needed to cross the boundaries between the web page and Greasemonkey was callbacks from the web page to my Greasemonkey script. This is necessary, because I’m attaching “input” elements to each search result, which contain a note and which, “onblur”, need to call a function that saves the content of the input box. Here’s part that constructs the input element:
jQuery("<input onclick='event.cancelBubble = true;'" + " onblur='saveComment(this, immoID);'>").insertAfter(immoElement);
And this is the function that gets called back by “onblur”:
unsafeWindow.saveComment = function(element, immoID) { unsafeWindow.localStorage.setItem(immoID, element.value); };
The next interesting thing you’ll note is usage of ’locaStorage’. Support for the latter in browsers does not seem mature yet. One problem I’ve encountered when developing under Firefox 3.6 was that saving to ’localStorage’ was not possible when cookies were disabled (see this report). Thus you’ll need to permanently enable cookies for Homegate in order for the script to be able to save its data.
Finally, while developing, a major problem was, that Firefox did not show me errors in the Greasemonkey scripts. Thus either the script would work or not work and fail completely silently. That made debugging a bit painful.
So now, here’s the script.
Tomáš Pospíšek
PS: This script also lives at userscripts.org