I've recently inherited an XPages codebase which tries to deliver on the unfortunate promise of 'it will look like the Notes Client, one-to-one'.
The original Notes Database which it tries to mimic is a database that has the 'discussion template' logic, with maintopics (containing a rich text) having child-response documents, they themselves having child documents, up to a depth of 5. The screen is divided in two, with the left side for the navigation, and the right side for displaying the rich text content of the currently selected document.
This is what it look like.
My predecessors made a laudable attempt to cater to this request, but there are some bugs in the codebase that I am having trouble pinpointing. The logic of clicking on a document is working correctly, alas the whole logic of the collapsing and expanding icons is not working correctly. I show how the current logic is working below.
If this was a fresh project, I would argue that collapsible views and the response-to-response logic is something that the Notes Client does trivially easy, but that there is no easy way to do this with the standard UI paradigms of the Web, so it's better to think about presenting the data in a completely different way - refer to Stefan Wissel's excellent blog entry:
http://www.wissel.net/blog/d6plinks/SHWL-7UDMQS
But since this is a bit of a firefighter project, I just want to repair the existing work. I'm torn between trying to debug the existing code, re-writing it, or using an out-of-the-box custom control.
1. Debug the existing code
The existing code uses 5 nested repeat controls. The first repeat control takes as a source a view containing only the main topics, and the subsequent repeat controls are fed with data using SSJS and .getDocuments.
var tempDc:NotesDocumentCollection = ColLevel2.getResponses();
var tempDoc:NotesDocument = tempDc.getFirstDocument();
var resultList:java.util.Vector = new java.util.Vector();
var tempTreeMap:java.util.TreeMap = new java.util.TreeMap();
var nn;
var subject;
var sortKey;
// FirstDoc
var ParUNID = tempDoc.getParentDocumentUNID();
var sub = tempDoc.getItemValueString("Subject");
var strAct = tree.getLev();
var iCount = 0;
// fill the treeMap
while (tempDoc != null) {
iCount++;
// set the value of the field in "fieldName" as key for sorting with this criteria
nn = tempDoc.getItemValueInteger("nChapterNumber");
subject = tempDoc.getItemValueString("Subject");
sortKey = @Right("000"+@Text(nn),3) + " " + subject;
if(strAct.equals(ParUNID)){
// _dump(iCount+". sortKey "+sortKey+" subject "+subject);
tempTreeMap.put(sortKey, tempDoc);
}
tempDoc = tempDc.getNextDocument(tempDoc);
}
// iterate through treemap to get sorted resultlist
var tempColl:java.util.Collection = tempTreeMap.values();
var tempIt:java.util.Iterator = tempColl.iterator();
while (tempIt.hasNext()) {
resultList.add(tempIt.next());
}
return resultList;
}catch(e){
sessionScope.Error = e.toString()
return ColLevel2.getResponses();
}
The collapse and logic code is using direct DOM manipulation to hide or show the divs that contain the nested information.
function expand(expandLinkId, collapseLinkId, panelId, stopRepeat) {
try{
var panel = null;
var image = null
var el = document.getElementById(panelId)
var children = el.getElementsByTagName('div');
var pos1;
var pos2;
//alert(children.length + " divs gefunden (repeat controls and panels)")
for(var i = 0; i< children.length;i++){
//alert(i + ": " + children[i].id)
panel = document.getElementById(children[i].id);
pos1 = panel.id.indexOf(stopRepeat);
//if( pos1<0 ){
panel.style.display = "block";
//}
}
// images
var children = el.getElementsByTagName('img');
//alert(children.length + " imgs (collapsed.giv / expanded.gif) gefunden")
for(var i = 0; i< children.length;i++){
//alert(i + ": " + children[i].id)
image = document.getElementById(children[i].id);
pos1 = image.id.indexOf(stopRepeat);
//if( pos1<0 ){
pos2 = image.id.indexOf("Collapse");
if( pos2 > 0){
image.style.display = "none";
}else{
image.style.display = "block";
try{
image.click(); // collapses all sub-chapters // not supported by XPINC 8.5
}catch(e){
// nothing
}
}
//}
}
// arrow images
var expand = document.getElementById(expandLinkId);
var collapse = document.getElementById(collapseLinkId);
expand.style.display = "inline"
collapse.style.display = "none"
}catch(e){
alert(e.message);
}
return(false);
}
I'm getting some places that are unexpectedly empty, and ideally I'm looking for a way to peek into what is within the repeat controls, but can't think of any better way than just printing everything out to the console.
2. Re-write the code.
Since there are only going to be 500 entries maximum, and the entries are more or less static, I'm imagining building a managed bean that loads all the data for the navigation in one go and feeds that data into a tree structure, and then accessing that data with Expression Language. I'm more comfortable using Java and Expression Language than SSJS.
3. Out-of-the box custom control.
I've looked at the different view controls that XPages offers out of the box (ViewControl) and most seem to me to be difficult to fine-tune the appearance - I'd need to be able to recreate the exact same look as shown above.
What would you recommend?