// ==UserScript==
// @name Blackboard and WebCT Forum - Social Analysis Tool
// @namespace BBFSA
// @description Forum Social Analysis Data Extraction and Visualiation Tool
// @include http://*.qut.edu.au/webapps/discussionboard/do/message?action=message_tree&course_id=*&conf_id=*&forum_id=*&nav=discussion_board&thread_id=*&message_id=*
// @include http://*.qut.edu.au/webapps/discussionboard/do/message?action=list_messages&course_id=*&conf_id=*&forum_id=*&nav=discussion_board&thread_id=*&message_id=*
// @include https://*.ubc.ca/webct/urw/*/newMessageThread.dowebct?discussionaction=mDisplay&topicid=*&areaid=*&fromTopic=*&homePage=*
// @include http://vista.uow.edu.au/webct/urw/*/newMessageThread.dowebct?discussionaction=mDisplay&topicid=*&areaid=*&fromTopic=*
// @include https://*.ubc.ca/webct/newMessageThread.dowebct
// @include http://vista.uow.edu.au/webct/newMessageThread.dowebct
// ==/UserScript==
// Global Functions
function stripSpaces(x) {
// Removes spaces from a string
return (x.replace(/^\W+/,'')).replace(/\W+$/,'');
}
function getTextAfterChar(Text, charToStart)
{
// Returns all characters in a string after the specified substring
var len = Text.length;
var posStart = Text.indexOf(charToStart);
return Text.substring(posStart,len);
}
function getRequestVars()
{
// Returns an array with all querystring parameters
var request= new Array();
var vals=location.search.substr(1).split("&");
for (var i in vals)
{
vals[i] = vals[i].replace(/\+/g, " ").split("=");
request[unescape(vals[i][0])] = unescape(vals[i][1]);
}
return request;
}
function InsertSNALink(urlString)
{
// Insert an SNA Link
urlString = getTextAfterChar(urlString,'&');
var buildHTML = "";
if (LMS == "Blackboard")
{
navbar = document.getElementById('checkboxPicker');
buildHTML += ' Perform Social Network Analysis';
}
else if (LMS == "WebCT")
{
navbar = document.getElementById('pages');
buildHTML += ' Perform Social Network Analysis';
}
if (navbar)
{
var newLink = document.createElement("span");
newLink.innerHTML = buildHTML;
//navbar.parentNode.insertBefore(newLink, nav.nextSibling);
if (LMS == "Blackboard")
{
navbar.parentNode.insertBefore(newLink, navbar.nextSibling);
}
else if (LMS == "WebCT")
{
navbar.appendChild(newLink);
//alert(navbar);
}
}
}
function GenerateGraphML(nodes,edges)
{
// Generates a the Social Network Graph in the GraphML XML Format
var graphML;
graphML = '\n';
graphML += '\n';
graphML += '\n';
// Generate the nodes
for (person in nodes)
{
graphML += '\n';
}
// Generate the edges (ie links between nodes)
for (reply in edges)
{
fromToArray = reply.split("_");
graphML += '' + edges[reply] + '' + '\n';
}
graphML += '\n';
graphML += '\n';
return graphML;
}
function GenerateVNAFileFormat(nodes,edges)
{
// Generates a the Social Network Graph in the GraphML XML Format
var vnaBuilder = "";
vnaBuilder += '*Node data\n';
vnaBuilder += 'ID posts\n';
// Generate the nodes
for (person in nodes)
{
vnaBuilder += '"' + person + '" ' + nodes[person] +'\n';
}
// Generate the edges (ie links between nodes)
vnaBuilder += '*Tie data\n';
vnaBuilder += 'from to talk strength\n';
for (reply in edges)
{
fromToArray = reply.split("_");
vnaBuilder += '"' + fromToArray[0] + '" "' + fromToArray[1] + '" 1 ' + edges[reply] + '\n';
}
return vnaBuilder;
}
function PostReplyTable(edges)
{
// Generates a Post-Reply Frequency Table
var tableBuilder = "";
tableBuilder += "
Post-Reply Frequency Table
";
tableBuilder += "Poster | Replied To | Frequency |
";
// Generate the edges (ie links between nodes)
for (reply in edges)
{
fromToArray = reply.split("_");
tableBuilder += "" + fromToArray[0] + " | " + fromToArray[1] + " | " + edges[reply] + " |
";
}
tableBuilder += '
\n';
return tableBuilder;
}
function PerformSocialAnalysis()
{
// Extract SNA Data
var forumusers = [];
var postsbyusers = "";
var totalposts = 0;
var threadowners = [];
var replies = [];
var formWithTable = document.getElementById("treeForm");
//alert(formWithTable.getAttribute("name"));
var table = formWithTable.getElementsByTagName("table");
var rows = table[0].getElementsByTagName("tr");
//alert("rows:" + rows.length);
var network = "";
network = network + "";
network = network + "Post ID | Thread Depth | Posted By | Posted On | Reply To |
";
for(i = 0; i < rows.length; i++)
{
var cols = rows[i].getElementsByTagName("td");
var rowtext = "--";
//alert("cols:" + cols.length);
for (j = 0; j < cols.length; j++)
{
//rowtext = rowtext + " " + cols[j].innerHTML;
if (j==3)
{
columnWithLink = cols[j].getElementsByTagName("a");
relationship = columnWithLink[1].getAttribute("href");
relationship = relationship.substring(relationship.indexOf('(')+1,relationship.length-1);
relationshiplist = relationship.split(",");
postid = relationshiplist[1].substring(1,relationshiplist[1].length-1);
threaddepth = getTextAfterChar(relationshiplist[2].substring(1,relationshiplist[2].length-1),'_').substring(1);
}
else if (j==4)
{
posted_by = cols[j].innerHTML;
posted_by = posted_by.substring(posted_by.indexOf('>'),posted_by.length);
posted_by = stripSpaces(posted_by);
if (forumusers[posted_by])
{
forumusers[posted_by] = forumusers[posted_by] + 1;
}
else
{
forumusers[posted_by] = 1;
}
}
else if (j==5)
{
posted_on = cols[j].innerHTML;
posted_on = stripSpaces(posted_on);
}
}
threadowners[threaddepth] = posted_by;
if (threaddepth.length != 1)
{
threadReplyDepth = threaddepth.substring(0,threaddepth.length-2);
reply_to = threadowners[threadReplyDepth];
sna_relationship = posted_by + "_" + reply_to;
if (replies[sna_relationship])
{
replies[sna_relationship] += 1;
}
else
{
replies[sna_relationship] = 1;
}
}
else
{
// Originating Thread
reply_to = "-";
}
totalposts = totalposts + 1;
network = network + "" + postid + " | " + threaddepth;
network += " | " + posted_by + " | " + posted_on + " | " + reply_to + " |
";
//network = network + postid + " " + threaddepth + " " + posted_by +" " + posted_on + "
";
}
network = network + "
";
//alert(network);
postsbyusers = postsbyusers + "";
postsbyusers = postsbyusers + "Forum Users | Number of Posts |
";
for (i in forumusers)
{
postsbyusers = postsbyusers + "" + i + " | " + forumusers[i] + " |
";
}
postsbyusers = postsbyusers + "
";
//alert(network + postsbyusers + "\n" + "totalposts:" + totalposts);
var forumstats = document.createElement("div");
BuildHTML = "
Blackboard Forum Social Network Analysis
Total Posts: " + totalposts + postsbyusers + "
" + network;
BuildHTML += PostReplyTable(replies);
BuildHTML += "
GraphML Output
";
BuildHTML += "";
BuildHTML += "VNA File Format
";
BuildHTML += "
";
BuildHTML += "Note: VNA Format is used by NetDraw";
forumstats.innerHTML = BuildHTML;
formWithTable.parentNode.insertBefore(forumstats, formWithTable.nextSibling);
}
function PerformSocialAnalysisWebCT()
{
// Extract SNA Data
var forumusers = [];
var postsbyusers = "";
var totalposts = 0;
var threadowners = [];
var replies = [];
var currRoot = "";
//var formWithTable = document.getElementById("messageViewForm");
var table = document.getElementById("datatable");
//formWithTable.getElementsByTagName("table");
var rows = table.tBodies[0].rows;//table.getElementsByTagName("tr");
//alert("rows:" + rows.length);
var network = "";
network = network + "";
network = network + "Post ID | Thread Depth | Posted By | Posted On | Reply To |
";
for(i = 0; i < rows.length; i++)
{
var cols = table.tBodies[0].rows[i].cells; //rows[i].getElementsByTagName("td");
var rowtext = "--";
//alert("cols:" + cols.length);
for (j = 0; j < cols.length; j++)
{
//alert(cols[j].innerHTML);
if (j==0)
{
inputtag = cols[j].getElementsByTagName("input");
postid = inputtag[0].getAttribute("id");
threaddepth = inputtag[0].getAttribute("indent");
if (threaddepth=="0")
{
currRoot = postid;
}
//alert(postid);
//
//columnWithLink = cols[j].getElementsByTagName("a");
//relationship = columnWithLink[1].getAttribute("href");
//relationship = relationship.substring(relationship.indexOf('(')+1,relationship.length-1);
//relationshiplist = relationship.split(",");
//postid = relationshiplist[1].substring(1,relationshiplist[1].length-1);
//threaddepth = getTextAfterChar(relationshiplist[2].substring(1,relationshiplist[2].length-1),'_').substring(1);
//
}
else if (j==1)
{
//inputtag = cols[j].getElementsByTagName("input");
//postid = inputtag[0].getAttribute("id");
//alert(cols[j].innerHTML);
//
//columnWithLink = cols[j].getElementsByTagName("a");
//relationship = columnWithLink[1].getAttribute("href");
//relationship = relationship.substring(relationship.indexOf('(')+1,relationship.length-1);
//relationshiplist = relationship.split(",");
//postid = relationshiplist[1].substring(1,relationshiplist[1].length-1);
//threaddepth = getTextAfterChar(relationshiplist[2].substring(1,relationshiplist[2].length-1),'_').substring(1);
//
}
else if (j==5)
{
posted_by = cols[j].innerHTML;
posted_by = posted_by.substring(posted_by.indexOf('>')+1,posted_by.length);
posted_by = posted_by.substring(0,posted_by.indexOf('<'));
//alert(posted_by);
if (posted_by == "")
{
posted_by = cols[j].innerHTML;
posted_by = posted_by.substring(2,posted_by.length-2);
}
if (forumusers[posted_by])
{
forumusers[posted_by] = forumusers[posted_by] + 1;
}
else
{
forumusers[posted_by] = 1;
}
}
else if (j==6)
{
posted_on = cols[j].innerHTML;
//alert(posted_on);
//posted_on = stripSpaces(posted_on);
}
}
threadowners[currRoot+"_"+threaddepth] = posted_by;
if (threaddepth=="0")
{
reply_to = "-";
}
else
{
reply_to = threadowners[currRoot+"_"+ (parseInt(threaddepth)-1)];
sna_relationship = posted_by + "_" + reply_to;
if (replies[sna_relationship])
{
replies[sna_relationship] += 1;
}
else
{
replies[sna_relationship] = 1;
}
}
totalposts = totalposts + 1;
network = network + "" + postid + " | " + threaddepth;
network += " | " + posted_by + " | " + posted_on + " | " + reply_to + " |
";
//network = network + postid + " " + threaddepth + " " + posted_by +" " + posted_on + "
";
}
network = network + "
";
postsbyusers = postsbyusers + "";
postsbyusers = postsbyusers + "Forum Users | Number of Posts |
";
for (i in forumusers)
{
postsbyusers = postsbyusers + "" + i + " | " + forumusers[i] + " |
";
}
postsbyusers = postsbyusers + "
";
//alert(network + postsbyusers + "\n" + "totalposts:" + totalposts);
var forumstats = document.createElement("div");
BuildHTML = "
WebCT Forum Social Network Analysis
Total Posts: " + totalposts + postsbyusers + "
";
BuildHTML += network;
BuildHTML += PostReplyTable(replies);
BuildHTML += "
GraphML Output
";
BuildHTML += "
";
BuildHTML += "
VNA File Format
";
BuildHTML += "
";
BuildHTML += "Note: VNA Format is used by
NetDraw ";
forumstats.innerHTML = BuildHTML;
navbar = document.getElementById('pages');
navbar.appendChild(forumstats);
}
// Get querystring
var querystring = document.location.href;
// Work out Forum page type - message list or forum tree/thread
var RequestVars = getRequestVars();
var actionRequetVar;
var ForumPageType;
var LMS;
if (RequestVars["action"])
{
// This is a Blackboard Page
actionRequetVar = RequestVars["action"];
ForumPageType = ((actionRequetVar == "message_tree") ? "message_tree" : "list_messages");
LMS = "Blackboard";
}
else if (RequestVars["discussionaction"])
{
// This is a WebCT Page
actionRequetVar = RequestVars["discussionaction"];
ForumPageType = "WebCTForum";
LMS = "WebCT";
}
else if ((querystring.indexOf("webct/newMessageThread.dowebct")!=-1))
{ // && (document.form.messageViewForm.discussionaction.value=="mCollapseAll")
// An Expanded Thread view is displayed in WebCT
ForumPageType = "WebCTForumThread";
LMS = "WebCT";
}
//alert(querystring.indexOf("webct/newMessageThread.dowebct"));
//alert(ForumPageType);
if (ForumPageType == "list_messages")
{
InsertSNALink(querystring);
}
else if (ForumPageType == "message_tree")
{
PerformSocialAnalysis();
}
else if (ForumPageType == "WebCTForum")
{
//alert("WebCT");
InsertSNALink(querystring);
//PerformSocialAnalysis();
}
else if (ForumPageType == "WebCTForumThread")
{
//alert("WebCT Expanded Thread");
PerformSocialAnalysisWebCT();
//alert(document.messageViewForm.discussionaction.value);
}