|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Preface
It is in our nature to use tools, and it is in our nature to make them. And one of our most powerful traits is in our ability to take tools made by others, and customize them to our own needs and preferences. Sadly, this is often an area where software tools, potentially some of the most flexible at our disposal, fail us. Consider the applications and utilities installed on your computer: how many of them nearly fit your mental model of how a tool could be used for certain tasks, but fall short in one area or another? If only you could make a few small modifications, how much easier and faster could your day-to-day work be accomplished? Because of this, software that enables customization of other software, meta-tools if you will, have existed for nearly as long as software itself. From the lowly macro assembler, to scripting frameworks, to complex patching tools, to the hardware-software combinations that allow today's game consoles to be used in ways their designers never intended, we have always found ways of fulfilling our drive to bend the work of others to our own ends. Web applications, themselves a novel take on technology originally created for much simpler tasks, are ripe for customization. The underlying design, a client-server system with well-documented communications protocols and data formats, is far more open to enhancement than nearly any other platform in common use. Even the much-lamented existence of "browser wars" speaks of opportunities that just don't exist in other areas - even the ability on *nix to choose from among different window managers pales in comparison. One of the most recent developments to this end has been the creation of tools that allow bits of code, "user scripts", to be inserted into a web page when it loads, thereby allowing users to enhance, automate, and extend websites and web apps in ways the authors of those sites were unable or unwilling to consider. One of the most popular of these meta-tools is the GreaseMonkey extension for the Firefox browser. Since its release, thousands of scripts have been written to do everything from making poorly-designed sites more accessible for those with disablities, to the so-called "mashup scripts" that combine information or functionality from two or more sites into a single interface. In this article, I will present a number of simple enhancements to forums on The Code Project website, and attempt to give some insight into the power - and the limitations - of tools such as GreaseMonkey. As you may know, The Code Project is a website dedicated to articles on code or programming-related topics, primarily for the Windows platform. One of its best attributes are the forums it provides, both those attached to each article and those dedicated to general topics such as MFC and .NET. Unlike many such forums, Code Project's integrate well into the rest of the site, and provide an especially good venue for discussion and debate on the topics presented in articles. Although they can be viewed in several different ways, the scripts I present here are intended for use in the most common format: the DHTML "Message View", where discussion threads and replies appear as subject lines that expand when clicked to display the full message. Tools: This Is GreaseMonkeyWe'll start out by gathering some useful tools. I'm not going to go into detail on how any of these are used, but consider spending some time on your own playing with them. GreaseMonkey is the most important, so go download and install it first: http://greasemonkey.mozdev.org/ (Of course, you should download the version for Firefox 1.5. If you don't have Firefox 1.5, then download and install it.) Now, Greasemonkey scripts are JavaScript. While fairly easy to use, you might benefit from having a quality debugger - on Firefox, that means Venkman: http://www.hacksrus.com/~ginda/venkman/ Another useful tool for working with JavaScript is a bookmarklet called JavaScript Shell, which gives you a console interface, complete with command completion, running in the context of a web page. If you've ever used and enjoyed BASIC/VB "Immediate Mode", you'll love this: http://www.squarefree.com/shell/ Finally, download and install the FireBug extension. Logging, error display, DOM inspection and modification... this tool has too many features to properly summarize. Just trust me, if you're doing any sort of web development, you want it: http://www.joehewitt.com/software/firebug/ DHTML Tweaks: Expand All
(note: I can't upload .js files to CP, so I'm hosting these myself.)
Although the default view (messages collapsed) is generally preferable, it is occasionally useful to make the text of all messages visible at once (for instance: in order to use the browser's Find feature to search through message texts). This script adds a button next to the (Refresh) link on each forum; when clicked, it expands all displayed messages: // ==UserScript==
// @namespace http://shog9.com/greasemonkey/scripts/
// @name CPExpandAll
// @author Joshua Heyer
// @description Add an "Expand All" option to Code Project forums
// @version 1.0
// @include http://*.codeproject.com/*
// @include http://*.codetools.com/*
// @include http://*.thecodeproject.com/*
// ==/UserScript==
var refreshLink = document.evaluate("//a[text()='Refresh']", document, null,
XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if ( refreshLink )
{
var expandBtn = document.createElement("BUTTON");
expandBtn.className = "FormButton";
expandBtn.textContent = "Expand All";
expandBtn.addEventListener("click", function(event)
{
var forumTable = document.getElementById("ForumTable");
if ( !forumTable )
return;
var messages = document.evaluate("./tbody/tr[4]/td/table/tbody/tr",
forumTable, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if ( messages )
{
for (i=0; i<messages.snapshotLength; ++i)
{
messages.snapshotItem(i).style.display = "";
}
}
}, false);
refreshLink.parentNode.insertBefore(expandBtn,
refreshLink.nextSibling.nextSibling);
}
Things to note:
AJAX-style: Delete
While developing these and other scripts, I often found it helpful to create dummy threads to test various things. Once I'd finished testing, deleting these posts would be rather tedious - the [delete] link on each post navigates first to a confirmation page, where pressing a button finally deletes the post and reloads the original forum. Creating a faster means of deleting posts was essential.
This script uses Points of interest:
The power of DOM and XSL: Printer-friendly forums![]()
By now, you've probably realized that Mozilla's powerful DOM implementation makes many enhancements a good deal easier than they would be on other platforms. But wait! There's more! If you've ever used XSL templates to transform XML, you know how they can reduce the drudgery of such tasks. Well, Mozilla's <xsl:variable name="forumID"
select="substring-before(substring-after(//a[text()='Refresh']/@href, 'forumid='), '&')"/>
<!-- lounge -->
<xsl:variable name="title1"
select="/html/body/table/tbody/tr[2]/td[3]/table/tbody/tr/td/font/b"/>
<!-- article -->
<xsl:variable name="title2"
select="/html/body/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr/td/b/font"/>
<!-- forum -->
<xsl:variable name="title3"
select="/html/body/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/font/b"/>
<!-- survey / news -->
<xsl:variable name="title4"
select="/html/body/table/tbody/tr/td[3]/table/tbody/tr/td/table/tbody/tr/td"/>
<xsl:variable name="title">
<xsl:choose>
<xsl:when test="$title1"><xsl:value-of select="$title1"/></xsl:when>
<xsl:when test="$title2"><xsl:value-of select="$title2"/></xsl:when>
<xsl:when test="$title3"><xsl:value-of select="$title3"/></xsl:when>
<xsl:when test="$title4"><xsl:value-of select="$title4"/></xsl:when>
</xsl:choose>
</xsl:variable>
This handles the ugly task of extracting information from the various forums. Lots of hairy XPath and special-cases (shown: code used to determine forum title). The output is an XML representation of the forum, which is fed into <xsl:template match="Content">
<div class="PostContent">
<xsl:copy-of select="text()|*"/>
<br clear='all'/>
</div>
</xsl:template>
This has the much more pleasant job of transforming the XML representation into a printer-friendly HTML representation. Naturally, it's much smaller and easier to read. The one mildly interesting bit (shown) involves keeping rowdy signature HTML from appearing outside the containing element. Using libraries: Syntax Highlighting![]() ![]() Greasemonkey scripts are run in a slightly separate environment from those embedded in the actual web page being modified. This is partially for security reasons (since GM scripts can do things like add menus and make cross-site requests, it would be dangerous to make it too easy for malicious pages to hook into it), and partially for practical reasons (it would be unfortunate if pages started breaking because of namespace collisions or other unforseen script interference). Regardless, it is almost always in the best interest of the user to keep it this way. However, there's no reason why, on sites where we have a good understanding of the scripting already in place, we can't use GM to insert additional unprivileged scripts into the page itself. Alex Gorbatchev has written an excellent Javascript library for doing syntax coloring of various languages. It's really quite good. And as soon as I saw it, I wanted it on the CP forums. So of course, i wrote a GM script. var forumLUT =
{
0 : "javascript", // default (javascript)
1649 : "c#", // C# forum
12076 : "c#", // ASP.NET forum
1650 : "c#", // .NET forum
1646 : "vb", // VB forum
1725 : "sql", // SQL / ADO / ADO.NET forum
3421 : "xml", // XML / XSL
};
var langLUT =
{
"javascript" : "shBrushJScript.js.txt",
"c#" : "shBrushCSharp.js.txt",
"vb" : "shBrushVb.js.txt",
"sql" : "shBrushSql.js.txt",
"xml" : "shBrushXml.js.txt"
};
My script has explicit mappings for several programming forums, so that the default coloring will be correct for those. For the rest, adding a Now, everyone likes easy-to-read code, but stop and think for a minute about how powerful this technique is. I'm loading these scripts from CP to avoid adding to the load on Alex's server, but for sites that don't allow uploads i could just as easily host these scripts on my own server. There are a growing number of excellent 3rd-party libraries that can be used in this way. ConclusionThe ever-increasing capability of tools such as Greasemonkey provides vast opportunity for bringing new and useful changes to sites like CodeProject. I hope this article has sparked your interest in writing site-specific enhancements, and I look forward to seeing what those of you inclined to experiment are able to accomplish. Additional ResourcesFor a more in-depth tutorial, please read Mark Pilgrim's Dive Into Greasemonkey: http://diveintogreasemonkey.org/ For an alternate method of scripting websites, see Chickenfoot: http://groups.csail.mit.edu/uid/chickenfoot/index.php
|
||||||||||||||||||||||