// ==UserScript==
// @name LDD Show Responses
// @namespace http://www.nsftools.com/tools
// @description Adds a [+] link next to responses at the bottom of a message on the Lotus developerWorks forum so you can view responses inline instead of having to open a page for each response.
// @include http://*.lotus.com/ldd*
// ==/UserScript==
/*
This is a Greasemonkey script designed to be used with the forums on the
Notes.net/LDD/Lotus developerWorks site. ( http://www.lotus.com/ldd )
If you have no idea what Greasemonkey is, start here:
Firefox users (the original):
http://greasemonkey.mozdev.org/
IE users (the copy):
http://www.daishar.com/blog/archives/2005/03/greasemonkey_fo.html
I've only tested this script with Firefox, so I have no idea how well it
does or doesn't work with IE.
===========================
The problem with the LDD forums is that you can't see the text of any of the
responses associated with a particular message. You get a list of links to the
responses at the bottom of the page, but you can only open a single message at
a time -- which is a huge pain if there are more than about 2 responses to a
message.
What this script does (thanks to the magic of Greasemonkey) is to add a little
[+] next to each response link at the bottom of the page. If you click on that
[+], it will open a
beneath the link that will get populated with the
message body for that particular response. Click it again, and the response
body disappears.
If none of this makes sense, just go to: http://www-10.lotus.com/ldd/nd6forum.nsf
and open a message that has several responses, and then try to read the responses
with and without this script enabled.
===========================
A few efficiencies I've added to this script:
1. None of the response messages are retrieved until you actually click the [+].
This means when you view a message that has a large number of responses, your
page will still load quickly (i.e. -- the browser won't be trying to get all
of the responses when the page opens). The text of the responses is only
retrieved when you click the [+].
2. If you click on a [+] to view a response message and then click it again to
make it disappear, it will remember what the message is. So if you click it
again to expand the response message before you refresh the page, you won't
have to make another round trip to the server in order to get the message
again -- it'll just come right up.
3. The responses are retrieved using asynchronous XML HTTP requests, which grab
the response doc, parse the message text, and insert it into a
(this
process is normally referred to as "Ajax" these days).
===========================
ISSUES:
1. I had to hardcode several things in here, because the LDD forums don't really
package up the messages in any kind of easily parsable way (say, with divs).
Some or all of this script could break tomorrow if the LDD folks decide to rename
some of their image files.
2. There's probably a much more elegant way of doing some or all of this using
regular expressions. I don't know how that way might work, and I don't really care.
This method seems to work, and it's easy to troubleshoot.
===========================
HISTORY:
version 1.0 -- April 16, 2005
Initial release.
version 1.1 -- April 16, 2005
Fixed bug where the tag I was using to determine the start of the body
block didn't exist when you were logged in, so you wouldn't get message text
if you were logged in.
version 1.2 -- April 17, 2005
Modified the script to make the display div block style "display: none;" when the
div was hidden, to get rid of the extra whitespace/linefeed that was appearing
between each of the response links.
===========================
This is version 1.2 of the lddresponse.user.js script
by Julian Robichaux ( http://www.nsftools.com )
April 17, 2005
You can do anything you'd like with this script, just don't hold me liable for
anything, and don't pretend like you wrote it yourself.
The latest release should always be available at the OpenNTF site, at:
http://www.OpenNTF.org/projects/pmt.nsf/ProjectLookup/LDDMonkey
*/
(function () {
// the main chunk of code here just steps through all the images on the
// page, and for all the "threadmap_inactive.gif" images it finds, it
// modifies them to add our little clickable [+] span
var images = document.getElementsByTagName("img");
for (i = 0; i < images.length; i++) {
var n = images[i];
var src = n.getAttribute("src");
if ((src) && (src.indexOf("threadmap_inactive.gif") > 0)) {
// marker for a response to this message, so the next
node should be
// a link to the that response
var sib = n;
while ((sib = sib.nextSibling) != null) {
if (sib.tagName == "A") {
var tag = sib.getAttribute("href");
if (tag) {
// we found the link for this response doc
// first, add something the user can click to get the response
var expander = document.createElement("span");
expander.style.cursor = "pointer";
expander.style.backgroundColor = "yellow";
expander.setAttribute("tag", tag);
expander.onclick = doExpander;
expander.innerHTML = " [+] ";
n.parentNode.insertBefore(expander, n);
// the next node after the icon should be of the format "...."
// we're going to try to count the periods to decide how much
// we want to left-indent the div that follows
var pees = n.nextSibling.nodeValue;
var indent = 20;
if (pees)
indent = (pees.split(".").length * 5) + 20;
// create a div that will hold the response contents
var div = document.createElement("div");
div.setAttribute("id", tag);
div.style.display = "none";
div.style.backgroundColor = "#eeeeee";
div.style.border = "1px solid #777777";
div.style.padding = "5px";
div.style.margin = "5px";
div.style.marginLeft = indent + "px";
div.style.visibility = "hidden";
// if there's a
tag nearby, try to put the div after that
var divsib = sib.nextSibling.nextSibling;
for (j = 0; j < 4; j++) {
sib = sib.nextSibling;
if (sib == null)
break;
if (sib.tagName == "BR")
divsib = sib.nextSibling;
}
divsib.parentNode.insertBefore(div, divsib);
break;
} // end if(tag)
} // end if(sib.tagName)
} // end while(sib != null)
} // end for loop
}
function doExpander () {
// this is the function that is called when the user clicks one of the [+]
// spans that we've added. Clicking that will toggle the div that contains
// the response message text. If we haven't retrieved the response message
// yet, we'll try to get after we display the div.
var tag = this.getAttribute("tag");
var div = document.getElementById(tag);
// if we're already showing the div, just hide it and return
if (div.style.visibility == "visible") {
div.style.display = "none";
div.style.height = 0;
div.style.visibility = "hidden";
return;
}
// show the div and grab the response message if we haven't already
div.style.visibility = "visible";
div.style.display = "block";
div.style.height = "";
if (!div.innerHTML) {
div.innerHTML = "getting " + tag + "...";
getResponseText(div, tag);
}
}
function getXMLHTTP() {
// function to create an XmlHttp object
var xmlHttp = null;
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch(oc) {
xmlHttp = null;
}
}
if(!xmlHttp && typeof XMLHttpRequest != "undefined") {
xmlHttp = new XMLHttpRequest();
}
return xmlHttp;
}
function getResponseText (div, tag) {
// function to asynchronously retrieve the web page specified by the tag
// parameter, parse it, and then put the parsed content in the specified
// div section
var xmlHttp = getXMLHTTP();
if (xmlHttp) {
xmlHttp.open("GET", tag, true);
// What do we do when the response comes back?
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.responseText) {
var resp = xmlHttp.responseText;
var bodyText = "";
// we pretty much want everything from
// to (not even sure why that
is there, but it
// seems consistent, and we don't really want any extra
// tags mucking up the works anyway)
var pos = resp.indexOf("/next.gif");
if (pos > 0) {
// there's a tag shortly after the next.gif graphic.
// we'll start there (version 1.1 fix: it turns out that when
// you're logged in, the tag isn't there...)
tpos = resp.indexOf("", pos);
brpos = resp.indexOf("