// ==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'; } // 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 += ""; // Generate the edges (ie links between nodes) for (reply in edges) { fromToArray = reply.split("_"); tableBuilder += ""; } tableBuilder += '
PosterReplied ToFrequency
" + fromToArray[0] + "" + fromToArray[1] + "" + edges[reply] + "
\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 + ""; 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 + ""; //network = network + postid + " " + threaddepth + " " + posted_by +" " + posted_on + "
"; } network = network + "
Post IDThread DepthPosted ByPosted OnReply To
" + postid + "" + threaddepth; network += "" + posted_by + "" + posted_on + "" + reply_to + "
"; //alert(network); postsbyusers = postsbyusers + ""; postsbyusers = postsbyusers + ""; for (i in forumusers) { postsbyusers = postsbyusers + ""; } postsbyusers = postsbyusers + "
Forum UsersNumber of Posts
" + i + "" + forumusers[i] + "
"; //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 + ""; 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 + ""; //network = network + postid + " " + threaddepth + " " + posted_by +" " + posted_on + "
"; } network = network + "
Post IDThread DepthPosted ByPosted OnReply To
" + postid + "" + threaddepth; network += "" + posted_by + "" + posted_on + "" + reply_to + "
"; postsbyusers = postsbyusers + ""; postsbyusers = postsbyusers + ""; for (i in forumusers) { postsbyusers = postsbyusers + ""; } postsbyusers = postsbyusers + "
Forum UsersNumber of Posts
" + i + "" + forumusers[i] + "
"; //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); }