Index: messageforums-app/src/webapp/js/forumTopicThreadsSorter.js
===================================================================
--- messageforums-app/src/webapp/js/forumTopicThreadsSorter.js (revision 0)
+++ messageforums-app/src/webapp/js/forumTopicThreadsSorter.js (revision 0)
@@ -0,0 +1,386 @@
+/* Client side sorting for sakai forums topic threads page
+ *
+ * threadsSorter: jQuery plugin
+ * @example : $('table').threadsSorter();
+ * Version : 1.1
+ * @requires : tablesorter plugin
+ * Author : Yuanhua Qu, Texas State University
+ * Date : 7/24/2010
+ * Mail : yq12@txstate.edu
+ * Description : This threadsSorter jquery is built on top of tablesorter jquery plguin.
+ * It handles specifically for sakai forums topic threads sorting case.
+ * Should also handle sorting normal table correctly. Works tested with IE7 & IE8,
+ * firefox 3 and safari 3 & 5
+ * Each thread in the topic is called -- parent
+ * Each response directly to the thread (parent) is called -- child(ren)
+ * Each response to the child and deeper from there is called grandchild(ren).
+ * All responses are called descendants which should include children and grandchildren.
+ * Sorting result expected:
+ * 1. If sorted by threads, all parents are sorted; Each parent's children are also sorted;
+ * but grandchildren are not sorted (This satisfies our users' need of no deeper sorting needed.
+ * Though potentially all could be sorted with same level of messages, only need little bit more
+ * work to get it done if there is such requirement.)
+ * Thread/message/response still keep their logic relative layout after sorting.
+ * 2. If sorted by date, all parents are sorted; Each parent's descendants (children and grandchildren)
+ * are also sorted. Descendants are not ordered by logic but date.
+ * 3. If sorted by author, it is absolutely sorted by author's firstname lastname order so that
+ * instructor will get all the messages grouped by author; Threads/messages/responses are
+ * out of their logic relative layout after sorting. This satisfies the use case of
+ * instructor's insterest to see messages of certain students.
+ * If you would like sorting by author behaves the same way as sorting by date, just comment out
+ * 3 lines:
+ * if ($(e.currentTarget).get(0).column == 2) {
+ * return false;
+ * }
+ * Note : It depends on the row class, id and indent to identify parent-descendant relationship.
+ * It is highly customized sorting result based on our users' needs.
+ * version 1.1 fixed issue with IE browsers.
+ */
+
+
+/* This helps to convert padding value from px to relative value */
+$.fn.toEm = function(settings){
+ settings = jQuery.extend({
+ scope: 'body'
+ }, settings);
+ var that = parseInt(this[0],10);
+ var scopeTest = jQuery('
').appendTo(settings.scope);
+ var scopeVal = scopeTest.height();
+ scopeTest.remove();
+ return (that / scopeVal).toFixed(0) + 'em';
+};
+
+
+/* add parser for link column 'Thread' , extend parser of tablesorter object */
+/* 'A' fix for IE */
+$.tablesorter.addParser({
+ id: "link",
+ is: function(s) {
+ return /^<(a|A)/.test(s);
+ },
+ format: function(s) {
+ var str = $(s).siblings("a|A").text();
+ return jQuery.trim($(s).siblings("a|A").text().toLowerCase());
+ },
+ type: "text"
+});
+
+// overwrite sortCSS defined locally in jquerytablesorter.js
+// it was defined wrong way
+// Changed that in jquery.tablesorter.js file, comment out here
+// sortCSS = ["headerSortUp", "headerSortDown"];
+
+jQuery.fn.threadsSorter = function() {
+ return this.each(function(){
+
+ /* util */
+ function isParent(node){
+ if (node.className == "hierItemBlock")
+ return true;
+ else
+ return false;
+ }
+
+ function isDescendant(node){
+ if (node.id.match(new RegExp('_id_[0-9]+__hide_division_')))
+ return true;
+ else
+ return false;
+ }
+
+ function isChild(node){
+ var paddingValue = $(node).find("td").eq(1).css("padding-left");
+ if (paddingValue.indexOf("px")>=0){
+ paddingValue = $(parseInt(paddingValue.replace("px",""))).toEm();
+ }
+ if(paddingValue == "1em"){
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /* Making header looks similar to sakai other sorting tables' header */
+ function decorateHeaders(){
+ var cssObj = { 'text-decoration': 'underline',
+ 'color':'#3355bb'
+ }
+ $('.header').each( function () {
+ var str = $(this).text().split(" ");
+ if(str[0] == "Authored"){
+ str[0] = "Author";
+ }
+ if(str[0] != ""){
+ $(this).css(cssObj);
+ $(this).attr("title","Sort By " + str[0]);
+ }
+ }),
+
+ $('.header').hover(
+ function () {
+ $(this).css("color","#0000ee");
+ },
+ function () {
+ $(this).css("color","#3355bb");
+ }
+ );
+ }
+
+ /* get original table cache before it's sorted to
+ record and mark the parent/desendant relationship in each row.
+ Need to remember row index for the children of each children node */
+ function buildOriginalCache(table) {
+ var totalRows, cache;
+ totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
+ cache = {row:[], childrenId:[]};
+ var parentId = null;
+ var descendantCount;
+
+ for (var i=0;i < totalRows; ++i) {
+ var c = table.tBodies[0].rows[i], cols = [];
+ if (isParent(c)) {
+ descendantCount = 0;
+ parentId = "parent" + i;
+ c.parentId = "parent" + i;
+ for(var k=i+1; k= 0){
+ var pixels = parseInt(leftpadding.replace("px", ""));
+ paddingDigitValue = parseInt($(pixels).toEm().replace("em",""));
+ }
+ else{
+ paddingDigitValue = parseInt(leftpadding.replace("em",""));
+ }
+
+ // while (next ) is a grandchild, save the array index in the originalCacheTable for the row;
+ while(paddingDigitValue > 1){
+ grandChildrenCount++;
+ grandChildrenRows.push(tempRowIndex);
+ next = next + 1;
+ tempRowIndex = tempRowIndex +1;
+ row = table.rows[next];
+ leftpadding = $(row).find("td").eq(1).css("padding-left");
+ if(leftpadding.indexOf("px") >= 0){
+ var pixels = parseInt(leftpadding.replace("px", ""));
+ paddingDigitValue = parseInt($(pixels).toEm().replace("em",""));
+ }
+ else{
+ paddingDigitValue = parseInt(leftpadding.replace("em",""));
+ }
+ } //end of while loop
+ c.grandChildrenCount = grandChildrenCount;
+ c.grandChildrenRows = grandChildrenRows;
+ }// end of isChild
+ }//end of isDescendant
+ cache.row.push($(c));
+ }; //end of first for loop
+ return cache;
+ };//end of buildOriginalCache
+
+ /* Record order of sorted list for children nodes */
+ function buildSortedCache(table){
+ var totalRows, cache;
+ totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
+ cache = {row:[]};
+
+ for (var i=0;i < totalRows; ++i) {
+ var c = table.tBodies[0].rows[i];
+ var descendantRow = [];
+ if (isParent(c)) {
+ var parentId = c.parentId;
+ var totalDescendant = c.descendantCount;
+ if (totalDescendant != 0) {
+ var descendant = 0;
+ for(var k=0; k 0 || m == 0; m--){
+ //get child row number in the sorted cache
+ var childRow = this.descendantRow[m];
+ //append child
+ $(cache.row[childRow]).insertAfter(this);
+ }
+ }
+ else{
+ //Get children sorted, keep logic of grandchildren and deeper descendents.
+ for (var m = this.descendantCount -1; m > 0 || m == 0; m--){
+ //get children row numbers in the sorted cache
+ var childRow = this.descendantRow[m];
+ var leftpadding;
+ var paddingValue;
+ //make it working cross browsers and versions hopefully, fixed IE7 & 8
+ leftpadding = $(cache.row[childRow][0].children[1]).css("padding-left");
+ if(leftpadding.indexOf("px")>=0){
+ var pixels = leftpadding.replace("px","");
+ paddingValue = $(parseInt(pixels)).toEm();
+ }
+ else{
+ paddingValue = leftpadding;
+ }
+ if(paddingValue == "1em"){
+ // Insert child
+ var insertedRow = $(cache.row[childRow]).insertAfter(this);
+ // Find its grandchildren and insert them in the original order
+ var count = cache.row[childRow][0].grandChildrenCount;
+ if(count != 0 ){
+ var rowIndexArray = cache.row[childRow][0].grandChildrenRows;
+ for (var n = 0; n < count; n++){
+ insertedRow = $(original.row[rowIndexArray[n]]).insertAfter(insertedRow);
+ }
+ }
+
+ }
+ }//end of for
+ }
+ }
+ });
+ }// end of buildForumSortedTable
+
+ /* build original table cache to mark parent-child relationship */
+ cacheOriginalTable = buildOriginalCache(this);
+
+ /* Calling jquery library tablesorter plugin function to do general sorting */
+ /* disable sorting on first column */
+ $(this).tablesorter({
+ headers:{
+ 0:{ sorter: false}
+ }
+ });
+
+ //Showing headers clickable and sortable like sakai style
+ decorateHeaders();
+
+ $this = $(this);
+
+ /*
+ * add another click handler doing customized sorting for forum topic threads table
+ * except first column
+ */
+
+ $(this).find("th:gt(0)").click(function(e){
+
+ //IE supports srcElement, not currentTarget
+ if(!e.currentTarget)
+ e.currentTarget = e.srcElement;
+
+ //If sorted by Author, sort all authors regardless of parent/descendent relationship.
+
+ //Comment out following 3 lines if you would like to keep parent/descendent relationship
+ //and keep Author sorted within each level.
+
+ if ($(e.currentTarget).get(0).column == 2) {
+ return false;
+ }
+
+ //Sort and keep parent/descendent relationship after sorting
+ //Set timer to be 10 ms to be executed later than executing functions in tablesorter; this
+ //fixes latency issue with IE browser.bugid:3565
+ setTimeout(function() {
+ //build cache for normally sorted table
+ cacheSortedTable = buildSortedCache($this[0]);
+ //build forum special sorted table
+ sortedByThread = ($(e.currentTarget).get(0).cellIndex) ==1;
+ buildForumSortedTable($this[0],cacheSortedTable,sortedByThread,cacheOriginalTable);
+ },10);
+ return false;
+ });
+
+
+ /*
+ * The sakai expand/collapse will reload the tables which wipe out the sorted rows when expending/collapsing.
+ * We added handler for expand/collapse when clicking on first column header -- the expand/collapse icon
+ * to overwrite the out of box behavior, so that the table still remains sorted and sorting direction indicator
+ * still shows up while it's expanding/collapsing.
+ */
+
+ var imageCollapseUrl = "/messageforums-tool/images/collapse.gif";
+ var imageExpandUrl = "/messageforums-tool/images/expand.gif";
+
+ var expandCollapseCol = $this[0].tHead.rows[0].cells[0];
+
+ $(expandCollapseCol).find("a").replaceWith("");
+ $(expandCollapseCol).css("cursor", "pointer");
+ var flip = 0; //indicates click times for expand all/collapse all
+
+ $(this).find("th:eq(0)").click(function(e){
+ flip++;
+
+ if(flip %2 == 0){
+ $($this[0].tBodies[0].rows).not(".hierItemBlock").hide();
+ //Sync icons showing consitent for collapsing
+ $(e.target).replaceWith("");
+ $(".attach img").attr({'src': imageCollapseUrl, 'alt':'Expand/Collapse', 'title':'Expand/Collapse'})
+ }
+ else {
+ $($this[0].tBodies[0].rows).not(".hierItemBlock").show();
+ //Sync icons showing consitent for expanding
+ $(e.target).replaceWith("");
+ $(".attach img").attr({'src': imageExpandUrl, 'alt':'Expand/Collapse', 'title':'Expand/Collapse'});
+ }
+ mySetMainFrameHeight($('iframe', parent.document)[0].id);
+ return false;
+
+ });
+
+ });
+
+}; //end of jquery threadsSorter plugin
Property changes on: messageforums-app/src/webapp/js/forumTopicThreadsSorter.js
___________________________________________________________________
Added: svn:keywords
+ Date Revision Author HeadURL Id
Added: svn:eol-style
+ native
Index: messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp
===================================================================
--- messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp (revision 79843)
+++ messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp (working copy)
@@ -14,6 +14,14 @@
+
+
+
<%--//
//plugin required below